g10,sm: Spell out --gen-key.
[gnupg.git] / sm / decrypt.c
index baf77d0..a2907f6 100644 (file)
@@ -1,11 +1,11 @@
 /* decrypt.c - Decrypt a message
- *     Copyright (C) 2001, 2003 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
- * 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,
@@ -14,9 +14,7 @@
  * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- * USA.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
@@ -24,7 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include <unistd.h> 
+#include <unistd.h>
 #include <time.h>
 #include <assert.h>
 
@@ -35,7 +33,8 @@
 #include "keydb.h"
 #include "i18n.h"
 
-struct decrypt_filter_parm_s {
+struct decrypt_filter_parm_s
+{
   int algo;
   int mode;
   int blklen;
@@ -54,7 +53,7 @@ struct decrypt_filter_parm_s {
 
 /* Decrypt the session key and fill in the parm structure.  The
    algo and the IV is expected to be already in PARM. */
-static int 
+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)
@@ -75,19 +74,21 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
     log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
 
   n=0;
-  if (seskeylen == 24)
+  if (seskeylen == 24 || seskeylen == 16)
     {
-      /* Smells like a 3-des key.  This might happen because a SC has
-         already done the unpacking. */
+      /* Smells like a 3-DES or AES-128 key.  This might happen
+       * because a SC has already done the unpacking.  A better
+       * solution would be to test for this only after we triggered
+       * the GPG_ERR_INV_SESSION_KEY. */
     }
   else
     {
       if (n + 7 > seskeylen )
         {
           rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
-          goto leave; 
+          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
@@ -95,20 +96,20 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
          should be fixed in gpg-agent of course. */
       if (!seskey[n])
         n++;
-      
+
       if (seskey[n] != 2 )  /* Wrong block type version. */
-        { 
+        {
           rc = gpg_error (GPG_ERR_INV_SESSION_KEY);
-          goto leave; 
+          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; 
+          goto leave;
         }
     }
 
@@ -121,7 +122,7 @@ prepare_decryption (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
       log_error ("error creating decryptor: %s\n", gpg_strerror (rc));
       goto leave;
     }
-                        
+
   rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
   if (gpg_err_code (rc) == GPG_ERR_WEAK_KEY)
     {
@@ -239,7 +240,7 @@ decrypt_filter (void *arg,
 \f
 /* Perform a decrypt operation.  */
 int
-gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
+gpgsm_decrypt (ctrl_t ctrl, int in_fd, estream_t out_fp)
 {
   int rc;
   Base64Context b64reader = NULL;
@@ -250,24 +251,25 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
   ksba_stop_reason_t stopreason;
   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);
 
-  kh = keydb_new (0);
+  audit_set_type (ctrl->audit, AUDIT_TYPE_DECRYPT);
+
+  kh = keydb_new ();
   if (!kh)
     {
-      log_error (_("failed to allocated keyDB handle\n"));
+      log_error (_("failed to allocate keyDB handle\n"));
       rc = gpg_error (GPG_ERR_GENERAL);
       goto leave;
     }
 
-
-  in_fp = fdopen ( dup (in_fd), "rb");
+  in_fp = es_fdopen_nc (in_fd, "rb");
   if (!in_fp)
     {
-      rc = gpg_error (gpg_err_code_from_errno (errno));
+      rc = gpg_error_from_syserror ();
       log_error ("fdopen() failed: %s\n", strerror (errno));
       goto leave;
     }
@@ -279,7 +281,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
       goto leave;
     }
 
-  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));
@@ -298,8 +300,10 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
       goto leave;
     }
 
+  audit_log (ctrl->audit, AUDIT_SETUP_READY);
+
   /* Parser loop. */
-  do 
+  do
     {
       rc = ksba_cms_parse (cms, &stopreason);
       if (rc)
@@ -314,14 +318,16 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
           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)
             {
               rc = gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
-              log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
+              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)
@@ -332,6 +338,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
                 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
@@ -341,6 +348,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
 
               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);
@@ -356,7 +365,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
               log_error ("error getting IV: %s\n", gpg_strerror (rc));
               goto leave;
             }
-          
+
           for (recp=0; !any_key; recp++)
             {
               char *issuer;
@@ -364,10 +373,14 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
               ksba_sexp_t enc_val;
               char *hexkeygrip = NULL;
               char *desc = NULL;
+              char kidbuf[16+1];
+
+              *kidbuf = 0;
 
               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",
                            recp, gpg_strerror (rc));
@@ -375,14 +388,21 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
                 {
                   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");
 
+                  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);
+                  rc = keydb_search_issuer_sn (ctrl, kh, issuer, serial);
                   if (rc)
                     {
                       log_error ("failed to find the certificate: %s\n",
@@ -394,8 +414,29 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
                   if (rc)
                     {
                       log_error ("failed to get cert: %s\n", gpg_strerror (rc));
-                      goto oops;     
+                      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 */
@@ -432,6 +473,8 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
                     {
                       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 */
@@ -440,10 +483,41 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
                                               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);
@@ -463,10 +537,10 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
                   goto leave;
                 }
               rc = ksba_writer_write (writer,
-                                      dfparm.lastblock, 
+                                      dfparm.lastblock,
                                       dfparm.blklen - npadding);
               if (rc)
-                  goto leave;
+                goto leave;
 
               for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
                 {
@@ -481,10 +555,10 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
         }
 
     }
-  while (stopreason != KSBA_SR_READY);   
+  while (stopreason != KSBA_SR_READY);
 
   rc = gpgsm_finish_writer (b64writer);
-  if (rc) 
+  if (rc)
     {
       log_error ("write failed: %s\n", gpg_strerror (rc));
       goto leave;
@@ -493,6 +567,7 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
 
 
  leave:
+  audit_log_ok (ctrl->audit, AUDIT_DECRYPTION_RESULT, rc);
   if (rc)
     {
       gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
@@ -502,12 +577,9 @@ gpgsm_decrypt (ctrl_t ctrl, int in_fd, FILE *out_fp)
   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)
-    gcry_cipher_close (dfparm.hd); 
+    gcry_cipher_close (dfparm.hd);
   return rc;
 }
-
-