* sign.c (hash_and_copy_data): New.
authorWerner Koch <wk@gnupg.org>
Wed, 12 Jun 2002 09:54:57 +0000 (09:54 +0000)
committerWerner Koch <wk@gnupg.org>
Wed, 12 Jun 2002 09:54:57 +0000 (09:54 +0000)
(gpgsm_sign): Implemented normal (non-detached) signatures.
* gpgsm.c (main): Ditto.

* certpath.c (gpgsm_validate_path): Special error handling for
no policy match.

* configure.ac (NEED_LIBKSBA_VERSION): We need 0.4.3 now.

sm/ChangeLog
sm/certchain.c
sm/certpath.c
sm/gpgsm.c
sm/server.c
sm/sign.c
sm/verify.c

index d5ae4f6..8e217ee 100644 (file)
@@ -1,3 +1,24 @@
+2002-06-12  Werner Koch  <wk@gnupg.org>
+
+       * sign.c (hash_and_copy_data): New.
+       (gpgsm_sign): Implemented normal (non-detached) signatures.
+       * gpgsm.c (main): Ditto.
+
+       * certpath.c (gpgsm_validate_path): Special error handling for
+       no policy match.
+
+2002-06-10  Werner Koch  <wk@gnupg.org>
+
+       * server.c (get_status_string): Add STATUS_ERROR.
+
+       * certpath.c (gpgsm_validate_path): Tweaked the error checking to 
+       return error codes in a more sensitive way.
+       * verify.c (gpgsm_verify): Send status TRUST_NEVER also for a bad
+       CA certificate and when the certificate has been revoked.  Issue
+       TRUST_FULLY even when the cert has expired.  Append an error token
+       to these status lines.  Issue the new generic error status when a
+       cert was not found and when leaving the function.
+
 2002-06-04  Werner Koch  <wk@gnupg.org>
 
        * gpgsm.c (main): New command --list-sigs
index 28c0be5..0b2d8b4 100644 (file)
@@ -317,6 +317,11 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
   KsbaCert subject_cert = NULL, issuer_cert = NULL;
   time_t current_time = gnupg_get_time ();
   time_t exptime = 0;
+  int any_expired = 0;
+  int any_revoked = 0;
+  int any_no_crl = 0;
+  int any_crl_too_old = 0;
+  int any_no_policy_match = 0;
 
   if (r_exptime)
     *r_exptime = 0;
@@ -376,7 +381,7 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
 
         if (not_before && current_time < not_before)
           {
-            log_error ("certificate to young; valid from ");
+            log_error ("certificate too young; valid from ");
             gpgsm_dump_time (not_before);
             log_printf ("\n");
             rc = GNUPG_Certificate_Too_Young;
@@ -387,8 +392,7 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
             log_error ("certificate has expired at ");
             gpgsm_dump_time (not_after);
             log_printf ("\n");
-            rc = GNUPG_Certificate_Expired;
-            goto leave;
+            any_expired = 1;
           }            
       }
 
@@ -399,7 +403,12 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
       if (!opt.no_policy_check)
         {
           rc = check_cert_policy (subject_cert);
-          if (rc)
+          if (rc == GNUPG_No_Policy_Match)
+            {
+              any_no_policy_match = 1;
+              rc = 1;
+            }
+          else if (rc)
             goto leave;
         }
 
@@ -412,21 +421,24 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
                 {
                 case GNUPG_Certificate_Revoked:
                   log_error (_("the certificate has been revoked\n"));
+                  any_revoked = 1;
                   break;
                 case GNUPG_No_CRL_Known:
                   log_error (_("no CRL found for certificate\n"));
+                  any_no_crl = 1;
                   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"));
+                  any_crl_too_old = 1;
                   break;
                 default:
                   log_error (_("checking the CRL failed: %s\n"),
                              gnupg_strerror (rc));
-                  break;
+                  goto leave;
                 }
-              goto leave;
+              rc = 0;
             }
         }
 
@@ -551,6 +563,21 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
     log_info ("policies not checked due to --disable-policy-checks option\n");
   if (opt.no_crl_check)
     log_info ("CRLs not checked due to --disable-crl-checks option\n");
+
+  if (!rc)
+    { /* If we encountered an error somewhere during the checks, set
+         the error code to the most critical one */
+      if (any_revoked)
+        rc = GNUPG_Certificate_Revoked;
+      else if (any_no_crl)
+        rc = GNUPG_No_CRL_Known;
+      else if (any_crl_too_old)
+        rc = GNUPG_CRL_Too_Old;
+      else if (any_no_policy_match)
+        rc = GNUPG_No_Policy_Match;
+      else if (any_expired)
+        rc = GNUPG_Certificate_Expired;
+    }
   
  leave:
   if (r_exptime)
index 28c0be5..0b2d8b4 100644 (file)
@@ -317,6 +317,11 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
   KsbaCert subject_cert = NULL, issuer_cert = NULL;
   time_t current_time = gnupg_get_time ();
   time_t exptime = 0;
+  int any_expired = 0;
+  int any_revoked = 0;
+  int any_no_crl = 0;
+  int any_crl_too_old = 0;
+  int any_no_policy_match = 0;
 
   if (r_exptime)
     *r_exptime = 0;
@@ -376,7 +381,7 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
 
         if (not_before && current_time < not_before)
           {
-            log_error ("certificate to young; valid from ");
+            log_error ("certificate too young; valid from ");
             gpgsm_dump_time (not_before);
             log_printf ("\n");
             rc = GNUPG_Certificate_Too_Young;
@@ -387,8 +392,7 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
             log_error ("certificate has expired at ");
             gpgsm_dump_time (not_after);
             log_printf ("\n");
-            rc = GNUPG_Certificate_Expired;
-            goto leave;
+            any_expired = 1;
           }            
       }
 
@@ -399,7 +403,12 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
       if (!opt.no_policy_check)
         {
           rc = check_cert_policy (subject_cert);
-          if (rc)
+          if (rc == GNUPG_No_Policy_Match)
+            {
+              any_no_policy_match = 1;
+              rc = 1;
+            }
+          else if (rc)
             goto leave;
         }
 
@@ -412,21 +421,24 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
                 {
                 case GNUPG_Certificate_Revoked:
                   log_error (_("the certificate has been revoked\n"));
+                  any_revoked = 1;
                   break;
                 case GNUPG_No_CRL_Known:
                   log_error (_("no CRL found for certificate\n"));
+                  any_no_crl = 1;
                   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"));
+                  any_crl_too_old = 1;
                   break;
                 default:
                   log_error (_("checking the CRL failed: %s\n"),
                              gnupg_strerror (rc));
-                  break;
+                  goto leave;
                 }
-              goto leave;
+              rc = 0;
             }
         }
 
@@ -551,6 +563,21 @@ gpgsm_validate_path (KsbaCert cert, time_t *r_exptime)
     log_info ("policies not checked due to --disable-policy-checks option\n");
   if (opt.no_crl_check)
     log_info ("CRLs not checked due to --disable-crl-checks option\n");
+
+  if (!rc)
+    { /* If we encountered an error somewhere during the checks, set
+         the error code to the most critical one */
+      if (any_revoked)
+        rc = GNUPG_Certificate_Revoked;
+      else if (any_no_crl)
+        rc = GNUPG_No_CRL_Known;
+      else if (any_crl_too_old)
+        rc = GNUPG_CRL_Too_Old;
+      else if (any_no_policy_match)
+        rc = GNUPG_No_Policy_Match;
+      else if (any_expired)
+        rc = GNUPG_Certificate_Expired;
+    }
   
  leave:
   if (r_exptime)
index 3aeddd8..f01ffc7 100644 (file)
@@ -1080,13 +1080,14 @@ main ( int argc, char **argv)
       break;
 
     case aSign: /* sign the given file */
-      /* FIXME: we can only do detached sigs for now and we don't
-         handle --output yet. We should also allow to concatenate
-         multiple files for signing because that is what gpg does.*/
+      /* FIXME: W we don't handle --output yet. We should also allow
+         to concatenate multiple files for signing because that is
+         what gpg does.*/
       if (!argc)
-        gpgsm_sign (&ctrl, 0, 1, stdout); /* create from stdin */
+        gpgsm_sign (&ctrl, 0, detached_sig, stdout); /* create from stdin */
       else if (argc == 1)
-        gpgsm_sign (&ctrl, open_read (*argv), 1, stdout); /* from file */
+        gpgsm_sign (&ctrl, open_read (*argv),
+                    detached_sig, stdout); /* from file */
       else
         wrong_args (_("--sign [datafile]"));
       break;
index 763084c..69abe7a 100644 (file)
@@ -789,6 +789,7 @@ get_status_string ( int no )
     case STATUS_EXPSIG         : s = "EXPSIG"; break;
     case STATUS_EXPKEYSIG      : s = "EXPKEYSIG"; break;
     case STATUS_TRUNCATED      : s = "TRUNCATED"; break;
+    case STATUS_ERROR          : s = "ERROR"; break;
     default: s = "?"; break;
     }
   return s;
index 46fa170..4cce9f9 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -60,6 +60,67 @@ hash_data (int fd, GCRY_MD_HD md)
   fclose (fp);
 }
 
+static int
+hash_and_copy_data (int fd, GCRY_MD_HD md, KsbaWriter writer)
+{
+  KsbaError err;
+  FILE *fp;
+  char buffer[4096];
+  int nread;
+  int rc = 0;
+  int any = 0;
+
+  fp = fdopen ( dup (fd), "rb");
+  if (!fp)
+    {
+      log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
+      return GNUPG_File_Open_Error;
+    }
+
+  do 
+    {
+      nread = fread (buffer, 1, DIM(buffer), fp);
+      if (nread)
+        {
+          any = 1;
+          gcry_md_write (md, buffer, nread);
+          err = ksba_writer_write_octet_string (writer, buffer, nread, 0);
+          if (err)
+            {
+              log_error ("write failed: %s\n", ksba_strerror (err));
+              rc = map_ksba_err (err);
+            }
+        }
+    }
+  while (nread && !rc);
+  if (ferror (fp))
+    {
+      log_error ("read error on fd %d: %s\n", fd, strerror (errno));
+      rc = GNUPG_Read_Error;
+    }
+  fclose (fp);
+  if (!any)
+    {
+      /* We can't allow to sign an empty message becuase it does not
+         make mnuch sense and more seriously, ksba-cms_build has
+         already written the tag for data and now expects an octet
+         string but an octet string of zeize 0 is illegal. */
+      log_error ("cannot sign an empty message\n");
+      rc = GNUPG_No_Data;
+    }
+  if (!rc)
+    {
+      err = ksba_writer_write_octet_string (writer, NULL, 0, 1);
+      if (err)
+        {
+          log_error ("write failed: %s\n", ksba_strerror (err));
+          rc = map_ksba_err (err);
+        }
+    }
+
+  return rc;
+}
+
 
 /* Get the default certificate which is defined as the first one our
    keyDB retruns and has a secret key available */
@@ -227,10 +288,10 @@ add_certificate_list (CTRL ctrl, KsbaCMS cms, KsbaCert cert)
 \f
 /* Perform a sign operation.  
 
-   Sign the data received on DATA-FD in embedded mode or in deatched
-   mode when DETACHED is true.  Write the signature to OUT_FP The key
-   used to sign is the default - we will extend the fucntion to take a
-   list of fingerprints in the future. */
+   Sign the data received on DATA-FD in embedded mode or in detached
+   mode when DETACHED is true.  Write the signature to OUT_FP.  The
+   key used to sign is the default one - we will extend the function
+   to take a list of fingerprints in the future. */
 int
 gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp)
 {
@@ -248,13 +309,6 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp)
   int algo;
   time_t signed_at;
 
-  if (!detached)
-    {
-       rc = seterr (Not_Implemented);
-       goto leave;
-    }
-
-
   kh = keydb_new (0);
   if (!kh)
     {
@@ -415,7 +469,35 @@ gpgsm_sign (CTRL ctrl, int data_fd, int detached, FILE *out_fp)
 
       if (stopreason == KSBA_SR_BEGIN_DATA)
         { /* hash the data and store the message digest */
+          unsigned char *digest;
+          size_t digest_len;
+
           assert (!detached);
+          /* Fixme do this for all signers and get the algo to use from
+             the signer's certificate - does not make mich sense, bu we
+             should do this consistent as we have already done it above.
+             Code is mostly duplicated above. */
+
+          algo = GCRY_MD_SHA1; 
+          rc = hash_and_copy_data (data_fd, data_md, writer);
+          if (rc)
+            goto leave;
+          digest = gcry_md_read (data_md, algo);
+          digest_len = gcry_md_get_algo_dlen (algo);
+          if ( !digest || !digest_len)
+            {
+              log_error ("problem getting the hash of the data\n");
+              rc = GNUPG_Bug;
+              goto leave;
+            }
+          err = ksba_cms_set_message_digest (cms, signer, digest, digest_len);
+          if (err)
+            {
+              log_error ("ksba_cms_set_message_digest failed: %s\n",
+                         ksba_strerror (err));
+              rc = map_ksba_err (err);
+              goto leave;
+            }
         }
       else if (stopreason == KSBA_SR_NEED_SIG)
         { /* calculate the signature for all signers */
index 5549470..394939e 100644 (file)
@@ -317,8 +317,18 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
       rc = keydb_search_issuer_sn (kh, issuer, serial);
       if (rc)
         {
-          log_error ("failed to find the certificate: %s\n",
-                     gnupg_strerror(rc));
+          if (rc == -1)
+            {
+              log_error ("certificate not found\n");
+              rc = GNUPG_No_Public_Key;
+            }
+          else
+            log_error ("failed to find the certificate: %s\n",
+                       gnupg_strerror(rc));
+          gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
+                         gnupg_error_token (rc), NULL);
+          /* fixme: we might want to append the issuer and serial
+             using our standard notation */
           goto next_signer;
         }
 
@@ -384,7 +394,10 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
         log_debug ("signature okay - checking certs\n");
       rc = gpgsm_validate_path (cert, &keyexptime);
       if (rc == GNUPG_Certificate_Expired)
-        gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
+        {
+          gpgsm_status (ctrl, STATUS_EXPKEYSIG, NULL);
+          rc = 0;
+        }
       else
         gpgsm_status (ctrl, STATUS_GOODSIG, NULL);
       
@@ -406,10 +419,12 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
         {
           log_error ("invalid certification path: %s\n", gnupg_strerror (rc));
           if (rc == GNUPG_Bad_Certificate_Path
-              || rc == GNUPG_Bad_Certificate)
-            gpgsm_status (ctrl, STATUS_TRUST_NEVER, NULL);
+              || rc == GNUPG_Bad_Certificate
+              || rc == GNUPG_Bad_CA_Certificate
+              || rc == GNUPG_Certificate_Revoked)
+            gpgsm_status (ctrl, STATUS_TRUST_NEVER, gnupg_error_token (rc));
           else
-            gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, NULL);
+            gpgsm_status (ctrl, STATUS_TRUST_UNDEFINED, gnupg_error_token (rc));
           goto next_signer;
         }
       log_info ("signature is good\n");
@@ -442,6 +457,10 @@ gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp)
   gcry_md_close (data_md);
   if (fp)
     fclose (fp);
+
+  if (rc)
+    gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
+                   gnupg_error_token (rc), NULL);
   return rc;
 }