gpgscm: Reduce opcode dispatch overhead.
[gnupg.git] / sm / decrypt.c
index 3068262..3cee54b 100644 (file)
@@ -1,11 +1,11 @@
 /* decrypt.c - Decrypt a message
 /* decrypt.c - Decrypt a message
- *     Copyright (C) 2001 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2003, 2010 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,8 +14,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
  */
 
 #include <config.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h> 
+#include <unistd.h>
 #include <time.h>
 #include <assert.h>
 
 #include <time.h>
 #include <assert.h>
 
+#include "gpgsm.h"
 #include <gcrypt.h>
 #include <ksba.h>
 
 #include <gcrypt.h>
 #include <ksba.h>
 
-#include "gpgsm.h"
 #include "keydb.h"
 #include "i18n.h"
 
 #include "keydb.h"
 #include "i18n.h"
 
-struct decrypt_filter_parm_s {
+struct decrypt_filter_parm_s
+{
   int algo;
   int mode;
   int blklen;
   int algo;
   int mode;
   int blklen;
-  GCRY_CIPHER_HD hd;
+  gcry_cipher_hd_t hd;
   char iv[16];
   size_t ivlen;
   int any_data;  /* dod we push anything through the filter at all? */
   char iv[16];
   size_t ivlen;
   int any_data;  /* dod we push anything through the filter at all? */
@@ -51,21 +51,22 @@ struct decrypt_filter_parm_s {
 
 
 
 
 
 
-/* decrypt the session key and fill in the parm structure.  The
+/* Decrypt the session key and fill in the parm structure.  The
    algo and the IV is expected to be already in PARM. */
    algo and the IV is expected to be already in PARM. */
-static int 
-prepare_decryption (const char *hexkeygrip, KsbaConstSexp enc_val,
+static int
+prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+                    ksba_const_sexp_t enc_val,
                     struct decrypt_filter_parm_s *parm)
 {
   char *seskey = NULL;
   size_t n, seskeylen;
   int rc;
 
                     struct decrypt_filter_parm_s *parm)
 {
   char *seskey = NULL;
   size_t n, seskeylen;
   int rc;
 
-  rc = gpgsm_agent_pkdecrypt (hexkeygrip, enc_val,
+  rc = gpgsm_agent_pkdecrypt (ctrl, hexkeygrip, desc, enc_val,
                               &seskey, &seskeylen);
   if (rc)
     {
                               &seskey, &seskeylen);
   if (rc)
     {
-      log_error ("error decrypting session key: %s\n", gnupg_strerror (rc));
+      log_error ("error decrypting session key: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
       goto leave;
     }
 
@@ -73,41 +74,55 @@ prepare_decryption (const char *hexkeygrip, KsbaConstSexp enc_val,
     log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
 
   n=0;
     log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
 
   n=0;
-  if (n + 7 > seskeylen )
+  if (seskeylen == 24)
     {
     {
-      rc = seterr (Invalid_Session_Key);
-      goto leave; 
+      /* Smells like a 3-des key.  This might happen because a SC has
+         already done the unpacking. */
     }
     }
+  else
+    {
+      if (n + 7 > seskeylen )
+        {
+          rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
+          goto leave;
+        }
 
 
-  if (seskey[n] != 2 )  /* wrong block type version */
-    { 
-      rc = seterr (Invalid_Session_Key);
-      goto leave; 
-    }
+      /* FIXME: Actually the leading zero is required but due to the way
+         we encode the output in libgcrypt as an MPI we are not able to
+         encode that leading zero.  However, when using a Smartcard we are
+         doing it the right way and therefore we have to skip the zero.  This
+         should be fixed in gpg-agent of course. */
+      if (!seskey[n])
+        n++;
 
 
-  for (n++; n < seskeylen && seskey[n]; n++) /* skip the random bytes */
-    ;
-  n++; /* and the zero byte */
-  if (n >= seskeylen )
-    { 
-      rc = seterr (Invalid_Session_Key);
-      goto leave; 
+      if (seskey[n] != 2 )  /* Wrong block type version. */
+        {
+          rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
+          goto leave;
+        }
+
+      for (n++; n < seskeylen && seskey[n]; n++) /* Skip the random bytes. */
+        ;
+      n++; /* and the zero byte */
+      if (n >= seskeylen )
+        {
+          rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
+          goto leave;
+        }
     }
     }
-  
+
   if (DBG_CRYPTO)
     log_printhex ("session key:", seskey+n, seskeylen-n);
 
   if (DBG_CRYPTO)
     log_printhex ("session key:", seskey+n, seskeylen-n);
 
-  parm->hd = gcry_cipher_open (parm->algo, parm->mode, 0);
-  if (!parm->hd)
+  rc = gcry_cipher_open (&parm->hd, parm->algo, parm->mode, 0);
+  if (rc)
     {
     {
-      rc = gcry_errno ();
-      log_error ("error creating decryptor: %s\n", gcry_strerror (rc));
-      rc = map_gcry_err (rc);
+      log_error ("error creating decryptor: %s\n", gpg_strerror (rc));
       goto leave;
     }
       goto leave;
     }
-                        
+
   rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
   rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
-  if (rc == GCRYERR_WEAK_KEY)
+  if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
     {
       log_info (_("WARNING: message was encrypted with "
                   "a weak key in the symmetric cipher.\n"));
     {
       log_info (_("WARNING: message was encrypted with "
                   "a weak key in the symmetric cipher.\n"));
@@ -115,8 +130,7 @@ prepare_decryption (const char *hexkeygrip, KsbaConstSexp enc_val,
     }
   if (rc)
     {
     }
   if (rc)
     {
-      log_error("key setup failed: %s\n", gcry_strerror(rc) );
-      rc = map_gcry_err (rc);
+      log_error("key setup failed: %s\n", gpg_strerror(rc) );
       goto leave;
     }
 
       goto leave;
     }
 
@@ -133,9 +147,9 @@ prepare_decryption (const char *hexkeygrip, KsbaConstSexp enc_val,
    decrypt it and store it inoutbuf which has a maximum size of
    maxoutlen.  The valid bytes in outbuf should be return in outlen.
    Due to different buffer sizes or different length of input and
    decrypt it and store it inoutbuf which has a maximum size of
    maxoutlen.  The valid bytes in outbuf should be return in outlen.
    Due to different buffer sizes or different length of input and
-   output, it may happen that fewer bytes are process or fewer bytes
+   output, it may happen that fewer bytes are processed or fewer bytes
    are written. */
    are written. */
-static KsbaError  
+static gpg_error_t
 decrypt_filter (void *arg,
                 const void *inbuf, size_t inlen, size_t *inused,
                 void *outbuf, size_t maxoutlen, size_t *outlen)
 decrypt_filter (void *arg,
                 const void *inbuf, size_t inlen, size_t *inused,
                 void *outbuf, size_t maxoutlen, size_t *outlen)
@@ -146,11 +160,11 @@ decrypt_filter (void *arg,
 
   /* fixme: Should we issue an error when we have not seen one full block? */
   if (!inlen)
 
   /* fixme: Should we issue an error when we have not seen one full block? */
   if (!inlen)
-    return KSBA_Bug;
+    return gpg_error (GPG_ERR_BUG);
 
   if (maxoutlen < 2*parm->blklen)
 
   if (maxoutlen < 2*parm->blklen)
-    return KSBA_Bug;
-  /* make some space becuase we will later need an extra block at the end */
+    return gpg_error (GPG_ERR_BUG);
+  /* Make some space because we will later need an extra block at the end.  */
   maxoutlen -= blklen;
 
   if (parm->helpblocklen)
   maxoutlen -= blklen;
 
   if (parm->helpblocklen)
@@ -161,7 +175,7 @@ decrypt_filter (void *arg,
         parm->helpblock[i] = ((const char*)inbuf)[j];
       inlen -= j;
       if (blklen > maxoutlen)
         parm->helpblock[i] = ((const char*)inbuf)[j];
       inlen -= j;
       if (blklen > maxoutlen)
-        return KSBA_Bug;
+        return gpg_error (GPG_ERR_BUG);
       if (i < blklen)
         {
           parm->helpblocklen = i;
       if (i < blklen)
         {
           parm->helpblocklen = i;
@@ -224,78 +238,75 @@ decrypt_filter (void *arg,
 \f
 /* Perform a decrypt operation.  */
 int
 \f
 /* Perform a decrypt operation.  */
 int
-gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
+gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
 {
   int rc;
 {
   int rc;
-  KsbaError err;
   Base64Context b64reader = NULL;
   Base64Context b64writer = NULL;
   Base64Context b64reader = NULL;
   Base64Context b64writer = NULL;
-  KsbaReader reader;
-  KsbaWriter writer;
-  KsbaCMS cms = NULL;
-  KsbaStopReason stopreason;
+  ksba_reader_t reader;
+  ksba_writer_t writer;
+  ksba_cms_t cms = NULL;
+  ksba_stop_reason_t stopreason;
   KEYDB_HANDLE kh;
   int recp;
   KEYDB_HANDLE kh;
   int recp;
-  FILE *in_fp = NULL;
+  estream_t in_fp = NULL;
   struct decrypt_filter_parm_s dfparm;
 
   memset (&dfparm, 0, sizeof dfparm);
 
   struct decrypt_filter_parm_s dfparm;
 
   memset (&dfparm, 0, sizeof dfparm);
 
+  audit_set_type (ctrl->audit, AUDIT_TYPE_DECRYPT);
+
   kh = keydb_new (0);
   if (!kh)
     {
   kh = keydb_new (0);
   if (!kh)
     {
-      log_error (_("failed to allocated keyDB handle\n"));
-      rc = GNUPG_General_Error;
+      log_error (_("failed to allocate keyDB handle\n"));
+      rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
     }
 
       goto leave;
     }
 
-
-  in_fp = fdopen ( dup (in_fd), "rb");
+  in_fp = es_fdopen_nc (in_fd, "rb");
   if (!in_fp)
     {
   if (!in_fp)
     {
+      rc = gpg_error_from_syserror ();
       log_error ("fdopen() failed: %s\n", strerror (errno));
       log_error ("fdopen() failed: %s\n", strerror (errno));
-      rc = seterr (IO_Error);
       goto leave;
     }
 
       goto leave;
     }
 
-  rc = gpgsm_create_reader (&b64reader, ctrl, in_fp, &reader);
+  rc = gpgsm_create_reader (&b64reader, ctrl, in_fp, 0, &reader);
   if (rc)
     {
   if (rc)
     {
-      log_error ("can't create reader: %s\n", gnupg_strerror (rc));
+      log_error ("can't create reader: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
   if (rc)
     {
       goto leave;
     }
 
   rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
   if (rc)
     {
-      log_error ("can't create writer: %s\n", gnupg_strerror (rc));
+      log_error ("can't create writer: %s\n", gpg_strerror (rc));
       goto leave;
     }
 
       goto leave;
     }
 
-  cms = ksba_cms_new ();
-  if (!cms)
-    {
-      rc = seterr (Out_Of_Core);
-      goto leave;
-    }
+  rc = ksba_cms_new (&cms);
+  if (rc)
+    goto leave;
 
 
-  err = ksba_cms_set_reader_writer (cms, reader, writer);
-  if (err)
+  rc = ksba_cms_set_reader_writer (cms, reader, writer);
+  if (rc)
     {
       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
     {
       log_debug ("ksba_cms_set_reader_writer failed: %s\n",
-                 ksba_strerror (err));
-      rc = map_ksba_err (err);
+                 gpg_strerror (rc));
       goto leave;
     }
 
       goto leave;
     }
 
-  /* parser loop */
-  do 
+  audit_log (ctrl->audit, AUDIT_SETUP_READY);
+
+  /* Parser loop. */
+  do
     {
     {
-      err = ksba_cms_parse (cms, &stopreason);
-      if (err)
+      rc = ksba_cms_parse (cms, &stopreason);
+      if (rc)
         {
         {
-          log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
-          rc = map_ksba_err (err);
+          log_debug ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
           goto leave;
         }
 
           goto leave;
         }
 
@@ -304,21 +315,44 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
         {
           int algo, mode;
           const char *algoid;
         {
           int algo, mode;
           const char *algoid;
-          
+          int any_key = 0;
+
+          audit_log (ctrl->audit, AUDIT_GOT_DATA);
+
           algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
           algo = gcry_cipher_map_name (algoid);
           mode = gcry_cipher_mode_from_oid (algoid);
           if (!algo || !mode)
             {
           algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
           algo = gcry_cipher_map_name (algoid);
           mode = gcry_cipher_mode_from_oid (algoid);
           if (!algo || !mode)
             {
-              log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
-              rc = GNUPG_Unsupported_Algorithm;
+              rc = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
+              log_error ("unsupported algorithm '%s'\n", algoid? algoid:"?");
+              if (algoid && !strcmp (algoid, "1.2.840.113549.3.2"))
+                log_info (_("(this is the RC2 algorithm)\n"));
+              else if (!algoid)
+                log_info (_("(this does not seem to be an encrypted"
+                            " message)\n"));
+              {
+                char numbuf[50];
+                sprintf (numbuf, "%d", rc);
+                gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.algorithm",
+                               numbuf, algoid?algoid:"?", NULL);
+                audit_log_s (ctrl->audit, AUDIT_BAD_DATA_CIPHER_ALGO, algoid);
+              }
+
+              /* If it seems that this is not an encrypted message we
+                 return a more sensible error code. */
+              if (!algoid)
+                rc = gpg_error (GPG_ERR_NO_DATA);
+
               goto leave;
             }
               goto leave;
             }
+
+          audit_log_i (ctrl->audit, AUDIT_DATA_CIPHER_ALGO, algo);
           dfparm.algo = algo;
           dfparm.mode = mode;
           dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
           if (dfparm.blklen > sizeof (dfparm.helpblock))
           dfparm.algo = algo;
           dfparm.mode = mode;
           dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
           if (dfparm.blklen > sizeof (dfparm.helpblock))
-            return GNUPG_Bug;
+            return gpg_error (GPG_ERR_BUG);
 
           rc = ksba_cms_get_content_enc_iv (cms,
                                             dfparm.iv,
 
           rc = ksba_cms_get_content_enc_iv (cms,
                                             dfparm.iv,
@@ -326,48 +360,96 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
                                             &dfparm.ivlen);
           if (rc)
             {
                                             &dfparm.ivlen);
           if (rc)
             {
-              log_error ("error getting IV: %s\n", ksba_strerror (err));
-              rc = map_ksba_err (err);
+              log_error ("error getting IV: %s\n", gpg_strerror (rc));
               goto leave;
             }
               goto leave;
             }
-          
-          for (recp=0; recp < 1; recp++)
+
+          for (recp=0; !any_key; recp++)
             {
               char *issuer;
             {
               char *issuer;
-              KsbaSexp serial;
-              KsbaSexp enc_val;
+              ksba_sexp_t serial;
+              ksba_sexp_t enc_val;
               char *hexkeygrip = NULL;
               char *hexkeygrip = NULL;
+              char *desc = NULL;
+              char kidbuf[16+1];
+
+              *kidbuf = 0;
 
 
-              err = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
-              if (err)
+              rc = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
+              if (rc == -1 && recp)
+                break; /* no more recipients */
+              audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp);
+              if (rc)
                 log_error ("recp %d - error getting info: %s\n",
                 log_error ("recp %d - error getting info: %s\n",
-                           recp, ksba_strerror (err));
+                           recp, gpg_strerror (rc));
               else
                 {
               else
                 {
-                  KsbaCert cert = NULL;
+                  ksba_cert_t cert = NULL;
 
 
-                  log_debug ("recp %d - issuer: `%s'\n",
+                  log_debug ("recp %d - issuer: '%s'\n",
                              recp, issuer? issuer:"[NONE]");
                   log_debug ("recp %d - serial: ", recp);
                   gpgsm_dump_serial (serial);
                   log_printf ("\n");
 
                              recp, issuer? issuer:"[NONE]");
                   log_debug ("recp %d - serial: ", recp);
                   gpgsm_dump_serial (serial);
                   log_printf ("\n");
 
+                  if (ctrl->audit)
+                    {
+                      char *tmpstr = gpgsm_format_sn_issuer (serial, issuer);
+                      audit_log_s (ctrl->audit, AUDIT_RECP_NAME, tmpstr);
+                      xfree (tmpstr);
+                    }
+
                   keydb_search_reset (kh);
                   rc = keydb_search_issuer_sn (kh, issuer, serial);
                   if (rc)
                     {
                   keydb_search_reset (kh);
                   rc = keydb_search_issuer_sn (kh, issuer, serial);
                   if (rc)
                     {
-                      log_debug ("failed to find the certificate: %s\n",
-                                 gnupg_strerror(rc));
+                      log_error ("failed to find the certificate: %s\n",
+                                 gpg_strerror(rc));
                       goto oops;
                     }
 
                   rc = keydb_get_cert (kh, &cert);
                   if (rc)
                     {
                       goto oops;
                     }
 
                   rc = keydb_get_cert (kh, &cert);
                   if (rc)
                     {
-                      log_debug ("failed to get cert: %s\n", gnupg_strerror (rc));
-                      goto oops;                    }
+                      log_error ("failed to get cert: %s\n", gpg_strerror (rc));
+                      goto oops;
+                    }
+
+                  /* Print the ENC_TO status line.  Note that we can
+                     do so only if we have the certificate.  This is
+                     in contrast to gpg where the keyID is commonly
+                     included in the encrypted messages. It is too
+                     cumbersome to retrieve the used algorithm, thus
+                     we don't print it for now.  We also record the
+                     keyid for later use.  */
+                  {
+                    unsigned long kid[2];
+
+                    kid[0] = gpgsm_get_short_fingerprint (cert, kid+1);
+                    snprintf (kidbuf, sizeof kidbuf, "%08lX%08lX",
+                              kid[1], kid[0]);
+                    gpgsm_status2 (ctrl, STATUS_ENC_TO,
+                                   kidbuf, "0", "0", NULL);
+                  }
+
+                  /* Put the certificate into the audit log.  */
+                  audit_log_cert (ctrl->audit, AUDIT_SAVE_CERT, cert, 0);
+
+                  /* Just in case there is a problem with the own
+                     certificate we print this message - should never
+                     happen of course */
+                  rc = gpgsm_cert_use_decrypt_p (cert);
+                  if (rc)
+                    {
+                      char numbuf[50];
+                      sprintf (numbuf, "%d", rc);
+                      gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.keyusage",
+                                     numbuf, NULL);
+                      rc = 0;
+                    }
 
                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
 
                   hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
+                  desc = gpgsm_format_keydesc (cert);
 
                 oops:
                   xfree (issuer);
 
                 oops:
                   xfree (issuer);
@@ -375,25 +457,69 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
                   ksba_cert_release (cert);
                 }
 
                   ksba_cert_release (cert);
                 }
 
-              enc_val = ksba_cms_get_enc_val (cms, recp);
-              if (!enc_val)
+              if (!hexkeygrip)
+                ;
+              else if (!(enc_val = ksba_cms_get_enc_val (cms, recp)))
                 log_error ("recp %d - error getting encrypted session key\n",
                            recp);
               else
                 {
                 log_error ("recp %d - error getting encrypted session key\n",
                            recp);
               else
                 {
-                  rc = prepare_decryption (hexkeygrip, enc_val,
-                                           &dfparm);
+                  rc = prepare_decryption (ctrl,
+                                           hexkeygrip, desc, enc_val, &dfparm);
                   xfree (enc_val);
                   if (rc)
                   xfree (enc_val);
                   if (rc)
-                    log_error ("decrypting session key failed: %s\n",
-                               gnupg_strerror (rc));
+                    {
+                      log_info ("decrypting session key failed: %s\n",
+                                gpg_strerror (rc));
+                      if (gpg_err_code (rc) == GPG_ERR_NO_SECKEY && *kidbuf)
+                        gpgsm_status2 (ctrl, STATUS_NO_SECKEY, kidbuf, NULL);
+                    }
                   else
                     { /* setup the bulk decrypter */
                   else
                     { /* setup the bulk decrypter */
+                      any_key = 1;
                       ksba_writer_set_filter (writer,
                                               decrypt_filter,
                                               &dfparm);
                     }
                       ksba_writer_set_filter (writer,
                                               decrypt_filter,
                                               &dfparm);
                     }
+                  audit_log_ok (ctrl->audit, AUDIT_RECP_RESULT, rc);
                 }
                 }
+              xfree (hexkeygrip);
+              xfree (desc);
+            }
+
+          /* If we write an audit log add the unused recipients to the
+             log as well.  */
+          if (ctrl->audit && any_key)
+            {
+              for (;; recp++)
+                {
+                  char *issuer;
+                  ksba_sexp_t serial;
+                  int tmp_rc;
+
+                  tmp_rc = ksba_cms_get_issuer_serial (cms, recp,
+                                                       &issuer, &serial);
+                  if (tmp_rc == -1)
+                    break; /* no more recipients */
+                  audit_log_i (ctrl->audit, AUDIT_NEW_RECP, recp);
+                  if (tmp_rc)
+                    log_error ("recp %d - error getting info: %s\n",
+                               recp, gpg_strerror (rc));
+                  else
+                    {
+                      char *tmpstr = gpgsm_format_sn_issuer (serial, issuer);
+                      audit_log_s (ctrl->audit, AUDIT_RECP_NAME, tmpstr);
+                      xfree (tmpstr);
+                      xfree (issuer);
+                      xfree (serial);
+                    }
+                }
+            }
+
+          if (!any_key)
+            {
+              rc = gpg_error (GPG_ERR_NO_SECKEY);
+              goto leave;
             }
         }
       else if (stopreason == KSBA_SR_END_DATA)
             }
         }
       else if (stopreason == KSBA_SR_END_DATA)
@@ -405,23 +531,21 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
               if (!npadding || npadding > dfparm.blklen)
                 {
                   log_error ("invalid padding with value %d\n", npadding);
               if (!npadding || npadding > dfparm.blklen)
                 {
                   log_error ("invalid padding with value %d\n", npadding);
-                  rc = seterr (Invalid_Data);
+                  rc = gpg_error (GPG_ERR_INV_DATA);
                   goto leave;
                 }
               rc = ksba_writer_write (writer,
                   goto leave;
                 }
               rc = ksba_writer_write (writer,
-                                      dfparm.lastblock, 
+                                      dfparm.lastblock,
                                       dfparm.blklen - npadding);
               if (rc)
                                       dfparm.blklen - npadding);
               if (rc)
-                {
-                  rc = map_ksba_err (rc);
-                  goto leave;
-                }
+                goto leave;
+
               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
                 {
                   if (dfparm.lastblock[i] != npadding)
                     {
                       log_error ("inconsistent padding\n");
               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
                 {
                   if (dfparm.lastblock[i] != npadding)
                     {
                       log_error ("inconsistent padding\n");
-                      rc = seterr (Invalid_Data);
+                      rc = gpg_error (GPG_ERR_INV_DATA);
                       goto leave;
                     }
                 }
                       goto leave;
                     }
                 }
@@ -429,29 +553,31 @@ gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
         }
 
     }
         }
 
     }
-  while (stopreason != KSBA_SR_READY);   
+  while (stopreason != KSBA_SR_READY);
 
   rc = gpgsm_finish_writer (b64writer);
 
   rc = gpgsm_finish_writer (b64writer);
-  if (rc) 
+  if (rc)
     {
     {
-      log_error ("write failed: %s\n", gnupg_strerror (rc));
+      log_error ("write failed: %s\n", gpg_strerror (rc));
       goto leave;
     }
   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
 
 
  leave:
       goto leave;
     }
   gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
 
 
  leave:
+  audit_log_ok (ctrl->audit, AUDIT_DECRYPTION_RESULT, rc);
   if (rc)
   if (rc)
-    gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
+    {
+      gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
+      log_error ("message decryption failed: %s <%s>\n",
+                 gpg_strerror (rc), gpg_strsource (rc));
+    }
   ksba_cms_release (cms);
   gpgsm_destroy_reader (b64reader);
   gpgsm_destroy_writer (b64writer);
   ksba_cms_release (cms);
   gpgsm_destroy_reader (b64reader);
   gpgsm_destroy_writer (b64writer);
-  keydb_release (kh); 
-  if (in_fp)
-    fclose (in_fp);
+  keydb_release (kh);
+  es_fclose (in_fp);
   if (dfparm.hd)
   if (dfparm.hd)
-    gcry_cipher_close (dfparm.hd); 
+    gcry_cipher_close (dfparm.hd);
   return rc;
 }
   return rc;
 }
-
-