* call-dirmngr.c: New.
authorWerner Koch <wk@gnupg.org>
Fri, 11 Jan 2002 17:07:51 +0000 (17:07 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 11 Jan 2002 17:07:51 +0000 (17:07 +0000)
* certpath.c (gpgsm_validate_path): Check the CRL here.
* fingerprint.c (gpgsm_get_certid): New.
* gpgsm.c: New options --dirmngr-program and --disable-crl-checks.

sm/ChangeLog
sm/Makefile.am
sm/call-agent.c
sm/call-dirmngr.c [new file with mode: 0644]
sm/certchain.c
sm/certpath.c
sm/fingerprint.c
sm/gpgsm.c
sm/gpgsm.h

index d2864c7..c31e766 100644 (file)
@@ -1,3 +1,10 @@
+2002-01-11  Werner Koch  <wk@gnupg.org>
+
+       * call-dirmngr.c: New.
+       * certpath.c (gpgsm_validate_path): Check the CRL here.
+       * fingerprint.c (gpgsm_get_certid): New.
+       * gpgsm.c: New options --dirmngr-program and --disable-crl-checks.
+
 2002-01-10  Werner Koch  <wk@gnupg.org>
 
        * base64.c (gpgsm_create_writer): Allow to set the object name
index edd9566..8bdbc01 100644 (file)
@@ -30,6 +30,7 @@ gpgsm_SOURCES = \
        keydb.c keydb.h \
        server.c \
        call-agent.c \
+       call-dirmngr.c \
        fingerprint.c \
        base64.c \
        certlist.c \
index 47a4ee7..87b1024 100644 (file)
@@ -1,5 +1,5 @@
 /* call-agent.c - divert operations to the agent
- *     Copyright (C) 2001 Free Software Foundation, Inc.
+ *     Copyright (C) 2001, 2002 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include "../assuan/assuan.h"
 #include "i18n.h"
 
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
-
-#define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
-                     *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
-#define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
-
 
 static ASSUAN_CONTEXT agent_ctx = NULL;
 
diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c
new file mode 100644 (file)
index 0000000..4e3de36
--- /dev/null
@@ -0,0 +1,182 @@
+/* call-dirmngr.c - communication with the dromngr 
+ *     Copyright (C) 2002 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 "gpgsm.h"
+#include "../assuan/assuan.h"
+#include "i18n.h"
+
+static ASSUAN_CONTEXT dirmngr_ctx = NULL;
+
+struct cipher_parm_s {
+  ASSUAN_CONTEXT ctx;
+  const char *ciphertext;
+  size_t ciphertextlen;
+};
+
+struct genkey_parm_s {
+  ASSUAN_CONTEXT ctx;
+  const char *sexp;
+  size_t sexplen;
+};
+
+
+struct membuf {
+  size_t len;
+  size_t size;
+  char *buf;
+  int out_of_core;
+};
+
+
+\f
+/* Try to connect to the agent via socket or fork it off and work by
+   pipes.  Handle the server's initial greeting */
+static int
+start_dirmngr (void)
+{
+  int rc;
+  char *infostr, *p;
+
+  if (dirmngr_ctx)
+    return 0; /* fixme: We need a context for each thread or serialize
+                 the access to the agent (which is suitable given that
+                 the agent is not MT */
+
+  infostr = getenv ("DIRMNGR_INFO");
+  if (!infostr)
+    {
+      const char *pgmname;
+      ASSUAN_CONTEXT ctx;
+      const char *argv[3];
+
+      log_info (_("no running dirmngr - starting one\n"));
+      
+      if (fflush (NULL))
+        {
+          log_error ("error flushing pending output: %s\n", strerror (errno));
+          return seterr (Write_Error);
+        }
+
+      if (!opt.dirmngr_program || !*opt.dirmngr_program)
+        opt.dirmngr_program = "/usr/sbin/dirmngr";
+      if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
+        pgmname = opt.dirmngr_program;
+      else
+        pgmname++;
+
+      argv[0] = pgmname;
+      argv[1] = "--server";
+      argv[2] = NULL;
+
+      /* connect to the agent and perform initial handshaking */
+      rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv, 0);
+      if (rc)
+        {
+          log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
+          return seterr (No_Dirmngr);
+        }
+      dirmngr_ctx = ctx;
+    }
+  else
+    {
+      infostr = xstrdup (infostr);
+      if ( !(p = strchr (infostr, ':')) || p == infostr
+           /* || (p-infostr)+1 >= sizeof client_addr.sun_path */)
+        {
+          log_error (_("malformed DIRMNGR_INFO environment variable\n"));
+          xfree (infostr);
+          return seterr (General_Error);
+        }
+      *p = 0;
+      log_error (_("socket based dirmngr communication not yet implemented\n"));
+      return seterr (Not_Implemented);
+    }
+
+  log_debug ("connection to dirmngr established\n");
+  return 0;
+}
+
+
+\f
+/* Handle a SENDCERT inquiry. */
+static AssuanError
+inq_certificate (void *opaque, const char *line)
+{
+  AssuanError rc;
+
+  if (strncmp (line, "SENDCERT ", 9) || !line[9])
+    {
+      log_error ("unsupported inquiry `%s'\n", line);
+      return ASSUAN_Inquire_Unknown;
+    }
+
+  /*  rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);*/
+  rc = 0;
+  return rc; 
+}
+
+
+\f
+/* Call the directory manager to check whether the certificate is valid
+   Returns 0 for valid or usually one of the errors:
+
+  GNUPG_Certificate_Revoked
+  GNUPG_No_CRL_Known
+  GNUPG_CRL_Too_Old
+ */
+int
+gpgsm_dirmngr_isvalid (KsbaCert cert)
+{
+  int rc;
+  char *certid;
+  char line[ASSUAN_LINELENGTH];
+
+  rc = start_dirmngr ();
+  if (rc)
+    return rc;
+
+  certid = gpgsm_get_certid (cert);
+  if (!certid)
+    {
+      log_error ("error getting the certificate ID\n");
+      return seterr (General_Error);
+    }
+
+  snprintf (line, DIM(line)-1, "ISVALID %s", certid);
+  line[DIM(line)-1] = 0;
+  xfree (certid);
+
+  rc = assuan_transact (dirmngr_ctx, line, NULL, NULL, inq_certificate, NULL);
+  return map_assuan_err (rc);
+}
+
+
+
index 31ddcd8..69a9c55 100644 (file)
@@ -69,6 +69,33 @@ gpgsm_validate_path (KsbaCert cert)
           goto leave;
         }
 
+      if (!opt.no_crl_check)
+        {
+          rc = gpgsm_dirmngr_isvalid (subject_cert);
+          if (rc)
+            {
+              switch (rc)
+                {
+                case GNUPG_Certificate_Revoked:
+                  log_error (_("the certificate has been revoked\n"));
+                  break;
+                case GNUPG_No_CRL_Known:
+                  log_error (_("no CRL found for certificate\n"));
+                  break;
+                case GNUPG_CRL_Too_Old:
+                  log_error (_("the available CRL is too old\n"));
+                  log_info (_("please make sure that the "
+                              "\"dirmngr\" is properly installed\n"));
+                  break;
+                default:
+                  log_error (_("checking the CRL failed: %s\n"),
+                             gnupg_strerror (rc));
+                  break;
+                }
+              goto leave;
+            }
+        }
+
       if (subject && !strcmp (issuer, subject))
         {
           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
@@ -118,6 +145,10 @@ gpgsm_validate_path (KsbaCert cert)
       subject_cert = issuer_cert;
       issuer_cert = NULL;
     }
+
+  if (opt.no_crl_check)
+    log_info ("CRL was not checked due to --no-crl-cechk option\n");
+
   
  leave:
   xfree (issuer);
index 31ddcd8..69a9c55 100644 (file)
@@ -69,6 +69,33 @@ gpgsm_validate_path (KsbaCert cert)
           goto leave;
         }
 
+      if (!opt.no_crl_check)
+        {
+          rc = gpgsm_dirmngr_isvalid (subject_cert);
+          if (rc)
+            {
+              switch (rc)
+                {
+                case GNUPG_Certificate_Revoked:
+                  log_error (_("the certificate has been revoked\n"));
+                  break;
+                case GNUPG_No_CRL_Known:
+                  log_error (_("no CRL found for certificate\n"));
+                  break;
+                case GNUPG_CRL_Too_Old:
+                  log_error (_("the available CRL is too old\n"));
+                  log_info (_("please make sure that the "
+                              "\"dirmngr\" is properly installed\n"));
+                  break;
+                default:
+                  log_error (_("checking the CRL failed: %s\n"),
+                             gnupg_strerror (rc));
+                  break;
+                }
+              goto leave;
+            }
+        }
+
       if (subject && !strcmp (issuer, subject))
         {
           if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
@@ -118,6 +145,10 @@ gpgsm_validate_path (KsbaCert cert)
       subject_cert = issuer_cert;
       issuer_cert = NULL;
     }
+
+  if (opt.no_crl_check)
+    log_info ("CRL was not checked due to --no-crl-cechk option\n");
+
   
  leave:
   xfree (issuer);
index a8edf6f..fec5f14 100644 (file)
@@ -187,6 +187,73 @@ gpgsm_get_keygrip_hexstring (KsbaCert cert)
 }
 
 
+\f
+/* For certain purposes we need a certificate id which has an upper
+   limit of the size.  We use the hash of the issuer name and the
+   serial number for this.  In most cases the serial number is not
+   that large and the resulting string can be passed on an assuan
+   command line.  Everything is hexencoded with the serialnumber
+   delimted from the has by a dot. 
+
+   The caller must free the string.
+*/
+char *
+gpgsm_get_certid (KsbaCert cert)
+{
+  KsbaSexp serial;
+  unsigned char *p;
+  char *endp;
+  unsigned char hash[20];
+  unsigned long n;
+  char *certid;
+  int i;
+  
+  p = ksba_cert_get_issuer (cert, 0);
+  if (!p)
+    return NULL; /* Ooops: No issuer */
+  gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
+  xfree (p);
+
+  serial = ksba_cert_get_serial (cert);
+  if (!serial)
+    return NULL; /* oops: no serial number */
+  p = serial;
+  if (*p != '(')
+    {
+      log_error ("Ooops: invalid serial number\n");
+      xfree (serial);
+      return NULL;
+    }
+  p++;
+  n = strtoul (p, &endp, 10);
+  p = endp;
+  if (*p != ':')
+    {
+      log_error ("Ooops: invalid serial number (no colon)\n");
+      xfree (serial);
+      return NULL;
+    }
+  p++;
+
+  certid = xtrymalloc ( 40 + 1 + n*2 + 1);
+  if (!certid)
+    {
+      xfree (serial);
+      return NULL; /* out of core */
+    }
+
+  for (i=0, endp = certid; i < 20; i++, endp += 2 )
+    sprintf (endp, "%02X", hash[i]);
+  *endp++ = '.';
+  for (i=0; i < n; i++, endp += 2)
+    sprintf (endp, "%02X", hash[i]);
+  *endp = 0;
+
+  xfree (serial);
+  return certid;
+}
+
+
 
 
 
index 130697f..0ca22b6 100644 (file)
@@ -83,7 +83,7 @@ enum cmd_and_opt_values {
 
   oEnableSpecialFilenames,
   oAgentProgram,
-
+  oDirmngrProgram,
 
 
 
@@ -95,7 +95,7 @@ enum cmd_and_opt_values {
   oBase64,
   oNoArmor,
 
-
+  oDisableCRLChecks,
 
   oTextmode,
   oFingerprint,
@@ -224,6 +224,10 @@ static ARGPARSE_OPTS opts[] = {
 
     { oRecipient, "recipient", 2, N_("|NAME|encrypt for NAME")},
 
+
+    { oDisableCRLChecks, "disable-crl-checks", 0, N_("never consult a CRL")},
+
+
 #if 0
     { oDefRecipient, "default-recipient" ,2,
                                  N_("|NAME|use NAME as default recipient")},
@@ -315,6 +319,7 @@ static ARGPARSE_OPTS opts[] = {
     { oNoOptions, "no-options", 0, "@" }, /* shortcut for --options /dev/null */
     { oHomedir, "homedir", 2, "@" },   /* defaults to "~/.gnupg" */
     { oAgentProgram, "agent-program", 2 , "@" },
+    { oDirmngrProgram, "dirmngr-program", 2 , "@" },
 
     { oNoBatch, "no-batch", 0, "@" },
     { oWithColons, "with-colons", 0, "@"},
@@ -727,6 +732,10 @@ main ( int argc, char **argv)
           ctrl.is_pem = 0;
           ctrl.is_base64 = 0;
           break;
+
+        case oDisableCRLChecks:
+          opt.no_crl_check = 1;
+          break;
           
 
         case oOutput: opt.outfile = pargs.r.ret_str; break;
@@ -780,6 +789,7 @@ main ( int argc, char **argv)
         case oNoOptions: break; /* no-options */
         case oHomedir: opt.homedir = pargs.r.ret_str; break;
         case oAgentProgram: opt.agent_program = pargs.r.ret_str;  break;
+        case oDirmngrProgram: opt.dirmngr_program = pargs.r.ret_str;  break;
           
         case oNoDefKeyring: default_keyring = 0; break;
         case oNoGreeting: nogreeting = 1; break;
index bc2b5ec..0ec923d 100644 (file)
@@ -39,6 +39,7 @@ struct {
 
   const char *homedir; /* configuration directory name */
   const char *agent_program; 
+  const char *dirmngr_program;
   char *outfile;    /* name of output file */
 
   int with_key_data;/* include raw key in the column delimted output */
@@ -65,6 +66,8 @@ struct {
 
   int ignore_time_conflict; /* Ignore certain time conflicts */
 
+  int no_crl_check;       /* Don't do a CRL check */
+
 } opt;
 
 
@@ -126,6 +129,8 @@ char *gpgsm_get_fingerprint_string (KsbaCert cert, int algo);
 char *gpgsm_get_fingerprint_hexstring (KsbaCert cert, int algo);
 char *gpgsm_get_keygrip (KsbaCert cert, char *array);
 char *gpgsm_get_keygrip_hexstring (KsbaCert cert);
+char *gpgsm_get_certid (KsbaCert cert);
+
 
 /*-- base64.c --*/
 int  gpgsm_create_reader (Base64Context *ctx,
@@ -190,6 +195,12 @@ int gpgsm_agent_pkdecrypt (const char *keygrip,
                            char **r_buf, size_t *r_buflen);
 int gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey);
 
+/*-- call-dirmngr.c --*/
+int gpgsm_dirmngr_isvalid (KsbaCert cert);
+
+
+
+
 
 #endif /*GPGSM_H*/