gpg,gpgsm: Fix compliance check for DSA and avoid an assert.
[gnupg.git] / sm / call-agent.c
index c7d4c5a..0e47c14 100644 (file)
@@ -15,7 +15,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, see <http://www.gnu.org/licenses/>.
+ * along with this program; if not, see <https://www.gnu.org/licenses/>.
  */
 
 #include <config.h>
 #include "gpgsm.h"
 #include <gcrypt.h>
 #include <assuan.h>
-#include "i18n.h"
-#include "asshelp.h"
+#include "../common/i18n.h"
+#include "../common/asshelp.h"
 #include "keydb.h" /* fixme: Move this to import.c */
-#include "membuf.h"
+#include "../common/membuf.h"
+#include "../common/shareddefs.h"
+#include "passphrase.h"
 
 
 static assuan_context_t agent_ctx = NULL;
@@ -74,6 +76,11 @@ struct import_key_parm_s
   size_t keylen;
 };
 
+struct default_inq_parm_s
+{
+  ctrl_t ctrl;
+  assuan_context_t ctx;
+};
 
 \f
 /* Print a warning if the server's version number is less than our
@@ -90,7 +97,7 @@ warn_version_mismatch (ctrl_t ctrl, assuan_context_t ctx,
   if (err)
     log_error (_("error getting version from '%s': %s\n"),
                servername, gpg_strerror (err));
-  else if (!compare_version_strings (serverversion, myversion))
+  else if (compare_version_strings (serverversion, myversion) < 0)
     {
       char *warn;
 
@@ -126,7 +133,6 @@ start_agent (ctrl_t ctrl)
     {
       rc = start_new_gpg_agent (&agent_ctx,
                                 GPG_ERR_SOURCE_DEFAULT,
-                                opt.homedir,
                                 opt.agent_program,
                                 opt.lc_ctype, opt.lc_messages,
                                 opt.session_env,
@@ -151,6 +157,20 @@ start_agent (ctrl_t ctrl)
              agents.  */
           assuan_transact (agent_ctx, "OPTION allow-pinentry-notify",
                            NULL, NULL, NULL, NULL, NULL, NULL);
+
+          /* Pass on the pinentry mode.  */
+          if (opt.pinentry_mode)
+            {
+              char *tmp = xasprintf ("OPTION pinentry-mode=%s",
+                                     str_pinentry_mode (opt.pinentry_mode));
+              rc = assuan_transact (agent_ctx, tmp,
+                               NULL, NULL, NULL, NULL, NULL, NULL);
+              xfree (tmp);
+              if (rc)
+                log_error ("setting pinentry mode '%s' failed: %s\n",
+                           str_pinentry_mode (opt.pinentry_mode),
+                           gpg_strerror (rc));
+            }
         }
     }
 
@@ -163,14 +183,14 @@ start_agent (ctrl_t ctrl)
   return rc;
 }
 
-
 /* This is the default inquiry callback.  It mainly handles the
    Pinentry notifications.  */
 static gpg_error_t
 default_inq_cb (void *opaque, const char *line)
 {
-  gpg_error_t err;
-  ctrl_t ctrl = opaque;
+  gpg_error_t err = 0;
+  struct default_inq_parm_s *parm = opaque;
+  ctrl_t ctrl = parm->ctrl;
 
   if (has_leading_keyword (line, "PINENTRY_LAUNCHED"))
     {
@@ -180,10 +200,18 @@ default_inq_cb (void *opaque, const char *line)
                    "PINENTRY_LAUNCHED");
       /* We do not pass errors to avoid breaking other code.  */
     }
+  else if ((has_leading_keyword (line, "PASSPHRASE")
+            || has_leading_keyword (line, "NEW_PASSPHRASE"))
+           && opt.pinentry_mode == PINENTRY_MODE_LOOPBACK
+           && have_static_passphrase ())
+    {
+      const char *s = get_static_passphrase ();
+      err = assuan_send_data (parm->ctx, s, strlen (s));
+    }
   else
     log_error ("ignoring gpg-agent inquiry '%s'\n", line);
 
-  return 0;
+  return err;
 }
 
 
@@ -200,11 +228,14 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
   char *p, line[ASSUAN_LINELENGTH];
   membuf_t data;
   size_t len;
+  struct default_inq_parm_s inq_parm;
 
   *r_buf = NULL;
   rc = start_agent (ctrl);
   if (rc)
     return rc;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   if (digestlen*2 + 50 > DIM(line))
     return gpg_error (GPG_ERR_GENERAL);
@@ -213,16 +244,14 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
   if (rc)
     return rc;
 
-  snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SIGKEY %s", keygrip);
   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return rc;
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       rc = assuan_transact (agent_ctx, line,
                             NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
@@ -239,7 +268,7 @@ gpgsm_agent_pksign (ctrl_t ctrl, const char *keygrip, const char *desc,
 
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, "PKSIGN",
-                        put_membuf_cb, &data, default_inq_cb, ctrl,
+                        put_membuf_cb, &data, default_inq_cb, &inq_parm,
                         NULL, NULL);
   if (rc)
     {
@@ -272,6 +301,7 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
   const char *hashopt;
   unsigned char *sigbuf;
   size_t sigbuflen;
+  struct default_inq_parm_s inq_parm;
 
   (void)desc;
 
@@ -290,6 +320,8 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
   rc = start_agent (ctrl);
   if (rc)
     return rc;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   if (digestlen*2 + 50 > DIM(line))
     return gpg_error (GPG_ERR_GENERAL);
@@ -303,10 +335,9 @@ gpgsm_scd_pksign (ctrl_t ctrl, const char *keyid, const char *desc,
 
   init_membuf (&data, 1024);
 
-  snprintf (line, DIM(line)-1, "SCD PKSIGN %s %s", hashopt, keyid);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SCD PKSIGN %s %s", hashopt, keyid);
   rc = assuan_transact (agent_ctx, line,
-                        put_membuf_cb, &data, default_inq_cb, ctrl,
+                        put_membuf_cb, &data, default_inq_cb, &inq_parm,
                         NULL, NULL);
   if (rc)
     {
@@ -356,7 +387,10 @@ inq_ciphertext_cb (void *opaque, const char *line)
       assuan_end_confidential (parm->ctx);
     }
   else
-    rc = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      rc = default_inq_cb (&inq_parm, line);
+    }
 
   return rc;
 }
@@ -394,16 +428,14 @@ gpgsm_agent_pkdecrypt (ctrl_t ctrl, const char *keygrip, const char *desc,
     return rc;
 
   assert ( DIM(line) >= 50 );
-  snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "SETKEY %s", keygrip);
   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return rc;
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       rc = assuan_transact (agent_ctx, line,
                             NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
@@ -476,7 +508,10 @@ inq_genkey_parms (void *opaque, const char *line)
       rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
     }
   else
-    rc = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      rc = default_inq_cb (&inq_parm, line);
+    }
 
   return rc;
 }
@@ -544,24 +579,26 @@ gpgsm_agent_readkey (ctrl_t ctrl, int fromcard, const char *hexkeygrip,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm;
 
   *r_pubkey = NULL;
   rc = start_agent (ctrl);
   if (rc)
     return rc;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   rc = assuan_transact (agent_ctx, "RESET",NULL, NULL, NULL, NULL, NULL, NULL);
   if (rc)
     return rc;
 
-  snprintf (line, DIM(line)-1, "%sREADKEY %s",
+  snprintf (line, DIM(line), "%sREADKEY %s",
             fromcard? "SCD ":"", hexkeygrip);
-  line[DIM(line)-1] = 0;
 
   init_membuf (&data, 1024);
   rc = assuan_transact (agent_ctx, line,
                         put_membuf_cb, &data,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   if (rc)
     {
       xfree (get_membuf (&data, &len));
@@ -631,15 +668,18 @@ gpgsm_agent_scd_serialno (ctrl_t ctrl, char **r_serialno)
 {
   int rc;
   char *serialno = NULL;
+  struct default_inq_parm_s inq_parm;
 
   *r_serialno = NULL;
   rc = start_agent (ctrl);
   if (rc)
     return rc;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   rc = assuan_transact (agent_ctx, "SCD SERIALNO",
                         NULL, NULL,
-                        default_inq_cb, ctrl,
+                        default_inq_cb, &inq_parm,
                         scd_serialno_status_cb, &serialno);
   if (!rc && !serialno)
     rc = gpg_error (GPG_ERR_INTERNAL);
@@ -700,15 +740,18 @@ gpgsm_agent_scd_keypairinfo (ctrl_t ctrl, strlist_t *r_list)
 {
   int rc;
   strlist_t list = NULL;
+  struct default_inq_parm_s inq_parm;
 
   *r_list = NULL;
   rc = start_agent (ctrl);
   if (rc)
     return rc;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   rc = assuan_transact (agent_ctx, "SCD LEARN --force",
                         NULL, NULL,
-                        default_inq_cb, ctrl,
+                        default_inq_cb, &inq_parm,
                         scd_keypairinfo_status_cb, &list);
   if (!rc && !list)
     rc = gpg_error (GPG_ERR_NO_DATA);
@@ -764,8 +807,7 @@ gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert, const char *hexfpr,
 
   if (hexfpr)
     {
-      snprintf (line, DIM(line)-1, "ISTRUSTED %s", hexfpr);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "ISTRUSTED %s", hexfpr);
     }
   else
     {
@@ -778,8 +820,7 @@ gpgsm_agent_istrusted (ctrl_t ctrl, ksba_cert_t cert, const char *hexfpr,
           return gpg_error (GPG_ERR_GENERAL);
         }
 
-      snprintf (line, DIM(line)-1, "ISTRUSTED %s", fpr);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "ISTRUSTED %s", fpr);
       xfree (fpr);
     }
 
@@ -797,10 +838,13 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert)
   int rc;
   char *fpr, *dn, *dnfmt;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm;
 
   rc = start_agent (ctrl);
   if (rc)
     return rc;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
   if (!fpr)
@@ -819,13 +863,12 @@ gpgsm_agent_marktrusted (ctrl_t ctrl, ksba_cert_t cert)
   xfree (dn);
   if (!dnfmt)
     return gpg_error_from_syserror ();
-  snprintf (line, DIM(line)-1, "MARKTRUSTED %s S %s", fpr, dnfmt);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "MARKTRUSTED %s S %s", fpr, dnfmt);
   ksba_free (dnfmt);
   xfree (fpr);
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -846,8 +889,7 @@ gpgsm_agent_havekey (ctrl_t ctrl, const char *hexkeygrip)
   if (!hexkeygrip || strlen (hexkeygrip) != 40)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "HAVEKEY %s", hexkeygrip);
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
   return rc;
@@ -928,7 +970,7 @@ learn_cb (void *opaque, const void *buffer, size_t length)
     {
       int existed;
 
-      if (!keydb_store_cert (cert, 0, &existed))
+      if (!keydb_store_cert (parm->ctrl, cert, 0, &existed))
         {
           if (opt.verbose > 1 && existed)
             log_info ("certificate already in DB\n");
@@ -983,29 +1025,30 @@ gpgsm_agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm;
 
   rc = start_agent (ctrl);
   if (rc)
     return rc;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   if (!hexkeygrip || strlen (hexkeygrip) != 40)
     return gpg_error (GPG_ERR_INV_VALUE);
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
-      line[DIM(line)-1] = 0;
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       rc = assuan_transact (agent_ctx, line,
                             NULL, NULL, NULL, NULL, NULL, NULL);
       if (rc)
         return rc;
     }
 
-  snprintf (line, DIM(line)-1, "PASSWD %s", hexkeygrip);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "PASSWD %s", hexkeygrip);
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -1018,16 +1061,18 @@ gpgsm_agent_get_confirmation (ctrl_t ctrl, const char *desc)
 {
   int rc;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm;
 
   rc = start_agent (ctrl);
   if (rc)
     return rc;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
-  snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", desc);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "GET_CONFIRMATION %s", desc);
 
   rc = assuan_transact (agent_ctx, line, NULL, NULL,
-                        default_inq_cb, ctrl, NULL, NULL);
+                        default_inq_cb, &inq_parm, NULL, NULL);
   return rc;
 }
 
@@ -1095,8 +1140,7 @@ gpgsm_agent_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
   if (!hexkeygrip || strlen (hexkeygrip) != 40)
     return gpg_error (GPG_ERR_INV_VALUE);
 
-  snprintf (line, DIM(line)-1, "KEYINFO %s", hexkeygrip);
-  line[DIM(line)-1] = 0;
+  snprintf (line, DIM(line), "KEYINFO %s", hexkeygrip);
 
   err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL,
                          keyinfo_status_cb, &serialno);
@@ -1128,17 +1172,20 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
   char line[ASSUAN_LINELENGTH];
   char *arg4 = NULL;
   membuf_t data;
+  struct default_inq_parm_s inq_parm;
 
   *r_passphrase = NULL;
 
   err = start_agent (ctrl);
   if (err)
     return err;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   if (desc_msg && *desc_msg && !(arg4 = percent_plus_escape (desc_msg)))
     return gpg_error_from_syserror ();
 
-  snprintf (line, DIM(line)-1, "GET_PASSPHRASE --data%s -- X X X %s",
+  snprintf (line, DIM(line), "GET_PASSPHRASE --data%s -- X X X %s",
             repeat? " --repeat=1 --check --qualitybar":"",
             arg4);
   xfree (arg4);
@@ -1146,7 +1193,7 @@ gpgsm_agent_ask_passphrase (ctrl_t ctrl, const char *desc_msg, int repeat,
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, NULL, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
 
   if (err)
     xfree (get_membuf (&data, NULL));
@@ -1174,19 +1221,22 @@ gpgsm_agent_keywrap_key (ctrl_t ctrl, int forexport,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm;
 
   *r_kek = NULL;
   err = start_agent (ctrl);
   if (err)
     return err;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
-  snprintf (line, DIM(line)-1, "KEYWRAP_KEY %s",
+  snprintf (line, DIM(line), "KEYWRAP_KEY %s",
             forexport? "--export":"--import");
 
   init_membuf_secure (&data, 64);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));
@@ -1217,7 +1267,10 @@ inq_import_key_parms (void *opaque, const char *line)
       assuan_end_confidential (parm->ctx);
     }
   else
-    err = default_inq_cb (parm->ctrl, line);
+    {
+      struct default_inq_parm_s inq_parm = { parm->ctrl, parm->ctx };
+      err = default_inq_cb (&inq_parm, line);
+    }
 
   return err;
 }
@@ -1259,28 +1312,31 @@ gpgsm_agent_export_key (ctrl_t ctrl, const char *keygrip, const char *desc,
   size_t len;
   unsigned char *buf;
   char line[ASSUAN_LINELENGTH];
+  struct default_inq_parm_s inq_parm;
 
   *r_result = NULL;
 
   err = start_agent (ctrl);
   if (err)
     return err;
+  inq_parm.ctrl = ctrl;
+  inq_parm.ctx = agent_ctx;
 
   if (desc)
     {
-      snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
+      snprintf (line, DIM(line), "SETKEYDESC %s", desc);
       err = assuan_transact (agent_ctx, line,
                              NULL, NULL, NULL, NULL, NULL, NULL);
       if (err)
         return err;
     }
 
-  snprintf (line, DIM(line)-1, "EXPORT_KEY %s", keygrip);
+  snprintf (line, DIM(line), "EXPORT_KEY %s", keygrip);
 
   init_membuf_secure (&data, 1024);
   err = assuan_transact (agent_ctx, line,
                          put_membuf_cb, &data,
-                         default_inq_cb, ctrl, NULL, NULL);
+                         default_inq_cb, &inq_parm, NULL, NULL);
   if (err)
     {
       xfree (get_membuf (&data, &len));