* gpgsm.c (main): New option --debug-ignore-expiration.
authorWerner Koch <wk@gnupg.org>
Fri, 20 Feb 2004 13:46:21 +0000 (13:46 +0000)
committerWerner Koch <wk@gnupg.org>
Fri, 20 Feb 2004 13:46:21 +0000 (13:46 +0000)
* certchain.c (gpgsm_validate_chain): Use it here.

* certlist.c (cert_usage_p): Apply extKeyUsage.

TODO
doc/gpgsm.texi
sm/ChangeLog
sm/certchain.c
sm/certlist.c
sm/gpgsm.c
sm/gpgsm.h
sm/keylist.c

diff --git a/TODO b/TODO
index 7f06e54..496babf 100644 (file)
--- a/TODO
+++ b/TODO
@@ -21,14 +21,6 @@ might want to have an agent context for each service request
 ** When a certificate chain was sucessfully verified, make ephemeral certs used  in this chain permanent.
 ** figure out how to auto retrieve a key by serialno+issuer.
    Dirmngr is currently not able to parse more than the CN.
-** Try all available root certs in case we have several of them in our keybox.
- For example TC TrustCenter Class 1 CA certs are ambiguous becuase
- user certs don't come with a authorityKeyIdentifier.
-** Support extKeyUsage
- The only value which makes sense for us is emailProtection (I have
- not yet found a test cetificate with that).  We might want to allow
- other usages depending on special options (e.g. an option used for code
- signing).
 
 * sm/decrypt.c
 ** replace leading zero in integer hack by a cleaner solution
@@ -49,10 +41,12 @@ might want to have an agent context for each service request
 ** Remove the inter-module dependencies between gpgsm and keybox
 ** Add an source_of_key field
 ** We need an error code GPG_ERR_NOT_LOCKED
+   It is already libgpg-error.
 
 * agent/gpg-agent.c
 ** A SIGHUP should also restart the scdaemon
    But do this only after all connections terminated.
+   As of now we only send a RESET.
 
 * agent/command.c
 ** Make sure that secure memory is used where appropriate
@@ -63,10 +57,6 @@ might want to have an agent context for each service request
 * agent/divert-scd.c
  Remove the agent_reset_scd kludge.
 
-* agent/protect-tool.c
-** Export certificates along with the secret key.
-** BUG? --p12-export seems to work only with unprotected keys
-
 * Move pkcs-1 encoding into libgcrypt.
 
 * Use a MAC to protect some files.
@@ -74,12 +64,6 @@ might want to have an agent context for each service request
 * sm/export.c
 ** Return an error code or a status info per user ID.
 
-* scd/apdu.c
-** We need close_reader functionality
-
-* ALL
-** Return IMPORT_OK status.
-
 * Where is http.c, regcomp.c, srv.c, w32reg.c  ?
 
 * scd/sc-investigate
@@ -90,12 +74,12 @@ might want to have an agent context for each service request
   authentication key.  Old GnuPG versions seem to encode the wrong
   keyID.
 
-* Store the revocation status directly in the Keybox
-
 * tests
 ** Makefile.am
   We use printf(1) to setup the library path, this is not portable.
   Furthermore LD_LIBRARY_PATH is not used on all systems.  It doesn't
   matter for now, because we use some GNU/*BSDish features anyway.
 
+** Add a test to check the extkeyusage.
+
 
index 5362455..24503a1 100644 (file)
@@ -411,6 +411,12 @@ Same as @code{--debug=0xffffffff}
 This is actually not a debugging option but only useful as such.  It
 lets gpgsm bypass all certificate chain validation checks.
 
+@item --debug-ignore-expiration
+@opindex debug-ignore-expiration
+This is actually not a debugging option but only useful as such.  It
+lets gpgsm ignore all notAfter dates, this is used by the regresssion
+tests.
+
 @end table
 
 All the long options may also be given in the configuration file after
index 922773e..a8a8f3f 100644 (file)
@@ -1,3 +1,10 @@
+2004-02-20  Werner Koch  <wk@gnupg.org>
+
+       * gpgsm.c (main): New option --debug-ignore-expiration.
+       * certchain.c (gpgsm_validate_chain): Use it here.
+
+       * certlist.c (cert_usage_p): Apply extKeyUsage.
+
 2004-02-19  Werner Koch  <wk@gnupg.org>
 
        * export.c (export_p12, popen_protect_tool)
index bf55825..2a59c55 100644 (file)
@@ -66,7 +66,6 @@ do_list (int is_error, int listmode, FILE *fp, const char *format, ...)
 }
 
 
-
 static int
 unknown_criticals (ksba_cert_t cert, int listmode, FILE *fp)
 {
@@ -74,6 +73,7 @@ unknown_criticals (ksba_cert_t cert, int listmode, FILE *fp)
     "2.5.29.15", /* keyUsage */
     "2.5.29.19", /* basic Constraints */
     "2.5.29.32", /* certificatePolicies */
+    "2.5.29.37", /* extendedKeyUsage - handled by certlist.c */
     NULL
   };
   int rc = 0, i, idx, crit;
@@ -548,16 +548,20 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t r_exptime,
             rc = gpg_error (GPG_ERR_CERT_TOO_YOUNG);
             goto leave;
           }            
-        if (not_after && strcmp (current_time, not_after) > 0 )
+        if (*not_after && strcmp (current_time, not_after) > 0 )
           {
-            do_list (1, lm, fp, _("certificate has expired"));
+            do_list (opt.ignore_expiration?0:1, lm, fp,
+                     _("certificate has expired"));
             if (!lm)
               {
-                log_error ("(expired at ");
+                log_info ("(expired at ");
                 gpgsm_dump_time (not_after);
                 log_printf (")\n");
               }
-            any_expired = 1;
+            if (opt.ignore_expiration)
+                log_info ("WARNING: ignoring expiration\n");
+            else
+              any_expired = 1;
           }            
       }
 
index 66fb463..8ee3c2c 100644 (file)
@@ -1,5 +1,5 @@
 /* certlist.c - build list of certificates
- *     Copyright (C) 2001, 2003 Free Software Foundation, Inc.
+ *     Copyright (C) 2001, 2003, 2004 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 
 #include "keydb.h"
 #include "i18n.h"
+
+
+static const char oid_kp_serverAuth[]     = "1.3.6.1.5.5.7.3.1";
+static const char oid_kp_clientAuth[]     = "1.3.6.1.5.5.7.3.2";
+static const char oid_kp_codeSigning[]    = "1.3.6.1.5.5.7.3.3";
+static const char oid_kp_emailProtection[]= "1.3.6.1.5.5.7.3.4";
+static const char oid_kp_timeStamping[]   = "1.3.6.1.5.5.7.3.8";
+
 /* Return 0 if the cert is usable for encryption.  A MODE of 0 checks
    for signing a MODE of 1 checks for encryption, a MODE of 2 checks
    for verification and a MODE of 3 for decryption (just for
@@ -43,20 +50,78 @@ cert_usage_p (ksba_cert_t cert, int mode)
 {
   gpg_error_t err;
   unsigned int use;
+  char *extkeyusages;
 
-  err = ksba_cert_get_key_usage (cert, &use);
+  err = ksba_cert_get_ext_key_usages (cert, &extkeyusages);
   if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+    err = 0; /* no policy given */
+  if (!err)
     {
-      if (opt.verbose && mode < 2)
-        log_info (mode? 
-                  _("no key usage specified - accepted for encryption\n"):
-                  _("no key usage specified - accepted for signing\n"));
-      return 0;
+      unsigned int extusemask = ~0; /* Allow all. */
+
+      if (extkeyusages)
+        {
+          char *p, *pend;
+          int any_critical = 0;
+
+          extusemask = 0;
+
+          p = extkeyusages;
+          while (p && (pend=strchr (p, ':')))
+            {
+              *pend++ = 0;
+              /* Only care about critical flagged usages. */
+              if ( *pend == 'C' )
+                {
+                  any_critical = 1;
+                  if ( !strcmp (p, oid_kp_serverAuth))
+                    extusemask |= (KSBA_KEYUSAGE_DIGITAL_SIGNATURE
+                                   | KSBA_KEYUSAGE_KEY_ENCIPHERMENT
+                                   | KSBA_KEYUSAGE_KEY_AGREEMENT);
+                  else if ( !strcmp (p, oid_kp_clientAuth))
+                    extusemask |= (KSBA_KEYUSAGE_DIGITAL_SIGNATURE
+                                   | KSBA_KEYUSAGE_KEY_AGREEMENT);
+                  else if ( !strcmp (p, oid_kp_codeSigning))
+                    extusemask |= (KSBA_KEYUSAGE_DIGITAL_SIGNATURE);
+                  else if ( !strcmp (p, oid_kp_emailProtection))
+                    extusemask |= (KSBA_KEYUSAGE_DIGITAL_SIGNATURE
+                                   | KSBA_KEYUSAGE_NON_REPUDIATION
+                                   | KSBA_KEYUSAGE_KEY_ENCIPHERMENT
+                                   | KSBA_KEYUSAGE_KEY_AGREEMENT);
+                  else if ( !strcmp (p, oid_kp_timeStamping))
+                    extusemask |= (KSBA_KEYUSAGE_DIGITAL_SIGNATURE
+                                   | KSBA_KEYUSAGE_NON_REPUDIATION);
+                }
+              
+              if ((p = strchr (pend, '\n')))
+                p++;
+            }
+          xfree (extkeyusages);
+          extkeyusages = NULL;
+          
+          if (!any_critical)
+            extusemask = ~0; /* Reset to the don't care mask. */
+        }
+
+
+      err = ksba_cert_get_key_usage (cert, &use);
+      if (gpg_err_code (err) == GPG_ERR_NO_DATA)
+        {
+          err = 0;
+          if (opt.verbose && mode < 2)
+            log_info (_("no key usage specified - assuming all usages\n"));
+          use = ~0;
+        }
+
+      /* Apply extKeyUsage. */
+      use &= extusemask;
+
     }
   if (err)
     { 
       log_error (_("error getting key usage information: %s\n"),
                  gpg_strerror (err));
+      xfree (extkeyusages);
       return err;
     } 
 
@@ -73,6 +138,7 @@ cert_usage_p (ksba_cert_t cert, int mode)
               (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"):
             mode==1? _("certificate is not usable for encryption\n"):
index ede432b..68214a6 100644 (file)
@@ -89,6 +89,7 @@ enum cmd_and_opt_values {
   oDebugAll,
   oDebugWait,
   oDebugNoChainValidation,
+  oDebugIgnoreExpiration,
   oLogFile,
 
   oEnableSpecialFilenames,
@@ -323,7 +324,8 @@ static ARGPARSE_OPTS opts[] = {
     { oDebugLevel, "debug-level" ,2, "@"},
     { oDebugAll, "debug-all" ,0, "@"},
     { oDebugWait, "debug-wait" ,1, "@"},
-    { oDebugNoChainValidation, "debug-no-chain-validation" ,0, "@"},
+    { oDebugNoChainValidation, "debug-no-chain-validation", 0, "@"},
+    { oDebugIgnoreExpiration,  "debug-ignore-expiration", 0, "@"},
     { oStatusFD, "status-fd" ,1, N_("|FD|write status info to this FD") },
     { aDummy, "no-comment", 0,   "@"},
     { aDummy, "completes-needed", 1, "@"},
@@ -991,6 +993,7 @@ main ( int argc, char **argv)
         case oDebugLevel: debug_level = pargs.r.ret_str; break;
         case oDebugWait: debug_wait = pargs.r.ret_int; break;
         case oDebugNoChainValidation: opt.no_chain_validation = 1; break;
+        case oDebugIgnoreExpiration: opt.ignore_expiration = 1; break;
 
         case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
         case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
index a1711a7..6cf3ed0 100644 (file)
@@ -94,6 +94,7 @@ struct {
   char *policy_file;        /* full pathname of policy file */
   int no_policy_check;      /* ignore certificate policies */
   int no_chain_validation;  /* Bypass all cert chain validity tests */
+  int ignore_expiration;    /* Ignore the notAfter validity checks. */
 
   int auto_issuer_key_retrieve; /* try to retrieve a missing issuer key. */
 } opt;
index e6daec6..a73d18e 100644 (file)
@@ -46,6 +46,28 @@ struct list_external_parm_s {
 };
 
 
+/* This table is to map Extended Key Usage OIDs to human readable
+   names.  */
+struct {
+  const char *oid;
+  const char *name;
+} key_purpose_map[] = {
+  { "1.3.6.1.5.5.7.3.1",  "serverAuth" },
+  { "1.3.6.1.5.5.7.3.2",  "clientAuth" },          
+  { "1.3.6.1.5.5.7.3.3",  "codeSigning" },      
+  { "1.3.6.1.5.5.7.3.4",  "emailProtection" },     
+  { "1.3.6.1.5.5.7.3.5",  "ipsecEndSystem" }, 
+  { "1.3.6.1.5.5.7.3.6",  "ipsecTunnel" },  
+  { "1.3.6.1.5.5.7.3.7",  "ipsecUser" },     
+  { "1.3.6.1.5.5.7.3.8",  "timeStamping" },       
+  { "1.3.6.1.5.5.7.3.9",  "ocspSigning" },    
+  { "1.3.6.1.5.5.7.3.10", "dvcs" },      
+  { "1.3.6.1.5.5.7.3.11", "sbgpCertAAServerAuth" },
+  { "1.3.6.1.5.5.7.3.13", "eapOverPPP" },
+  { "1.3.6.1.5.5.7.3.14", "wlanSSID" },       
+  { NULL, NULL }
+};
+
 
 static void
 print_key_data (ksba_cert_t cert, FILE *fp)
@@ -292,10 +314,10 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
   ksba_sexp_t sexp;
   char *dn;
   ksba_isotime_t t;
-  int idx;
+  int idx, i;
   int is_ca, chainlen;
   unsigned int kusage;
-  char *string, *p;
+  char *string, *p, *pend;
 
   sexp = ksba_cert_get_serial (cert);
   fputs ("Serial number: ", fp);
@@ -367,6 +389,36 @@ list_cert_std (ctrl_t ctrl, ksba_cert_t cert, FILE *fp, int have_secret,
       putc ('\n', fp);
     }
 
+  err = ksba_cert_get_ext_key_usages (cert, &string);
+  if (gpg_err_code (err) != GPG_ERR_NO_DATA)
+    { 
+      fputs ("ext key usage: ", fp);
+      if (err)
+        fprintf (fp, "[error: %s]", gpg_strerror (err));
+      else
+        {
+          p = string;
+          while (p && (pend=strchr (p, ':')))
+            {
+              *pend++ = 0;
+              for (i=0; key_purpose_map[i].oid; i++)
+                if ( !strcmp (key_purpose_map[i].oid, p) )
+                  break;
+              fputs (key_purpose_map[i].oid?key_purpose_map[i].name:p, fp);
+              p = pend;
+              if (*p != 'C')
+                fputs (" (suggested)", fp);
+              if ((p = strchr (p, '\n')))
+                {
+                  p++;
+                  fputs (", ", fp);
+                }
+            }
+          xfree (string);
+        }
+      putc ('\n', fp);
+    }
+
   err = ksba_cert_get_cert_policies (cert, &string);
   if (gpg_err_code (err) != GPG_ERR_NO_DATA)
     {