* verify.c (gpgsm_verify): Print STATUS_NEWSIG for each signature.
authorWerner Koch <wk@gnupg.org>
Mon, 5 Apr 2004 17:25:21 +0000 (17:25 +0000)
committerWerner Koch <wk@gnupg.org>
Mon, 5 Apr 2004 17:25:21 +0000 (17:25 +0000)
* certchain.c (gpgsm_validate_chain) <gpgsm_cert_use_cer_p>: Do
not just warn if a cert is not suitable; bail out immediately.

* call-dirmngr.c (isvalid_status_cb): New.
(unhexify_fpr): New. Taken from ../g10/call-agent.c
(gpgsm_dirmngr_isvalid): Add new arg CTRL, changed caller to pass
it thru.  Detect need to check the respondert cert and do that.
* certchain.c (gpgsm_validate_chain): Add new arg FLAGS.  Changed
all callers.

sm/ChangeLog
sm/call-dirmngr.c
sm/certchain.c
sm/certlist.c
sm/gpgsm.h
sm/keylist.c
sm/sign.c
sm/verify.c

index ecf1125..c1ca076 100644 (file)
@@ -1,3 +1,19 @@
+2004-04-05  Werner Koch  <wk@gnupg.org>
+
+       * verify.c (gpgsm_verify): Print STATUS_NEWSIG for each signature.
+
+       * certchain.c (gpgsm_validate_chain) <gpgsm_cert_use_cer_p>: Do
+       not just warn if a cert is not suitable; bail out immediately.
+
+2004-04-01  Werner Koch  <wk@gnupg.org>
+
+       * call-dirmngr.c (isvalid_status_cb): New.
+       (unhexify_fpr): New. Taken from ../g10/call-agent.c
+       (gpgsm_dirmngr_isvalid): Add new arg CTRL, changed caller to pass
+       it thru.  Detect need to check the respondert cert and do that.
+       * certchain.c (gpgsm_validate_chain): Add new arg FLAGS.  Changed
+       all callers.
+
 2004-03-24  Werner Koch  <wk@gnupg.org>
 
        * sign.c (gpgsm_sign): Include a short list of capabilities.
index 4f07fec..0e8f67f 100644 (file)
@@ -33,6 +33,8 @@
 #include <assuan.h>
 
 #include "i18n.h"
+#include "keydb.h"
+
 
 struct membuf {
   size_t len;
@@ -52,6 +54,12 @@ struct inq_certificate_parm_s {
   ksba_cert_t issuer_cert;
 };
 
+struct isvalid_status_parm_s {
+  int seen;
+  unsigned char fpr[20];
+};
+
+
 struct lookup_parm_s {
   CTRL ctrl;
   ASSUAN_CONTEXT ctx;
@@ -300,6 +308,42 @@ inq_certificate (void *opaque, const char *line)
 }
 
 
+/* Take a 20 byte hexencoded string and put it into the the provided
+   20 byte buffer FPR in binary format. */
+static int
+unhexify_fpr (const char *hexstr, unsigned char *fpr)
+{
+  const char *s;
+  int n;
+
+  for (s=hexstr, n=0; hexdigitp (s); s++, n++)
+    ;
+  if (*s || (n != 40))
+    return 0; /* no fingerprint (invalid or wrong length). */
+  n /= 2;
+  for (s=hexstr, n=0; *s; s += 2, n++)
+    fpr[n] = xtoi_2 (s);
+  return 1; /* okay */
+}
+
+
+static assuan_error_t
+isvalid_status_cb (void *opaque, const char *line)
+{
+  struct isvalid_status_parm_s *parm = opaque;
+
+  if (!strncmp (line, "ONLY_VALID_IF_CERT_VALID", 24)
+      && (line[24]==' ' || !line[24]))
+    {
+      parm->seen++;
+      if (!line[24] || !unhexify_fpr (line+25, parm->fpr))
+        parm->seen++; /* Bumb it to indicate an error. */
+    }
+  return 0;
+}
+
+
+
 \f
 /* Call the directory manager to check whether the certificate is valid
    Returns 0 for valid or usually one of the errors:
@@ -312,12 +356,14 @@ inq_certificate (void *opaque, const char *line)
   request first.
  */
 int
-gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
+gpgsm_dirmngr_isvalid (ctrl_t ctrl,
+                       ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
 {
   int rc;
   char *certid;
   char line[ASSUAN_LINELENGTH];
   struct inq_certificate_parm_s parm;
+  struct isvalid_status_parm_s stparm;
 
   rc = start_dirmngr ();
   if (rc)
@@ -349,6 +395,9 @@ gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
   parm.cert = cert;
   parm.issuer_cert = issuer_cert;
 
+  stparm.seen = 0;
+  memset (stparm.fpr, 0, 20);
+
   /* FIXME: If --disable-crl-checks has been set, we should pass an
      option to dirmngr, so that no fallback CRL check is done after an
      ocsp check. */
@@ -358,10 +407,66 @@ gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert, int use_ocsp)
   xfree (certid);
 
   rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
-                        inq_certificate, &parm, NULL, NULL);
+                        inq_certificate, &parm,
+                        isvalid_status_cb, &stparm);
   if (opt.verbose > 1)
     log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
-  return map_assuan_err (rc);
+  rc = map_assuan_err (rc);
+
+  if (!rc && stparm.seen)
+    {
+      /* Need to also check the certificate validity. */
+      if (stparm.seen != 1)
+        {
+          log_error ("communication problem with dirmngr detected\n");
+          rc = gpg_error (GPG_ERR_INV_CRL);
+        }
+      else
+        {
+          KEYDB_HANDLE kh;
+          ksba_cert_t rspcert = NULL;
+
+          /* Fixme: First try to get the certificate from the
+             dirmngr's cache - it should be there. */
+          kh = keydb_new (0);
+          if (!kh)
+            rc = gpg_error (GPG_ERR_ENOMEM);
+          if (!rc)
+            rc = keydb_search_fpr (kh, stparm.fpr);
+          if (!rc)
+            rc = keydb_get_cert (kh, &rspcert);
+          if (rc)
+            {
+              log_error ("unable to find the certificate used "
+                         "by the dirmngr: %s\n", gpg_strerror (rc));
+              rc = gpg_error (GPG_ERR_INV_CRL);
+            }
+          keydb_release (kh);
+
+          if (!rc)
+            {
+              /* fixme: We should refine the check to check for
+                 certificates allowed for CRL/OCPS. */
+              rc = gpgsm_cert_use_verify_p (rspcert);
+              if (rc)
+                rc = gpg_error (GPG_ERR_INV_CRL);
+              else
+                {
+                  /* Note, the flag = 1: This avoids checking this
+                     certificate over and over again. */
+                  rc = gpgsm_validate_chain (ctrl, rspcert, NULL, 0, NULL, 1);
+                  if (rc)
+                    {
+                      log_error ("invalid certificate used for CRL/OCSP: %s\n",
+                                 gpg_strerror (rc));
+                      rc = gpg_error (GPG_ERR_INV_CRL);
+                    }
+                }
+            }
+          ksba_cert_release (rspcert);
+        }
+    }
+  return rc;
 }
 
 
index 5056139..3bdba2a 100644 (file)
@@ -480,7 +480,8 @@ is_cert_still_valid (ctrl_t ctrl, int lm, FILE *fp,
     {
       gpg_error_t err;
 
-      err = gpgsm_dirmngr_isvalid (subject_cert, issuer_cert, ctrl->use_ocsp);
+      err = gpgsm_dirmngr_isvalid (ctrl,
+                                   subject_cert, issuer_cert, ctrl->use_ocsp);
       if (err)
         {
           /* Fixme: We should change the wording because we may
@@ -522,10 +523,13 @@ is_cert_still_valid (ctrl_t ctrl, int lm, FILE *fp,
 /* Validate a chain and optionally return the nearest expiration time
    in R_EXPTIME. With LISTMODE set to 1 a special listmode is
    activated where only information about the certificate is printed
-   to FP and no outputis send to the usual log stream. */
+   to FP and no output is send to the usual log stream. 
+
+   Defined flag bits: 0 - do not do any dirmngr isvalid checks.
+*/
 int
 gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
-                      int listmode, FILE *fp)
+                      int listmode, FILE *fp, unsigned int flags)
 {
   int rc = 0, depth = 0, maxdepth;
   char *issuer = NULL;
@@ -698,10 +702,13 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
             }
           
           /* Check for revocations etc. */
-          rc = is_cert_still_valid (ctrl, lm, fp,
-                                    subject_cert, subject_cert,
-                                    &any_revoked, &any_no_crl,
-                                    &any_crl_too_old);
+          if ((flags & 1))
+            rc = 0;
+          else
+            rc = is_cert_still_valid (ctrl, lm, fp,
+                                      subject_cert, subject_cert,
+                                      &any_revoked, &any_no_crl,
+                                      &any_crl_too_old);
           if (rc)
             goto leave;
 
@@ -818,14 +825,17 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
               sprintf (numbuf, "%d", rc);
               gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage",
                              numbuf, NULL);
-              rc = 0;
+              goto leave;
             }
         }
 
       /* Check for revocations etc. */
-      rc = is_cert_still_valid (ctrl, lm, fp,
-                                subject_cert, issuer_cert,
-                                &any_revoked, &any_no_crl, &any_crl_too_old);
+      if ((flags & 1))
+        rc = 0;
+      else
+        rc = is_cert_still_valid (ctrl, lm, fp,
+                                  subject_cert, issuer_cert,
+                                  &any_revoked, &any_no_crl, &any_crl_too_old);
       if (rc)
         goto leave;
 
index 6e694b7..0394a58 100644 (file)
@@ -130,7 +130,8 @@ cert_usage_p (ksba_cert_t cert, int mode)
     {
       if ((use & (KSBA_KEYUSAGE_KEY_CERT_SIGN)))
         return 0;
-      log_info ( _("certificate should have not been used certification\n"));
+      log_info (_("certificate should have not "
+                  "been used for certification\n"));
       return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
     }
 
@@ -347,7 +348,7 @@ gpgsm_add_to_certlist (CTRL ctrl, const char *name, int secret,
                     }
                 }
               if (!rc)
-                rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL);
+                rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL, 0);
               if (!rc)
                 {
                   CERTLIST cl = xtrycalloc (1, sizeof *cl);
index 62bc053..93487f0 100644 (file)
@@ -222,7 +222,8 @@ int gpgsm_walk_cert_chain (ksba_cert_t start, ksba_cert_t *r_next);
 int gpgsm_is_root_cert (ksba_cert_t cert);
 int gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert,
                           ksba_isotime_t r_exptime,
-                          int listmode, FILE *listfp);
+                          int listmode, FILE *listfp,
+                          unsigned int flags);
 int gpgsm_basic_cert_check (ksba_cert_t cert);
 
 /*-- certlist.c --*/
@@ -288,7 +289,8 @@ int gpgsm_agent_learn (void);
 int gpgsm_agent_passwd (const char *hexkeygrip, const char *desc);
 
 /*-- call-dirmngr.c --*/
-int gpgsm_dirmngr_isvalid (ksba_cert_t cert, ksba_cert_t issuer_cert,
+int gpgsm_dirmngr_isvalid (ctrl_t ctrl,
+                           ksba_cert_t cert, ksba_cert_t issuer_cert,
                            int use_ocsp);
 int gpgsm_dirmngr_lookup (ctrl_t ctrl, STRLIST names,
                           void (*cb)(void*, ksba_cert_t), void *cb_value);
index 80cc675..4e6f28d 100644 (file)
@@ -182,7 +182,7 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
   gpg_error_t valerr;
 
   if (ctrl->with_validation)
-    valerr = gpgsm_validate_chain (ctrl, cert, NULL, 1, NULL);
+    valerr = gpgsm_validate_chain (ctrl, cert, NULL, 1, NULL, 0);
   else
     valerr = 0;
 
@@ -483,7 +483,7 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
 
   if (with_validation)
     {
-      err = gpgsm_validate_chain (ctrl, cert, NULL, 1, fp);
+      err = gpgsm_validate_chain (ctrl, cert, NULL, 1, fp, 0);
       if (!err)
         fprintf (fp, "  [certificate is good]\n");
       else
index 3cc1444..473cf93 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -378,7 +378,7 @@ gpgsm_sign (CTRL ctrl, CERTLIST signerlist,
          valid. */
       rc = gpgsm_cert_use_sign_p (cert);
       if (!rc)
-        rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL);
+        rc = gpgsm_validate_chain (ctrl, cert, NULL, 0, NULL, 0);
       if (rc)
         goto leave;
 
index bd33490..4b43ed0 100644 (file)
@@ -263,6 +263,9 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
             err = 0;
           break;
         }
+
+      gpgsm_status (ctrl, STATUS_NEWSIG, NULL);
+
       if (DBG_X509)
         {
           log_debug ("signer %d - issuer: `%s'\n",
@@ -458,7 +461,7 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
 
       if (DBG_X509)
         log_debug ("signature okay - checking certs\n");
-      rc = gpgsm_validate_chain (ctrl, cert, keyexptime, 0, NULL);
+      rc = gpgsm_validate_chain (ctrl, cert, keyexptime, 0, NULL, 0);
       if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
         {
           gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);