* certlist.c (gpgsm_add_to_certlist): Fixed locating of a
authorWerner Koch <wk@gnupg.org>
Thu, 20 Jun 2002 10:43:02 +0000 (10:43 +0000)
committerWerner Koch <wk@gnupg.org>
Thu, 20 Jun 2002 10:43:02 +0000 (10:43 +0000)
certificate with the required key usage.

* gpgsm.c (main): Fixed a segv when using --outfile without an
argument.

* keylist.c (print_capabilities): Also check for non-repudiation
and data encipherment.
* certlist.c (cert_usage_p): Test for signing and encryption was
swapped.  Add a case for certification usage, handle
non-repudiation and data encipherment.
(gpgsm_cert_use_cert_p): New.
(gpgsm_add_to_certlist): Added a CTRL argument and changed all
callers to pass it.
* certpath.c (gpgsm_validate_path): Use it here to print a status
message. Added a CTRL argument and changed all callers to pass it.
* decrypt.c (gpgsm_decrypt): Print a status message for wrong key
usage.
* verify.c (gpgsm_verify): Ditto.
* keydb.c (classify_user_id): Allow a colon delimited fingerprint.

12 files changed:
sm/ChangeLog
sm/call-dirmngr.c
sm/certchain.c
sm/certlist.c
sm/certpath.c
sm/decrypt.c
sm/gpgsm.c
sm/gpgsm.h
sm/keydb.c
sm/keylist.c
sm/server.c
sm/verify.c

index 87426cb..b612c1d 100644 (file)
@@ -1,3 +1,26 @@
+2002-06-20  Werner Koch  <wk@gnupg.org>
+
+       * certlist.c (gpgsm_add_to_certlist): Fixed locating of a
+       certificate with the required key usage.
+
+       * gpgsm.c (main): Fixed a segv when using --outfile without an
+       argument.
+
+       * keylist.c (print_capabilities): Also check for non-repudiation
+       and data encipherment.
+       * certlist.c (cert_usage_p): Test for signing and encryption was
+       swapped.  Add a case for certification usage, handle
+       non-repudiation and data encipherment.
+       (gpgsm_cert_use_cert_p): New.
+       (gpgsm_add_to_certlist): Added a CTRL argument and changed all
+       callers to pass it.
+       * certpath.c (gpgsm_validate_path): Use it here to print a status
+       message. Added a CTRL argument and changed all callers to pass it.
+       * decrypt.c (gpgsm_decrypt): Print a status message for wrong key
+       usage.
+       * verify.c (gpgsm_verify): Ditto.
+       * keydb.c (classify_user_id): Allow a colon delimited fingerprint.
+
 2002-06-19  Werner Koch  <wk@gnupg.org>
 
        * call-agent.c (learn_cb): Use log_info instead of log_error on
index 3128866..1cdf3e2 100644 (file)
@@ -420,7 +420,6 @@ static AssuanError
 lookup_status_cb (void *opaque, const char *line)
 {
   struct lookup_parm_s *parm = opaque;
-  int i;
 
   if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
     {
index 0b2d8b4..01696fc 100644 (file)
@@ -308,7 +308,7 @@ gpgsm_is_root_cert (KsbaCert cert)
 /* Validate a path and optionally return the nearest expiration time
    in R_EXPTIME */
 int
-gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
+gpgsm_validate_path (CTRL ctrl, KsbaCert cert, time_t *r_exptime)
 {
   int rc = 0, depth = 0, maxdepth;
   char *issuer = NULL;
@@ -551,6 +551,14 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
           }
       }
 
+      rc = gpgsm_cert_use_cert_p (issuer_cert);
+      if (rc)
+        {
+          gpgsm_status2 (ctrl, STATUS_ERROR, "certpath.issuer.keyusage",
+                         gnupg_error_token (rc), NULL);
+          rc = 0;
+        }
+
       if (opt.verbose)
         log_info ("certificate is good\n");
       
index 177f867..ca61eb0 100644 (file)
@@ -60,8 +60,18 @@ cert_usage_p (KsbaCert cert, int mode)
       return map_ksba_err (err);
     } 
 
-  if ((use & ((mode&1)? KSBA_KEYUSAGE_DIGITAL_SIGNATURE
-              : KSBA_KEYUSAGE_KEY_ENCIPHERMENT)))
+  if (mode == 4)
+    {
+      if ((use & (KSBA_KEYUSAGE_KEY_CERT_SIGN)))
+        return 0;
+      log_info ( _("certificate should have not been used certification\n"));
+      return GNUPG_Wrong_Key_Usage;
+    }
+
+  if ((use & ((mode&1)?
+              (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT):
+              (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION)))
+      )
     return 0;
   log_info (mode==3? _("certificate should have not been used for encryption\n"):
             mode==2? _("certificate should have not been used for signing\n"):
@@ -98,10 +108,35 @@ gpgsm_cert_use_decrypt_p (KsbaCert cert)
   return cert_usage_p (cert, 3);
 }
 
+int
+gpgsm_cert_use_cert_p (KsbaCert cert)
+{
+  return cert_usage_p (cert, 4);
+}
+
+
+static int
+same_subject_issuer (const char *subject, const char *issuer, KsbaCert cert)
+{
+  char *subject2 = ksba_cert_get_subject (cert, 0);
+  char *issuer2 = ksba_cert_get_subject (cert, 0);
+  int tmp;
+  
+  tmp = (subject && subject2
+         && !strcmp (subject, subject2)
+         && issuer && issuer2
+         && !strcmp (issuer, issuer2));
+  xfree (subject2);
+  xfree (issuer2);
+  return tmp;
+}
+
+
+
 /* add a certificate to a list of certificate and make sure that it is
    a valid certificate */
 int
-gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
+gpgsm_add_to_certlist (CTRL ctrl, const char *name, CERTLIST *listaddr)
 {
   int rc;
   KEYDB_SEARCH_DESC desc;
@@ -117,6 +152,9 @@ gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
       else
         {
           int wrong_usage = 0;
+          char *subject = NULL;
+          char *issuer = NULL;
+
         get_next:
           rc = keydb_search (kh, &desc, 1);
           if (!rc)
@@ -127,32 +165,61 @@ gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr)
               if (rc == GNUPG_Wrong_Key_Usage)
                 {
                   /* There might be another certificate with the
-                     correct usage, so we better try again */
-                  wrong_usage = rc;
-                  ksba_cert_release (cert);
-                  cert = NULL;
-                  goto get_next;
+                     correct usage, so we try again */
+                  if (!wrong_usage)
+                    { /* save the first match */
+                      wrong_usage = rc;
+                      subject = ksba_cert_get_subject (cert, 0);
+                      issuer = ksba_cert_get_subject (cert, 0);
+                      ksba_cert_release (cert);
+                      cert = NULL;
+                      goto get_next;
+                    }
+                  else if (same_subject_issuer (subject, issuer, cert))
+                    {
+                      wrong_usage = rc;
+                      ksba_cert_release (cert);
+                      cert = NULL;
+                      goto get_next;
+                    }
+                  else
+                    wrong_usage = rc;
+
                 }
             }
           /* we want the error code from the first match in this case */
-          if (wrong_usage)
+          if (rc && wrong_usage)
             rc = wrong_usage;
-
+          
           if (!rc)
             {
-              /* Fixme: If we ever have two certifciates differing
-                 only in the key usage, we should only bail out here
-                 if the certificate differes just in the key usage.
-                 However we need to find some criteria to match the
-                 identities */
+            next_ambigious:
               rc = keydb_search (kh, &desc, 1);
               if (rc == -1)
                 rc = 0;
               else if (!rc)
-                rc = GNUPG_Ambiguous_Name;
+                {
+                  KsbaCert cert2 = NULL;
+
+                  /* We have to ignore ambigious names as long as
+                     there only fault is a bad key usage */
+                  if (!keydb_get_cert (kh, &cert2))
+                    {
+                      int tmp = (same_subject_issuer (subject, issuer, cert2)
+                                 && (gpgsm_cert_use_encrypt_p (cert2)
+                                     == GNUPG_Wrong_Key_Usage));
+                      ksba_cert_release (cert2);
+                      if (tmp)
+                        goto next_ambigious;
+                    }
+                  rc = GNUPG_Ambiguous_Name;
+                }
             }
+          xfree (subject);
+          xfree (issuer);
+
           if (!rc)
-            rc = gpgsm_validate_path (cert, NULL);
+            rc = gpgsm_validate_path (ctrl, cert, NULL);
           if (!rc)
             {
               CERTLIST cl = xtrycalloc (1, sizeof *cl);
index 0b2d8b4..01696fc 100644 (file)
@@ -308,7 +308,7 @@ gpgsm_is_root_cert (KsbaCert cert)
 /* Validate a path and optionally return the nearest expiration time
    in R_EXPTIME */
 int
-gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
+gpgsm_validate_path (CTRL ctrl, KsbaCert cert, time_t *r_exptime)
 {
   int rc = 0, depth = 0, maxdepth;
   char *issuer = NULL;
@@ -551,6 +551,14 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
           }
       }
 
+      rc = gpgsm_cert_use_cert_p (issuer_cert);
+      if (rc)
+        {
+          gpgsm_status2 (ctrl, STATUS_ERROR, "certpath.issuer.keyusage",
+                         gnupg_error_token (rc), NULL);
+          rc = 0;
+        }
+
       if (opt.verbose)
         log_info ("certificate is good\n");
       
index e3566fd..ccbcae2 100644 (file)
@@ -381,7 +381,13 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
                   /* Just in case there is a problem with the own
                      certificate we print this message - should never
                      happen of course */
-                  gpgsm_cert_use_decrypt_p (cert);
+                  rc = gpgsm_cert_use_decrypt_p (cert);
+                  if (rc)
+                    {
+                      gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.keyusage",
+                                     gnupg_error_token (rc), NULL);
+                      rc = 0;
+                    }
 
                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
 
index 06a3a9c..385648c 100644 (file)
@@ -1054,7 +1054,7 @@ main ( int argc, char **argv)
 
   for (sl = remusr; sl; sl = sl->next)
     {
-      int rc = gpgsm_add_to_certlist (sl->d, &recplist);
+      int rc = gpgsm_add_to_certlist (&ctrl, sl->d, &recplist);
       if (rc)
         {
           log_error (_("can't encrypt to `%s': %s\n"),
@@ -1164,7 +1164,7 @@ main ( int argc, char **argv)
       {
         FILE *fp = NULL;
 
-        if (argc == 2 && *opt.outfile)
+        if (argc == 2 && opt.outfile)
           log_info ("option --output ignored for a detached signature\n");
         else if (opt.outfile)
           fp = open_fwrite (opt.outfile);
index 43c1543..a3cf903 100644 (file)
@@ -186,7 +186,7 @@ int gpgsm_create_cms_signature (KsbaCert cert, GCRY_MD_HD md, int mdalgo,
 /*-- certpath.c --*/
 int gpgsm_walk_cert_chain (KsbaCert start, KsbaCert *r_next);
 int gpgsm_is_root_cert (KsbaCert cert);
-int gpgsm_validate_path (KsbaCert cert, time_t *r_exptime);
+int gpgsm_validate_path (CTRL ctrl, KsbaCert cert, time_t *r_exptime);
 int gpgsm_basic_cert_check (KsbaCert cert);
 
 /*-- certlist.c --*/
@@ -194,7 +194,8 @@ int gpgsm_cert_use_sign_p (KsbaCert cert);
 int gpgsm_cert_use_encrypt_p (KsbaCert cert);
 int gpgsm_cert_use_verify_p (KsbaCert cert);
 int gpgsm_cert_use_decrypt_p (KsbaCert cert);
-int gpgsm_add_to_certlist (const char *name, CERTLIST *listaddr);
+int gpgsm_cert_use_cert_p (KsbaCert cert);
+int gpgsm_add_to_certlist (CTRL ctrl, const char *name, CERTLIST *listaddr);
 void gpgsm_release_certlist (CERTLIST list);
 int gpgsm_find_cert (const char *name, KsbaCert *r_cert);
 
index 50c9e54..bc47214 100644 (file)
@@ -1137,10 +1137,31 @@ classify_user_id (const char *name,
           mode = KEYDB_SEARCH_MODE_FPR20;
         }
       else if (!hexprefix)
-        { /* default is substring search */
-          *force_exact = 0;
-          desc->u.name = s;
-          mode = KEYDB_SEARCH_MODE_SUBSTR; 
+        { 
+          /* The fingerprint in an X.509 listing is often delimited by
+             colons, so we try to single this case out. */
+          mode = 0;
+          hexlength = strspn (s, ":0123456789abcdefABCDEF");
+          if (hexlength == 59 && (!s[hexlength] || spacep (s+hexlength))) 
+            {
+              int i;
+
+              for (i=0; i < 20; i++, s += 3) 
+                {
+                  int c = hextobyte(s);
+                  if (c == -1 || (i < 19 && s[2] != ':'))
+                    break;
+                  desc->u.fpr[i] = c;
+                }
+              if (i == 20)
+                mode = KEYDB_SEARCH_MODE_FPR20;
+            }
+          if (!mode) /* default is substring search */
+            { 
+              *force_exact = 0;
+              desc->u.name = s;
+              mode = KEYDB_SEARCH_MODE_SUBSTR; 
+            }
         }
       else
        { /* hex number with a prefix but a wrong length */
index a8d9c54..c17fb70 100644 (file)
@@ -84,15 +84,15 @@ print_capabilities (KsbaCert cert, FILE *fp)
       return;
     } 
 
-  if ((use & KSBA_KEYUSAGE_KEY_ENCIPHERMENT))
+  if ((use & (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT)))
     putc ('e', fp);
-  if ((use & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
+  if ((use & (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION)))
     putc ('s', fp);
   if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
     putc ('c', fp);
-  if ((use & KSBA_KEYUSAGE_KEY_ENCIPHERMENT))
+  if ((use & (KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT)))
     putc ('E', fp);
-  if ((use & KSBA_KEYUSAGE_DIGITAL_SIGNATURE))
+  if ((use & (KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION)))
     putc ('S', fp);
   if ((use & KSBA_KEYUSAGE_KEY_CERT_SIGN))
     putc ('C', fp);
index 69abe7a..a7ae98d 100644 (file)
@@ -239,7 +239,7 @@ cmd_recipient (ASSUAN_CONTEXT ctx, char *line)
   CTRL ctrl = assuan_get_pointer (ctx);
   int rc;
 
-  rc = gpgsm_add_to_certlist (line, &ctrl->server_local->recplist);
+  rc = gpgsm_add_to_certlist (ctrl, line, &ctrl->server_local->recplist);
   if (rc)
     gpgsm_status2 (ctrl, STATUS_INV_RECP,
                    rc == -1? "1":
index 286dc68..d5f8629 100644 (file)
@@ -389,10 +389,17 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
           gpgsm_status (ctrl, STATUS_BADSIG, NULL);
           goto next_signer;
         }
-      gpgsm_cert_use_verify_p (cert); /* this displays an info message */
+      rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
+      if (rc)
+        {
+          gpgsm_status2 (ctrl, STATUS_ERROR, "verify.keyusage",
+                         gnupg_error_token (rc), NULL);
+          rc = 0;
+        }
+
       if (DBG_X509)
         log_debug ("signature okay - checking certs\n");
-      rc = gpgsm_validate_path (cert, &keyexptime);
+      rc = gpgsm_validate_path (ctrl, cert, &keyexptime);
       if (rc == GNUPG_Certificate_Expired)
         {
           gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);