Fixed problem with unplugging card readers.
[gnupg.git] / sm / sign.c
index c87382e..250363b 100644 (file)
--- a/sm/sign.c
+++ b/sm/sign.c
@@ -1,5 +1,6 @@
 /* sign.c - Sign a message
- *     Copyright (C) 2001, 2002, 2003, 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2003, 2008,
+ *               2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
 #include "keydb.h"
 #include "i18n.h"
 
-/* Remove this if libgcrypt 1.4 is required. */
-#define MY_GCRY_MD_SHA224  11
 
-
-static void
+/* Hash the data and return if something was hashed.  Return -1 on error.  */
+static int
 hash_data (int fd, gcry_md_hd_t md)
 {
-  FILE *fp;
+  estream_t fp;
   char buffer[4096];
   int nread;
+  int rc = 0;
 
-  fp = fdopen ( dup (fd), "rb");
+  fp = es_fdopen_nc (fd, "rb");
   if (!fp)
     {
       log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
-      return;
+      return -1;
     }
 
   do 
     {
-      nread = fread (buffer, 1, DIM(buffer), fp);
+      nread = es_fread (buffer, 1, DIM(buffer), fp);
       gcry_md_write (md, buffer, nread);
     }
   while (nread);
-  if (ferror (fp))
+  if (es_ferror (fp))
+    {
       log_error ("read error on fd %d: %s\n", fd, strerror (errno));
-  fclose (fp);
+      rc = -1;
+    }
+  es_fclose (fp);
+  return rc;
 }
 
+
 static int
 hash_and_copy_data (int fd, gcry_md_hd_t md, ksba_writer_t writer)
 {
   gpg_error_t err;
-  FILE *fp;
+  estream_t fp;
   char buffer[4096];
   int nread;
   int rc = 0;
   int any = 0;
 
-  fp = fdopen ( dup (fd), "rb");
+  fp = es_fdopen_nc (fd, "rb");
   if (!fp)
     {
-      gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
+      gpg_error_t tmperr = gpg_error_from_syserror ();
       log_error ("fdopen(%d) failed: %s\n", fd, strerror (errno));
       return tmperr;
     }
 
   do 
     {
-      nread = fread (buffer, 1, DIM(buffer), fp);
+      nread = es_fread (buffer, 1, DIM(buffer), fp);
       if (nread)
         {
           any = 1;
@@ -96,18 +101,18 @@ hash_and_copy_data (int fd, gcry_md_hd_t md, ksba_writer_t writer)
         }
     }
   while (nread && !rc);
-  if (ferror (fp))
+  if (es_ferror (fp))
     {
-      rc = gpg_error (gpg_err_code_from_errno (errno));
+      rc = gpg_error_from_syserror ();
       log_error ("read error on fd %d: %s\n", fd, strerror (errno));
     }
-  fclose (fp);
+  es_fclose (fp);
   if (!any)
     {
       /* We can't allow to sign an empty message because it does not
-         make much sense and more seriously, ksba-cms_build has
+         make much 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. */
+         string and an octet string of size 0 is illegal.  */
       log_error ("cannot sign an empty message\n");
       rc = gpg_error (GPG_ERR_NO_DATA);
     }
@@ -206,7 +211,7 @@ get_default_signer (ctrl_t ctrl)
       return cert;
     }
 
-  rc = keydb_classify_name (opt.local_user, &desc);
+  rc = classify_user_id (opt.local_user, &desc);
   if (rc)
     {
       log_error ("failed to find default signer: %s\n", gpg_strerror (rc));
@@ -307,7 +312,7 @@ add_certificate_list (ctrl_t ctrl, ksba_cms_t cms, ksba_cert_t cert)
    be used if the value of this argument is NULL. */
 int
 gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
-            int data_fd, int detached, FILE *out_fp)
+            int data_fd, int detached, estream_t out_fp)
 {
   int i, rc;
   gpg_error_t err;
@@ -324,6 +329,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
   certlist_t cl;
   int release_signerlist = 0;
 
+  audit_set_type (ctrl->audit, AUDIT_TYPE_SIGN);
+
   kh = keydb_new (0);
   if (!kh)
     {
@@ -333,7 +340,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
     }
 
   ctrl->pem_name = "SIGNED MESSAGE";
-  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
+  rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
   if (rc)
     {
       log_error ("can't create writer: %s\n", gpg_strerror (rc));
@@ -375,6 +382,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
       if (!cert)
         {
           log_error ("no default signer found\n");
+          gpgsm_status2 (ctrl, STATUS_INV_SGNR, 
+                         get_inv_recpsgnr_code (GPG_ERR_NO_SECKEY), NULL);
           rc = gpg_error (GPG_ERR_GENERAL);
           goto leave;
         }
@@ -385,7 +394,15 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
       if (!rc)
         rc = gpgsm_validate_chain (ctrl, cert, "", NULL, 0, NULL, 0, NULL);
       if (rc)
-        goto leave;
+        {
+          char *tmpfpr;
+
+          tmpfpr = gpgsm_get_fingerprint_hexstring (cert, 0);
+          gpgsm_status2 (ctrl, STATUS_INV_SGNR, 
+                         get_inv_recpsgnr_code (rc), tmpfpr, NULL);
+          xfree (tmpfpr);
+          goto leave;
+        }
 
       /* That one is fine - create signerlist. */
       signerlist = xtrycalloc (1, sizeof *signerlist);
@@ -402,16 +419,27 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
   /* Figure out the hash algorithm to use. We do not want to use the
      one for the certificate but if possible an OID for the plain
      algorithm.  */
+  if (opt.forced_digest_algo && opt.verbose)
+    log_info ("user requested hash algorithm %d\n", opt.forced_digest_algo);
   for (i=0, cl=signerlist; cl; cl = cl->next, i++)
     {
-      const char *oid = ksba_cert_get_digest_algo (cl->cert);
+      const char *oid;
 
-      cl->hash_algo = oid ? gcry_md_map_name (oid) : 0;
+      if (opt.forced_digest_algo)
+        {
+          oid = NULL;
+          cl->hash_algo = opt.forced_digest_algo;
+        }
+      else
+        {
+          oid = ksba_cert_get_digest_algo (cl->cert);
+          cl->hash_algo = oid ? gcry_md_map_name (oid) : 0;
+        }
       switch (cl->hash_algo)
         {
         case GCRY_MD_SHA1:   oid = "1.3.14.3.2.26"; break;
         case GCRY_MD_RMD160: oid = "1.3.36.3.2.1"; break;
-        case MY_GCRY_MD_SHA224: oid = "2.16.840.1.101.3.4.2.4"; break;
+        case GCRY_MD_SHA224: oid = "2.16.840.1.101.3.4.2.4"; break;
         case GCRY_MD_SHA256: oid = "2.16.840.1.101.3.4.2.1"; break;
         case GCRY_MD_SHA384: oid = "2.16.840.1.101.3.4.2.2"; break;
         case GCRY_MD_SHA512: oid = "2.16.840.1.101.3.4.2.3"; break;
@@ -430,6 +458,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
         }
       cl->hash_algo_oid = oid;
     }
+
   if (opt.verbose)
     {
       for (i=0, cl=signerlist; cl; cl = cl->next, i++)
@@ -474,31 +503,34 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
   /* Check whether one of the certificates is qualified.  Note that we
      already validated the certificate and thus the user data stored
      flag must be available. */
-  for (cl=signerlist; cl; cl = cl->next)
+  if (!opt.no_chain_validation)
     {
-      size_t buflen;
-      char buffer[1];
-      
-      err = ksba_cert_get_user_data (cl->cert, "is_qualified", 
-                                     &buffer, sizeof (buffer), &buflen);
-      if (err || !buflen)
-        {
-          log_error (_("checking for qualified certificate failed: %s\n"),
-                     gpg_strerror (err)); 
-          rc = err;
-          goto leave;
-        }
-      if (*buffer)
-        err = gpgsm_qualified_consent (ctrl, cl->cert);
-      else
-        err = gpgsm_not_qualified_warning (ctrl, cl->cert);
-      if (err)
+      for (cl=signerlist; cl; cl = cl->next)
         {
-          rc = err;
-          goto leave;
+          size_t buflen;
+          char buffer[1];
+          
+          err = ksba_cert_get_user_data (cl->cert, "is_qualified", 
+                                         &buffer, sizeof (buffer), &buflen);
+          if (err || !buflen)
+            {
+              log_error (_("checking for qualified certificate failed: %s\n"),
+                         gpg_strerror (err)); 
+              rc = err;
+              goto leave;
+            }
+          if (*buffer)
+            err = gpgsm_qualified_consent (ctrl, cl->cert);
+          else
+            err = gpgsm_not_qualified_warning (ctrl, cl->cert);
+          if (err)
+            {
+              rc = err;
+              goto leave;
+            }
         }
     }
-  
+
   /* Prepare hashing (actually we are figuring out what we have set
      above). */
   rc = gcry_md_open (&data_md, 0, 0);
@@ -520,8 +552,11 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
           goto leave;
         }
       gcry_md_enable (data_md, algo);
+      audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
     }
 
+  audit_log (ctrl->audit, AUDIT_SETUP_READY);
+
   if (detached)
     { /* We hash the data right now so that we can store the message
          digest.  ksba_cms_build() takes this as an flag that detached
@@ -529,7 +564,8 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
       unsigned char *digest;
       size_t digest_len;
 
-      hash_data (data_fd, data_md);
+      if (!hash_data (data_fd, data_md))
+        audit_log (ctrl->audit, AUDIT_GOT_DATA);
       for (cl=signerlist,signer=0; cl; cl = cl->next, signer++)
         {
           digest = gcry_md_read (data_md, cl->hash_algo);
@@ -604,6 +640,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
           rc = hash_and_copy_data (data_fd, data_md, writer);
           if (rc)
             goto leave;
+          audit_log (ctrl->audit, AUDIT_GOT_DATA);
           for (cl=signerlist,signer=0; cl; cl = cl->next, signer++)
             {
               digest = gcry_md_read (data_md, cl->hash_algo);
@@ -644,13 +681,18 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
               unsigned char *sigval = NULL;
               char *buf, *fpr;
 
+              audit_log_i (ctrl->audit, AUDIT_NEW_SIG, signer);
               if (signer)
                 gcry_md_reset (md);
               {
                 certlist_t cl_tmp;
 
                 for (cl_tmp=signerlist; cl_tmp; cl_tmp = cl_tmp->next)
-                  gcry_md_enable (md, cl_tmp->hash_algo);
+                  {
+                    gcry_md_enable (md, cl_tmp->hash_algo);
+                    audit_log_i (ctrl->audit, AUDIT_ATTR_HASH_ALGO, 
+                                 cl_tmp->hash_algo);
+                  }
               }
 
               rc = ksba_cms_hash_signed_attrs (cms, signer);
@@ -666,6 +708,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
                                                md, cl->hash_algo, &sigval);
               if (rc)
                 {
+                  audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, rc);
                   gcry_md_close (md);
                   goto leave;
                 }
@@ -674,6 +717,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
               xfree (sigval);
               if (err)
                 {
+                  audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, err);
                   log_error ("failed to store the signature: %s\n",
                              gpg_strerror (err));
                   rc = err;
@@ -689,28 +733,29 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
                   gcry_md_close (md);
                   goto leave;
                 }
+              rc = 0;
               {
                 int pkalgo = gpgsm_get_key_algo_info (cl->cert, NULL);
-                rc = asprintf (&buf, "%c %d %d 00 %s %s",
-                               detached? 'D':'S',
-                               pkalgo, 
-                               cl->hash_algo, 
-                               signed_at,
-                               fpr);
+                buf = xtryasprintf ("%c %d %d 00 %s %s",
+                                    detached? 'D':'S',
+                                    pkalgo, 
+                                    cl->hash_algo, 
+                                    signed_at,
+                                    fpr);
+                if (!buf)
+                  rc = gpg_error_from_syserror ();
               }
               xfree (fpr);
-              if (rc < 0)
+              if (rc)
                 {
-                  rc = gpg_error (GPG_ERR_ENOMEM);
                   gcry_md_close (md);
                   goto leave;
                 }
-              rc = 0;
               gpgsm_status (ctrl, STATUS_SIG_CREATED, buf);
-              free (buf); /* yes, we must use the regular free() here */
+              xfree (buf);
+              audit_log_cert (ctrl->audit, AUDIT_SIGNED_BY, cl->cert, 0);
             }
           gcry_md_close (md);
-
         }
     }
   while (stopreason != KSBA_SR_READY);   
@@ -722,6 +767,7 @@ gpgsm_sign (ctrl_t ctrl, certlist_t signerlist,
       goto leave;
     }
 
+  audit_log (ctrl->audit, AUDIT_SIGNING_DONE);
   log_info ("signature created\n");