* certpath.c (check_cert_policy): New.
authorWerner Koch <wk@gnupg.org>
Tue, 19 Feb 2002 17:39:05 +0000 (17:39 +0000)
committerWerner Koch <wk@gnupg.org>
Tue, 19 Feb 2002 17:39:05 +0000 (17:39 +0000)
(gpgsm_validate_path): And call it from here.
* gpgsm.c (main): New options --policy-file,
--disable-policy-checks and --enable-policy-checks.
* gpgsm.h (opt): Added policy_file, no_policy_checks.

common/errors.h
sm/ChangeLog
sm/certchain.c
sm/certpath.c
sm/gpgsm.c
sm/gpgsm.h

index d968d70..42842af 100644 (file)
@@ -92,6 +92,8 @@ enum {
   GNUPG_Card_Not_Present = 63,
   GNUPG_No_PKCS15_App = 64,
   GNUPG_Not_Confirmed = 65,
+  GNUPG_Configuration_Error = 66,
+  GNUPG_No_Policy_Match = 67,
 };
 
 /* Status codes - fixme: should go into another file */
index 9f9aaa3..167e883 100644 (file)
@@ -1,3 +1,11 @@
+2002-02-19  Werner Koch  <wk@gnupg.org>
+
+       * certpath.c (check_cert_policy): New.
+       (gpgsm_validate_path): And call it from here.
+       * gpgsm.c (main): New options --policy-file,
+       --disable-policy-checks and --enable-policy-checks.
+       * gpgsm.h (opt): Added policy_file, no_policy_checks.
+
 2002-02-18  Werner Koch  <wk@gnupg.org>
 
        * certpath.c (gpgsm_validate_path): Ask the agent to add the
index e76ff6c..0dac59a 100644 (file)
@@ -84,6 +84,114 @@ allowed_ca (KsbaCert cert, int *pathlen)
   return 0;
 }
 
+
+static int
+check_cert_policy (KsbaCert cert)
+{
+  KsbaError err;
+  char *policies;
+  FILE *fp;
+  int any_critical;
+
+  err = ksba_cert_get_cert_policies (cert, &policies);
+  if (err == KSBA_No_Data)
+    return 0; /* no policy given */
+  if (err)
+    return map_ksba_err (err);
+
+  /* STRING is a line delimited list of certifiate policies as stored
+     in the certificate.  The line itself is colon delimted where the
+     first field is the OID of the policy and the second field either
+     N or C for normal or critical extension */
+
+  /* The check is very minimal but won't give false positives */
+  any_critical = !!strstr (policies, ":C");
+
+  if (!opt.policy_file)
+    { 
+      xfree (policies);
+      if (any_critical)
+        {
+          log_error ("critical marked policy without configured policies\n");
+          return GNUPG_No_Policy_Match;
+        }
+      return 0;
+    }
+
+  fp = fopen (opt.policy_file, "r");
+  if (!fp)
+    {
+      log_error ("failed to open `%s': %s\n",
+                 opt.policy_file, strerror (errno));
+      xfree (policies);
+      return GNUPG_Configuration_Error;
+    }
+
+  for (;;) 
+    {
+      int c;
+      char *p, line[256];
+      char *haystack, *allowed;
+
+      /* read line */
+      do
+        {
+          if (!fgets (line, DIM(line)-1, fp) )
+            {
+              xfree (policies);
+              if (feof (fp))
+                {
+                  fclose (fp);
+                  log_error (_("certificate policy not allowed\n"));
+                  /* with no critical policies this is only a warning */
+                  return any_critical? GNUPG_No_Policy_Match : 0;
+                }
+              fclose (fp);
+              return GNUPG_Read_Error;
+            }
+      
+          if (!*line || line[strlen(line)-1] != '\n')
+            {
+              /* eat until end of line */
+              while ( (c=getc (fp)) != EOF && c != '\n')
+                ;
+              fclose (fp);
+              xfree (policies);
+              return *line? GNUPG_Line_Too_Long: GNUPG_Incomplete_Line;
+            }
+          
+          /* Allow for empty lines and spaces */
+          for (p=line; spacep (p); p++)
+            ;
+        }
+      while (!*p || *p == '\n' || *p == '#');
+  
+      /* parse line */
+      for (allowed=line; spacep (allowed); allowed++)
+        ;
+      p = strpbrk (allowed, " :\n");
+      if (!*p || p == allowed)
+        {
+          fclose (fp);
+          xfree (policies);
+          return GNUPG_Configuration_Error;
+        }
+      *p = 0; /* strip the rest of the line */
+      /* See whether we find ALLOWED (which is an OID) in POLICIES */
+      for (haystack=policies; (p=strstr (haystack, allowed)); haystack = p+1)
+        {
+          if ( !(p == policies || p[-1] == '\n') )
+            continue; /* does not match the begin of a line */
+          if (p[strlen (allowed)] != ':')
+            continue; /* the length does not match */
+          /* Yep - it does match so return okay */
+          fclose (fp);
+          xfree (policies);
+          return 0;
+        }
+    }
+}
+
 /* Return the next certificate up in the chain starting at START.
    Returns -1 when there are no more certificates. */
 int
@@ -216,7 +324,14 @@ gpgsm_validate_path (KsbaCert cert)
       rc = unknown_criticals (subject_cert);
       if (rc)
         goto leave;
-        
+
+      if (!opt.no_policy_check)
+        {
+          rc = check_cert_policy (subject_cert);
+          if (rc)
+            goto leave;
+        }
+
       if (!opt.no_crl_check)
         {
           rc = gpgsm_dirmngr_isvalid (subject_cert);
@@ -360,9 +475,10 @@ gpgsm_validate_path (KsbaCert cert)
       issuer_cert = NULL;
     }
 
+  if (opt.no_policy_check)
+    log_info ("policies not checked due to --disable-policy-checks option\n");
   if (opt.no_crl_check)
-    log_info ("CRL was not checked due to --no-crl-cechk option\n");
-
+    log_info ("CRLs not checked due to --disable-crl-checks option\n");
   
  leave:
   xfree (issuer);
index e76ff6c..0dac59a 100644 (file)
@@ -84,6 +84,114 @@ allowed_ca (KsbaCert cert, int *pathlen)
   return 0;
 }
 
+
+static int
+check_cert_policy (KsbaCert cert)
+{
+  KsbaError err;
+  char *policies;
+  FILE *fp;
+  int any_critical;
+
+  err = ksba_cert_get_cert_policies (cert, &policies);
+  if (err == KSBA_No_Data)
+    return 0; /* no policy given */
+  if (err)
+    return map_ksba_err (err);
+
+  /* STRING is a line delimited list of certifiate policies as stored
+     in the certificate.  The line itself is colon delimted where the
+     first field is the OID of the policy and the second field either
+     N or C for normal or critical extension */
+
+  /* The check is very minimal but won't give false positives */
+  any_critical = !!strstr (policies, ":C");
+
+  if (!opt.policy_file)
+    { 
+      xfree (policies);
+      if (any_critical)
+        {
+          log_error ("critical marked policy without configured policies\n");
+          return GNUPG_No_Policy_Match;
+        }
+      return 0;
+    }
+
+  fp = fopen (opt.policy_file, "r");
+  if (!fp)
+    {
+      log_error ("failed to open `%s': %s\n",
+                 opt.policy_file, strerror (errno));
+      xfree (policies);
+      return GNUPG_Configuration_Error;
+    }
+
+  for (;;) 
+    {
+      int c;
+      char *p, line[256];
+      char *haystack, *allowed;
+
+      /* read line */
+      do
+        {
+          if (!fgets (line, DIM(line)-1, fp) )
+            {
+              xfree (policies);
+              if (feof (fp))
+                {
+                  fclose (fp);
+                  log_error (_("certificate policy not allowed\n"));
+                  /* with no critical policies this is only a warning */
+                  return any_critical? GNUPG_No_Policy_Match : 0;
+                }
+              fclose (fp);
+              return GNUPG_Read_Error;
+            }
+      
+          if (!*line || line[strlen(line)-1] != '\n')
+            {
+              /* eat until end of line */
+              while ( (c=getc (fp)) != EOF && c != '\n')
+                ;
+              fclose (fp);
+              xfree (policies);
+              return *line? GNUPG_Line_Too_Long: GNUPG_Incomplete_Line;
+            }
+          
+          /* Allow for empty lines and spaces */
+          for (p=line; spacep (p); p++)
+            ;
+        }
+      while (!*p || *p == '\n' || *p == '#');
+  
+      /* parse line */
+      for (allowed=line; spacep (allowed); allowed++)
+        ;
+      p = strpbrk (allowed, " :\n");
+      if (!*p || p == allowed)
+        {
+          fclose (fp);
+          xfree (policies);
+          return GNUPG_Configuration_Error;
+        }
+      *p = 0; /* strip the rest of the line */
+      /* See whether we find ALLOWED (which is an OID) in POLICIES */
+      for (haystack=policies; (p=strstr (haystack, allowed)); haystack = p+1)
+        {
+          if ( !(p == policies || p[-1] == '\n') )
+            continue; /* does not match the begin of a line */
+          if (p[strlen (allowed)] != ':')
+            continue; /* the length does not match */
+          /* Yep - it does match so return okay */
+          fclose (fp);
+          xfree (policies);
+          return 0;
+        }
+    }
+}
+
 /* Return the next certificate up in the chain starting at START.
    Returns -1 when there are no more certificates. */
 int
@@ -216,7 +324,14 @@ gpgsm_validate_path (KsbaCert cert)
       rc = unknown_criticals (subject_cert);
       if (rc)
         goto leave;
-        
+
+      if (!opt.no_policy_check)
+        {
+          rc = check_cert_policy (subject_cert);
+          if (rc)
+            goto leave;
+        }
+
       if (!opt.no_crl_check)
         {
           rc = gpgsm_dirmngr_isvalid (subject_cert);
@@ -360,9 +475,10 @@ gpgsm_validate_path (KsbaCert cert)
       issuer_cert = NULL;
     }
 
+  if (opt.no_policy_check)
+    log_info ("policies not checked due to --disable-policy-checks option\n");
   if (opt.no_crl_check)
-    log_info ("CRL was not checked due to --no-crl-cechk option\n");
-
+    log_info ("CRLs not checked due to --disable-crl-checks option\n");
   
  leave:
   xfree (issuer);
index cc86f05..9927357 100644 (file)
@@ -100,10 +100,9 @@ enum cmd_and_opt_values {
   oEnableCRLChecks,
 
   oIncludeCerts,
-
-
-
-
+  oPolicyFile,
+  oDisablePolicyChecks,
+  oEnablePolicyChecks,
 
 
 
@@ -242,6 +241,12 @@ static ARGPARSE_OPTS opts[] = {
     { oIncludeCerts, "include-certs", 1,
                                  N_("|N|number of certificates to include") },
 
+    { oPolicyFile, "policy-file", 2,
+                    N_("|FILE|take policy information from FILE") },
+
+    { oDisablePolicyChecks, "disable-policy-checks", 0,
+                           N_("do not check certificate policies")},
+    { oEnablePolicyChecks, "enable-policy-checks", 0, "@"},
 
 #if 0
     { oDefRecipient, "default-recipient" ,2,
@@ -654,6 +659,8 @@ main ( int argc, char **argv)
   /* set the default option file */
   if (default_config )
     configname = make_filename (opt.homedir, "gpgsm.conf", NULL);
+  /* cet the default policy file */
+  opt.policy_file = make_filename (opt.homedir, "policies.txt", NULL);
   
   argc        = orig_argc;
   argv        = orig_argv;
@@ -759,6 +766,22 @@ main ( int argc, char **argv)
 
         case oIncludeCerts: ctrl.include_certs = pargs.r.ret_int; break;
 
+        case oPolicyFile:
+          xfree (opt.policy_file);
+          if (*pargs.r.ret_str)
+            opt.policy_file = xstrdup (pargs.r.ret_str);
+          else
+            opt.policy_file = NULL;
+          break;
+
+        case oDisablePolicyChecks:
+          opt.no_policy_check = 1;
+          break;
+        case oEnablePolicyChecks:
+          opt.no_policy_check = 0;
+          break;
+
+
         case oOutput: opt.outfile = pargs.r.ret_str; break;
 
         
index fdb6844..ab2d366 100644 (file)
@@ -66,7 +66,10 @@ struct {
 
   int ignore_time_conflict; /* Ignore certain time conflicts */
 
-  int no_crl_check;       /* Don't do a CRL check */
+  int no_crl_check;         /* Don't do a CRL check */
+
+  char *policy_file;        /* full pathname of policy file */
+  int no_policy_check;      /* ignore certificate policies */
 
 } opt;
 
@@ -208,6 +211,7 @@ int gpgsm_agent_pkdecrypt (const char *keygrip,
 int gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey);
 int gpgsm_agent_istrusted (KsbaCert cert);
 int gpgsm_agent_havekey (const char *hexkeygrip);
+int gpgsm_agent_marktrusted (KsbaCert cert);
 
 /*-- call-dirmngr.c --*/
 int gpgsm_dirmngr_isvalid (KsbaCert cert);