/* call-agent.c - Divert GPG operations to the agent.
- * Copyright (C) 2001, 2002, 2003, 2006, 2007, 2008, 2009,
- * 2010, 2011, 2013 Free Software Foundation, Inc.
- * Copyright (C) 2013, 2014 Werner Koch
+ * Copyright (C) 2001-2003, 2006-2011, 2013 Free Software Foundation, Inc.
+ * Copyright (C) 2013-2015 Werner Koch
*
* This file is part of GnuPG.
*
* 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 <errno.h>
#include <unistd.h>
#include <time.h>
-#include <assert.h>
#ifdef HAVE_LOCALE_H
#include <locale.h>
#endif
#include "gpg.h"
#include <assuan.h>
-#include "util.h"
-#include "membuf.h"
+#include "../common/util.h"
+#include "../common/membuf.h"
#include "options.h"
-#include "i18n.h"
-#include "asshelp.h"
-#include "sysutils.h"
+#include "../common/i18n.h"
+#include "../common/asshelp.h"
+#include "../common/sysutils.h"
#include "call-agent.h"
-#include "status.h"
+#include "../common/status.h"
#include "../common/shareddefs.h"
-
-#ifndef DBG_ASSUAN
-# define DBG_ASSUAN 1
-#endif
+#include "../common/host2net.h"
#define CONTROL_D ('D' - 'A' + 1)
{
struct default_inq_parm_s *dflt;
const char *keyparms;
+ const char *passphrase;
};
struct import_key_parm_s
};
-struct scd_genkey_parm_s
-{
- struct agent_card_genkey_s *cgk;
- char *savedbytes; /* Malloced space to save key parameter chunks. */
-};
-
-
static gpg_error_t learn_status_cb (void *opaque, const char *line);
}
-static gpg_error_t
-membuf_data_cb (void *opaque, const void *buffer, size_t length)
-{
- membuf_t *data = opaque;
-
- if (buffer)
- put_membuf (data, buffer, length);
- return 0;
-}
-
-
-
/* This is the default inquiry callback. It mainly handles the
Pinentry notifications. */
static gpg_error_t
else
{
char *pw;
+ char buf[32];
if (parm->keyinfo.keyid)
- emit_status_need_passphrase (parm->keyinfo.keyid,
+ emit_status_need_passphrase (parm->ctrl,
+ parm->keyinfo.keyid,
parm->keyinfo.mainkeyid,
parm->keyinfo.pubkey_algo);
+
+ snprintf (buf, sizeof (buf), "%u", 100);
+ write_status_text (STATUS_INQUIRE_MAXLEN, buf);
pw = cpr_get_hidden ("passphrase.enter", _("Enter passphrase: "));
cpr_kill_prompt ();
if (*pw == CONTROL_D && !pw[1])
}
-/* Check whether gnome-keyring hijacked the gpg-agent. */
-static void
-check_hijacking (assuan_context_t ctx)
+/* Print a warning if the server's version number is less than our
+ version number. Returns an error code on a connection problem. */
+static gpg_error_t
+warn_version_mismatch (assuan_context_t ctx, const char *servername, int mode)
{
- membuf_t mb;
- char *string;
-
- init_membuf (&mb, 64);
-
- /* AGENT_ID is a command implemented by gnome-keyring-daemon. It
- does not return any data but an OK line with a remark. */
- if (assuan_transact (ctx, "AGENT_ID",
- membuf_data_cb, &mb, NULL, NULL, NULL, NULL))
- {
- xfree (get_membuf (&mb, NULL));
- return; /* Error - Probably not hijacked. */
- }
- put_membuf (&mb, "", 1);
- string = get_membuf (&mb, NULL);
- if (!string || !*string)
- {
- /* Definitely hijacked - show a warning prompt. */
- static int shown;
- const char warn1[] =
- "The GNOME keyring manager hijacked the GnuPG agent.";
- const char warn2[] =
- "GnuPG will not work properly - please configure that "
- "tool to not interfere with the GnuPG system!";
- log_info ("WARNING: %s\n", warn1);
- log_info ("WARNING: %s\n", warn2);
- /* (GPG_ERR_SOURCRE_GPG, GPG_ERR_NO_AGENT) */
- write_status_text (STATUS_ERROR, "check_hijacking 33554509");
- xfree (string);
- string = strconcat (warn1, "\n\n", warn2, NULL);
- if (string && !shown && !opt.batch)
+ gpg_error_t err;
+ char *serverversion;
+ const char *myversion = strusage (13);
+
+ err = get_assuan_server_version (ctx, mode, &serverversion);
+ if (err)
+ log_log (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED?
+ GPGRT_LOGLVL_INFO : GPGRT_LOGLVL_ERROR,
+ _("error getting version from '%s': %s\n"),
+ servername, gpg_strerror (err));
+ else if (compare_version_strings (serverversion, myversion) < 0)
+ {
+ char *warn;
+
+ warn = xtryasprintf (_("server '%s' is older than us (%s < %s)"),
+ servername, serverversion, myversion);
+ if (!warn)
+ err = gpg_error_from_syserror ();
+ else
{
- /* NB: The Pinentry based prompt will only work if a
- gnome-keyring manager passes invalid commands on to the
- original gpg-agent. */
- char *cmd, *cmdargs;
-
- cmdargs = percent_plus_escape (string);
- cmd = strconcat ("GET_CONFIRMATION ", cmdargs, NULL);
- xfree (cmdargs);
- if (cmd)
+ log_info (_("WARNING: %s\n"), warn);
+ if (!opt.quiet)
{
- struct default_inq_parm_s dfltparm;
-
- memset (&dfltparm, 0, sizeof dfltparm);
- dfltparm.ctx = ctx;
- assuan_transact (ctx, cmd, NULL, NULL,
- default_inq_cb, &dfltparm,
- NULL, NULL);
- xfree (cmd);
- shown = 1;
+ log_info (_("Note: Outdated servers may lack important"
+ " security fixes.\n"));
+ log_info (_("Note: Use the command \"%s\" to restart them.\n"),
+ "gpgconf --kill all");
}
+ write_status_strings (STATUS_WARNING, "server_version_mismatch 0",
+ " ", warn, NULL);
+ xfree (warn);
}
}
- xfree (string);
+ xfree (serverversion);
+ return err;
}
+#define FLAG_FOR_CARD_SUPPRESS_ERRORS 2
/* Try to connect to the agent via socket or fork it off and work by
pipes. Handle the server's initial greeting */
static int
-start_agent (ctrl_t ctrl, int for_card)
+start_agent (ctrl_t ctrl, int flag_for_card)
{
int rc;
{
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,
- opt.autostart, opt.verbose, DBG_ASSUAN,
+ opt.autostart, opt.verbose, DBG_IPC,
NULL, NULL);
if (!opt.autostart && gpg_err_code (rc) == GPG_ERR_NO_AGENT)
{
log_info (_("no gpg-agent running in this session\n"));
}
}
- else if (!rc)
+ else if (!rc
+ && !(rc = warn_version_mismatch (agent_ctx, GPG_AGENT_NAME, 0)))
{
/* Tell the agent that we support Pinentry notifications.
No error checking so that it will work also with older
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));
+ {
+ log_error ("setting pinentry mode '%s' failed: %s\n",
+ str_pinentry_mode (opt.pinentry_mode),
+ gpg_strerror (rc));
+ write_status_error ("set_pinentry_mode", rc);
+ }
+ }
+
+ /* Pass on the request origin. */
+ if (opt.request_origin)
+ {
+ char *tmp = xasprintf ("OPTION pretend-request-origin=%s",
+ str_request_origin (opt.request_origin));
+ rc = assuan_transact (agent_ctx, tmp,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ xfree (tmp);
+ if (rc)
+ {
+ log_error ("setting request origin '%s' failed: %s\n",
+ str_request_origin (opt.request_origin),
+ gpg_strerror (rc));
+ write_status_error ("set_request_origin", rc);
+ }
+ }
+
+ /* In DE_VS mode under Windows we require that the JENT RNG
+ * is active. */
+#ifdef HAVE_W32_SYSTEM
+ if (!rc && opt.compliance == CO_DE_VS)
+ {
+ if (assuan_transact (agent_ctx, "GETINFO jent_active",
+ NULL, NULL, NULL, NULL, NULL, NULL))
+ {
+ rc = gpg_error (GPG_ERR_FORBIDDEN);
+ log_error (_("%s is not compliant with %s mode\n"),
+ GPG_AGENT_NAME,
+ gnupg_compliance_option_string (opt.compliance));
+ write_status_error ("random-compliance", rc);
+ }
}
+#endif /*HAVE_W32_SYSTEM*/
- check_hijacking (agent_ctx);
}
}
- if (!rc && for_card && !did_early_card_test)
+ if (!rc && flag_for_card && !did_early_card_test)
{
/* Request the serial number of the card for an early test. */
struct agent_card_info_s info;
memset (&info, 0, sizeof info);
- rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
- NULL, NULL, NULL, NULL,
- learn_status_cb, &info);
- if (rc)
+
+ if (!(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
+ rc = warn_version_mismatch (agent_ctx, SCDAEMON_NAME, 2);
+ if (!rc)
+ rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
+ NULL, NULL, NULL, NULL,
+ learn_status_cb, &info);
+ if (rc && !(flag_for_card & FLAG_FOR_CARD_SUPPRESS_ERRORS))
{
switch (gpg_err_code (rc))
{
case GPG_ERR_NO_SCDAEMON:
write_status_text (STATUS_CARDCTRL, "6");
break;
+ case GPG_ERR_OBJ_TERM_STATE:
+ write_status_text (STATUS_CARDCTRL, "7");
+ break;
default:
write_status_text (STATUS_CARDCTRL, "4");
log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
}
-/* Take a 20 byte hexencoded string and put it into the the provided
- 20 byte buffer FPR in binary format. */
-static int
-unhexify_fpr (const char *hexstr, unsigned char *fpr)
+/* Take a 20 or 32 byte hexencoded string and put it into the provided
+ * FPRLEN byte long buffer FPR in binary format. Returns the actual
+ * used length of the FPR buffer or 0 on error. */
+static unsigned int
+unhexify_fpr (const char *hexstr, unsigned char *fpr, unsigned int fprlen)
{
const char *s;
int n;
for (s=hexstr, n=0; hexdigitp (s); s++, n++)
;
- if (*s || (n != 40))
+ if ((*s && *s != ' ') || !(n == 40 || n == 64))
return 0; /* no fingerprint (invalid or wrong length). */
- for (s=hexstr, n=0; *s; s += 2, n++)
+ for (s=hexstr, n=0; *s && n < fprlen; s += 2, n++)
fpr[n] = xtoi_2 (s);
- return 1; /* okay */
+
+ return (n == 20 || n == 32)? n : 0;
}
/* Take the serial number from LINE and return it verbatim in a newly
void
agent_release_card_info (struct agent_card_info_s *info)
{
+ int i;
+
if (!info)
return;
+ xfree (info->reader); info->reader = NULL;
xfree (info->serialno); info->serialno = NULL;
xfree (info->apptype); info->apptype = NULL;
xfree (info->disp_name); info->disp_name = NULL;
xfree (info->disp_lang); info->disp_lang = NULL;
xfree (info->pubkey_url); info->pubkey_url = NULL;
xfree (info->login_data); info->login_data = NULL;
- info->cafpr1valid = info->cafpr2valid = info->cafpr3valid = 0;
- info->fpr1valid = info->fpr2valid = info->fpr3valid = 0;
+ info->cafpr1len = info->cafpr2len = info->cafpr3len = 0;
+ info->fpr1len = info->fpr2len = info->fpr3len = 0;
+ for (i=0; i < DIM(info->private_do); i++)
+ {
+ xfree (info->private_do[i]);
+ info->private_do[i] = NULL;
+ }
}
+
static gpg_error_t
learn_status_cb (void *opaque, const char *line)
{
while (spacep (line))
line++;
- if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
+ if (keywordlen == 6 && !memcmp (keyword, "READER", keywordlen))
+ {
+ xfree (parm->reader);
+ parm->reader = unescape_status_string (line);
+ }
+ else if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
{
xfree (parm->serialno);
parm->serialno = store_serialno (line);
parm->extcap.ki = abool;
else if (!strcmp (p, "aac"))
parm->extcap.aac = abool;
+ else if (!strcmp (p, "bt"))
+ parm->extcap.bt = abool;
+ else if (!strcmp (p, "kdf"))
+ parm->extcap.kdf = abool;
+ else if (!strcmp (p, "si"))
+ parm->status_indicator = strtoul (p2, NULL, 10);
}
}
xfree (buf);
while (spacep (line))
line++;
if (no == 1)
- parm->fpr1valid = unhexify_fpr (line, parm->fpr1);
+ parm->fpr1len = unhexify_fpr (line, parm->fpr1, sizeof parm->fpr1);
else if (no == 2)
- parm->fpr2valid = unhexify_fpr (line, parm->fpr2);
+ parm->fpr2len = unhexify_fpr (line, parm->fpr2, sizeof parm->fpr2);
else if (no == 3)
- parm->fpr3valid = unhexify_fpr (line, parm->fpr3);
+ parm->fpr3len = unhexify_fpr (line, parm->fpr3, sizeof parm->fpr3);
}
else if (keywordlen == 8 && !memcmp (keyword, "KEY-TIME", keywordlen))
{
else if (no == 3)
parm->fpr3time = strtoul (line, NULL, 10);
}
+ else if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
+ {
+ const char *hexgrp = line;
+ int no;
+
+ while (*line && !spacep (line))
+ line++;
+ while (spacep (line))
+ line++;
+ if (strncmp (line, "OPENPGP.", 8))
+ ;
+ else if ((no = atoi (line+8)) == 1)
+ unhexify_fpr (hexgrp, parm->grp1, sizeof parm->grp1);
+ else if (no == 2)
+ unhexify_fpr (hexgrp, parm->grp2, sizeof parm->grp2);
+ else if (no == 3)
+ unhexify_fpr (hexgrp, parm->grp3, sizeof parm->grp3);
+ }
else if (keywordlen == 6 && !memcmp (keyword, "CA-FPR", keywordlen))
{
int no = atoi (line);
while (spacep (line))
line++;
if (no == 1)
- parm->cafpr1valid = unhexify_fpr (line, parm->cafpr1);
+ parm->cafpr1len = unhexify_fpr (line, parm->cafpr1,sizeof parm->cafpr1);
else if (no == 2)
- parm->cafpr2valid = unhexify_fpr (line, parm->cafpr2);
+ parm->cafpr2len = unhexify_fpr (line, parm->cafpr2,sizeof parm->cafpr2);
else if (no == 3)
- parm->cafpr3valid = unhexify_fpr (line, parm->cafpr3);
+ parm->cafpr3len = unhexify_fpr (line, parm->cafpr3,sizeof parm->cafpr3);
}
else if (keywordlen == 8 && !memcmp (keyword, "KEY-ATTR", keywordlen))
{
- int keyno, algo, nbits;
+ int keyno = 0;
+ int algo = PUBKEY_ALGO_RSA;
+ int n = 0;
- sscanf (line, "%d %d %d", &keyno, &algo, &nbits);
+ sscanf (line, "%d %d %n", &keyno, &algo, &n);
keyno--;
- if (keyno >= 0 && keyno < DIM (parm->key_attr))
- {
- parm->key_attr[keyno].algo = algo;
- parm->key_attr[keyno].nbits = nbits;
- }
+ if (keyno < 0 || keyno >= DIM (parm->key_attr))
+ return 0;
+
+ parm->key_attr[keyno].algo = algo;
+ if (algo == PUBKEY_ALGO_RSA)
+ parm->key_attr[keyno].nbits = strtoul (line+n+3, NULL, 10);
+ else if (algo == PUBKEY_ALGO_ECDH || algo == PUBKEY_ALGO_ECDSA
+ || algo == PUBKEY_ALGO_EDDSA)
+ parm->key_attr[keyno].curve = openpgp_is_curve_supported (line + n,
+ NULL, NULL);
+ }
+ else if (keywordlen == 12 && !memcmp (keyword, "PRIVATE-DO-", 11)
+ && strchr("1234", keyword[11]))
+ {
+ int no = keyword[11] - '1';
+ log_assert (no >= 0 && no <= 3);
+ xfree (parm->private_do[no]);
+ parm->private_do[no] = unescape_status_string (line);
+ }
+ else if (keywordlen == 3 && !memcmp (keyword, "KDF", 3))
+ {
+ parm->kdf_do_enabled = 1;
+ }
+ else if (keywordlen == 5 && !memcmp (keyword, "UIF-", 4)
+ && strchr("123", keyword[4]))
+ {
+ unsigned char *data;
+ int no = keyword[4] - '1';
+
+ log_assert (no >= 0 && no <= 2);
+ data = unescape_status_string (line);
+ parm->uif[no] = (data[0] != 0xff);
+ xfree (data);
}
return 0;
/* Call the scdaemon to learn about a smartcard */
int
-agent_scd_learn (struct agent_card_info_s *info)
+agent_scd_learn (struct agent_card_info_s *info, int force)
{
int rc;
struct default_inq_parm_s parm;
struct agent_card_info_s dummyinfo;
+ if (!info)
+ info = &dummyinfo;
+ memset (info, 0, sizeof *info);
memset (&parm, 0, sizeof parm);
rc = start_agent (NULL, 1);
if (rc)
return rc;
- /* Send the serialno command to initialize the connection. We don't
- care about the data returned. If the card has already been
- initialized, this is a very fast command. The main reason we
- need to do this here is to handle a card removed case so that an
- "l" command in --card-edit can be used to show ta newly inserted
- card. We request the openpgp card because that is what we
- expect. */
- rc = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return rc;
-
- if (!info)
- info = &dummyinfo;
-
parm.ctx = agent_ctx;
- memset (info, 0, sizeof *info);
- rc = assuan_transact (agent_ctx, "LEARN --sendinfo",
+ rc = assuan_transact (agent_ctx,
+ force ? "LEARN --sendinfo --force" : "LEARN --sendinfo",
dummy_data_cb, NULL, default_inq_cb, &parm,
learn_status_cb, info);
/* Also try to get the key attributes. */
}
+/* Send an APDU to the current card. On success the status word is
+ stored at R_SW. With HEXAPDU being NULL only a RESET command is
+ send to scd. With HEXAPDU being the string "undefined" the command
+ "SERIALNO undefined" is send to scd. */
+gpg_error_t
+agent_scd_apdu (const char *hexapdu, unsigned int *r_sw)
+{
+ gpg_error_t err;
+
+ /* Start the agent but not with the card flag so that we do not
+ autoselect the openpgp application. */
+ err = start_agent (NULL, 0);
+ if (err)
+ return err;
+
+ if (!hexapdu)
+ {
+ err = assuan_transact (agent_ctx, "SCD RESET",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+
+ }
+ else if (!strcmp (hexapdu, "undefined"))
+ {
+ err = assuan_transact (agent_ctx, "SCD SERIALNO undefined",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ }
+ else
+ {
+ char line[ASSUAN_LINELENGTH];
+ membuf_t mb;
+ unsigned char *data;
+ size_t datalen;
+
+ init_membuf (&mb, 256);
+
+ snprintf (line, DIM(line), "SCD APDU %s", hexapdu);
+ err = assuan_transact (agent_ctx, line,
+ put_membuf_cb, &mb, NULL, NULL, NULL, NULL);
+ if (!err)
+ {
+ data = get_membuf (&mb, &datalen);
+ if (!data)
+ err = gpg_error_from_syserror ();
+ else if (datalen < 2) /* Ooops */
+ err = gpg_error (GPG_ERR_CARD);
+ else
+ {
+ *r_sw = buf16_to_uint (data+datalen-2);
+ }
+ xfree (data);
+ }
+ }
+
+ return err;
+}
+
+
int
agent_keytocard (const char *hexgrip, int keyno, int force,
const char *serialno, const char *timestamp)
struct default_inq_parm_s parm;
memset (&parm, 0, sizeof parm);
- parm.ctx = agent_ctx;
- snprintf (line, DIM(line)-1, "KEYTOCARD %s%s %s OPENPGP.%d %s",
+ snprintf (line, DIM(line), "KEYTOCARD %s%s %s OPENPGP.%d %s",
force?"--force ": "", hexgrip, serialno, keyno, timestamp);
- line[DIM(line)-1] = 0;
rc = start_agent (NULL, 1);
if (rc)
return rc;
+ parm.ctx = agent_ctx;
rc = assuan_transact (agent_ctx, line, NULL, NULL, default_inq_cb, &parm,
NULL, NULL);
return rc;
}
+
+
\f
/* Call the agent to retrieve a data object. This function returns
the data in the same structure as used by the learn command. It is
- allowed to update such a structure using this commmand. */
+ allowed to update such a structure using this command. */
int
agent_scd_getattr (const char *name, struct agent_card_info_s *info)
{
memset (&parms, 0, sizeof parms);
- snprintf (line, DIM(line)-1, "SCD WRITECERT %s", certidstr);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SCD WRITECERT %s", certidstr);
dfltparm.ctx = agent_ctx;
parms.dflt = &dfltparm;
parms.certdata = certdata;
memset (&parms, 0, sizeof parms);
- snprintf (line, DIM(line)-1, "SCD WRITEKEY --force OPENPGP.%d", keyno);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SCD WRITEKEY --force OPENPGP.%d", keyno);
dfltparm.ctx = agent_ctx;
parms.dflt = &dfltparm;
parms.keydata = keydata;
\f
-static gpg_error_t
-scd_genkey_cb_append_savedbytes (struct scd_genkey_parm_s *parm,
- const char *line)
-{
- gpg_error_t err = 0;
- char *p;
-
- if (!parm->savedbytes)
- {
- parm->savedbytes = xtrystrdup (line);
- if (!parm->savedbytes)
- err = gpg_error_from_syserror ();
- }
- else
- {
- p = xtrymalloc (strlen (parm->savedbytes) + strlen (line) + 1);
- if (!p)
- err = gpg_error_from_syserror ();
- else
- {
- strcpy (stpcpy (p, parm->savedbytes), line);
- xfree (parm->savedbytes);
- parm->savedbytes = p;
- }
- }
-
- return err;
-}
-
/* Status callback for the SCD GENKEY command. */
static gpg_error_t
scd_genkey_cb (void *opaque, const char *line)
{
- struct scd_genkey_parm_s *parm = opaque;
+ u32 *createtime = opaque;
const char *keyword = line;
int keywordlen;
- gpg_error_t rc = 0;
for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
;
while (spacep (line))
line++;
- if (keywordlen == 7 && !memcmp (keyword, "KEY-FPR", keywordlen))
+ if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
{
- parm->cgk->fprvalid = unhexify_fpr (line, parm->cgk->fpr);
- }
- else if (keywordlen == 8 && !memcmp (keyword, "KEY-DATA", keywordlen))
- {
- gcry_mpi_t a;
- const char *name = line;
-
- while (*line && !spacep (line))
- line++;
- while (spacep (line))
- line++;
-
- if (*name == '-' && spacep (name+1))
- rc = scd_genkey_cb_append_savedbytes (parm, line);
- else
- {
- if (parm->savedbytes)
- {
- rc = scd_genkey_cb_append_savedbytes (parm, line);
- if (!rc)
- rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX,
- parm->savedbytes, 0, NULL);
- }
- else
- rc = gcry_mpi_scan (&a, GCRYMPI_FMT_HEX, line, 0, NULL);
- if (rc)
- log_error ("error parsing received key data: %s\n",
- gpg_strerror (rc));
- else if (*name == 'n' && spacep (name+1))
- parm->cgk->n = a;
- else if (*name == 'e' && spacep (name+1))
- parm->cgk->e = a;
- else
- {
- log_info ("unknown parameter name in received key data\n");
- gcry_mpi_release (a);
- rc = gpg_error (GPG_ERR_INV_PARAMETER);
- }
-
- xfree (parm->savedbytes);
- parm->savedbytes = NULL;
- }
- }
- else if (keywordlen == 14 && !memcmp (keyword,"KEY-CREATED-AT", keywordlen))
- {
- parm->cgk->created_at = (u32)strtoul (line, NULL, 10);
+ *createtime = (u32)strtoul (line, NULL, 10);
}
else if (keywordlen == 8 && !memcmp (keyword, "PROGRESS", keywordlen))
{
write_status_text (STATUS_PROGRESS, line);
}
- return rc;
+ return 0;
}
-/* Send a GENKEY command to the SCdaemon. SERIALNO is not used in
- this implementation. If CREATEDATE is not 0, it will be passed to
- SCDAEMON so that the key is created with this timestamp. INFO will
- receive information about the generated key. */
+/* Send a GENKEY command to the SCdaemon. If *CREATETIME is not 0,
+ the value will be passed to SCDAEMON with --timestamp option so that
+ the key is created with this. Otherwise, timestamp was generated by
+ SCDEAMON. On success, creation time is stored back to
+ CREATETIME. */
int
-agent_scd_genkey (struct agent_card_genkey_s *info, int keyno, int force,
- const char *serialno, u32 createtime)
+agent_scd_genkey (int keyno, int force, u32 *createtime)
{
int rc;
char line[ASSUAN_LINELENGTH];
gnupg_isotime_t tbuf;
- struct scd_genkey_parm_s parms;
struct default_inq_parm_s dfltparm;
memset (&dfltparm, 0, sizeof dfltparm);
- (void)serialno;
-
- memset (&parms, 0, sizeof parms);
- parms.cgk = info;
-
rc = start_agent (NULL, 1);
if (rc)
return rc;
- if (createtime)
- epoch2isotime (tbuf, createtime);
+ if (*createtime)
+ epoch2isotime (tbuf, *createtime);
else
*tbuf = 0;
- snprintf (line, DIM(line)-1, "SCD GENKEY %s%s %s %d",
+ snprintf (line, DIM(line), "SCD GENKEY %s%s %s %d",
*tbuf? "--timestamp=":"", tbuf,
force? "--force":"",
keyno);
- line[DIM(line)-1] = 0;
dfltparm.ctx = agent_ctx;
- memset (info, 0, sizeof *info);
rc = assuan_transact (agent_ctx, line,
NULL, NULL, default_inq_cb, &dfltparm,
- scd_genkey_cb, &parms);
-
- xfree (parms.savedbytes);
+ scd_genkey_cb, createtime);
status_sc_op_failure (rc);
return rc;
}
-
-
-
\f
-/* Issue an SCD SERIALNO openpgp command and if SERIALNO is not NULL
- ask the user to insert the requested card. */
-gpg_error_t
-select_openpgp (const char *serialno)
+/* Return the serial number of the card or an appropriate error. The
+ serial number is returned as a hexstring. */
+int
+agent_scd_serialno (char **r_serialno, const char *demand)
{
- gpg_error_t err;
-
- /* Send the serialno command to initialize the connection. Without
- a given S/N we don't care about the data returned. If the card
- has already been initialized, this is a very fast command. We
- request the openpgp card because that is what we expect.
-
- Note that an opt.limit_card_insert_tries of 1 means: No tries at
- all whereas 0 means do not limit the number of tries. Due to the
- sue of a pinentry prompt with a cancel option we use it here in a
- boolean sense. */
- if (!serialno || opt.limit_card_insert_tries == 1)
- err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
- NULL, NULL, NULL, NULL, NULL, NULL);
- else
- {
- char *this_sn = NULL;
- char *desc;
- int ask;
- char *want_sn;
- char *p;
-
- want_sn = xtrystrdup (serialno);
- if (!want_sn)
- return gpg_error_from_syserror ();
- p = strchr (want_sn, '/');
- if (p)
- *p = 0;
+ int err;
+ char *serialno = NULL;
+ char line[ASSUAN_LINELENGTH];
- do
- {
- ask = 0;
- err = assuan_transact (agent_ctx, "SCD SERIALNO openpgp",
- NULL, NULL, NULL, NULL,
- get_serialno_cb, &this_sn);
- if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
- ask = 1;
- else if (gpg_err_code (err) == GPG_ERR_NOT_SUPPORTED)
- ask = 2;
- else if (err)
- ;
- else if (this_sn)
- {
- if (strcmp (want_sn, this_sn))
- ask = 2;
- }
+ err = start_agent (NULL, 1 | FLAG_FOR_CARD_SUPPRESS_ERRORS);
+ if (err)
+ return err;
- xfree (this_sn);
- this_sn = NULL;
+ if (!demand)
+ strcpy (line, "SCD SERIALNO");
+ else
+ snprintf (line, DIM(line), "SCD SERIALNO --demand=%s", demand);
- if (ask)
- {
- char *formatted = NULL;
- char *ocodeset = i18n_switchto_utf8 ();
-
- if (!strncmp (want_sn, "D27600012401", 12)
- && strlen (want_sn) == 32 )
- formatted = xtryasprintf ("(%.4s) %.8s",
- want_sn + 16, want_sn + 20);
-
- err = 0;
- desc = xtryasprintf
- ("%s:\n\n"
- " \"%s\"",
- ask == 1
- ? _("Please insert the card with serial number")
- : _("Please remove the current card and "
- "insert the one with serial number"),
- formatted? formatted : want_sn);
- if (!desc)
- err = gpg_error_from_syserror ();
- xfree (formatted);
- i18n_switchback (ocodeset);
- if (!err)
- err = gpg_agent_get_confirmation (desc);
- xfree (desc);
- }
- }
- while (ask && !err);
- xfree (want_sn);
+ err = assuan_transact (agent_ctx, line,
+ NULL, NULL, NULL, NULL,
+ get_serialno_cb, &serialno);
+ if (err)
+ {
+ xfree (serialno);
+ return err;
}
- return err;
+ *r_serialno = serialno;
+ return 0;
}
-
-
\f
/* Send a READCERT command to the SCdaemon. */
int
init_membuf (&data, 2048);
- snprintf (line, DIM(line)-1, "SCD READCERT %s", certidstr);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SCD READCERT %s", certidstr);
rc = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
default_inq_cb, &dfltparm,
NULL, NULL);
if (rc)
return 0;
}
+\f
+struct card_cardlist_parm_s {
+ int error;
+ strlist_t list;
+};
+
+
+/* Callback function for agent_card_cardlist. */
+static gpg_error_t
+card_cardlist_cb (void *opaque, const char *line)
+{
+ struct card_cardlist_parm_s *parm = opaque;
+ const char *keyword = line;
+ int keywordlen;
+
+ for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+ ;
+ while (spacep (line))
+ line++;
+
+ if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
+ {
+ const char *s;
+ int n;
+
+ for (n=0,s=line; hexdigitp (s); s++, n++)
+ ;
+
+ if (!n || (n&1) || *s)
+ parm->error = gpg_error (GPG_ERR_ASS_PARAMETER);
+ else
+ add_to_strlist (&parm->list, line);
+ }
+
+ return 0;
+}
+
+/* Return cardlist. */
+int
+agent_scd_cardlist (strlist_t *result)
+{
+ int err;
+ char line[ASSUAN_LINELENGTH];
+ struct card_cardlist_parm_s parm;
+ memset (&parm, 0, sizeof parm);
+ *result = NULL;
+ err = start_agent (NULL, 1);
+ if (err)
+ return err;
+
+ strcpy (line, "SCD GETINFO card_list");
+
+ err = assuan_transact (agent_ctx, line,
+ NULL, NULL, NULL, NULL,
+ card_cardlist_cb, &parm);
+ if (!err && parm.error)
+ err = parm.error;
+
+ if (!err)
+ *result = parm.list;
+ else
+ free_strlist (parm.list);
+ return 0;
+}
\f
/* Change the PIN of an OpenPGP card or reset the retry counter.
CHVNO 1: Change the PIN
return rc;
dfltparm.ctx = agent_ctx;
- snprintf (line, DIM(line)-1, "SCD PASSWD %s %d", reset, chvno);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SCD PASSWD %s %d", reset, chvno);
rc = assuan_transact (agent_ctx, line,
NULL, NULL,
default_inq_cb, &dfltparm,
return rc;
dfltparm.ctx = agent_ctx;
- snprintf (line, DIM(line)-1, "SCD CHECKPIN %s", serialno);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SCD CHECKPIN %s", serialno);
rc = assuan_transact (agent_ctx, line,
NULL, NULL,
default_inq_cb, &dfltparm,
if (!(arg4 = percent_plus_escape (desc_msg)))
goto no_mem;
- snprintf (line, DIM(line)-1,
+ snprintf (line, DIM(line),
"GET_PASSPHRASE --data --repeat=%d%s -- %s %s %s %s",
repeat,
check? " --check --qualitybar":"",
arg2? arg2:"X",
arg3? arg3:"X",
arg4? arg4:"X");
- line[DIM(line)-1] = 0;
xfree (arg1);
xfree (arg2);
xfree (arg3);
init_membuf_secure (&data, 64);
rc = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
default_inq_cb, &dfltparm,
NULL, NULL);
return rc;
dfltparm.ctx = agent_ctx;
- snprintf (line, DIM(line)-1, "CLEAR_PASSPHRASE %s", cache_id);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "CLEAR_PASSPHRASE %s", cache_id);
return assuan_transact (agent_ctx, line,
NULL, NULL,
default_inq_cb, &dfltparm,
tmp = percent_plus_escape (desc);
if (!tmp)
return gpg_error_from_syserror ();
- snprintf (line, DIM(line)-1, "GET_CONFIRMATION %s", tmp);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "GET_CONFIRMATION %s", tmp);
xfree (tmp);
rc = assuan_transact (agent_ctx, line,
init_membuf (&data, 32);
err = assuan_transact (agent_ctx, "GETINFO s2k_count",
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
NULL, NULL, NULL, NULL);
if (err)
xfree (get_membuf (&data, NULL));
char *p;
kbnode_t kbctx, node;
int nkeys;
- unsigned char grip[20];
+ unsigned char grip[KEYGRIP_LEN];
err = start_agent (ctrl, 0);
if (err)
\f
+struct keyinfo_data_parm_s
+{
+ char *serialno;
+ int cleartext;
+};
+
+
static gpg_error_t
keyinfo_status_cb (void *opaque, const char *line)
{
- char **serialno = opaque;
- const char *s, *s2;
+ struct keyinfo_data_parm_s *data = opaque;
+ int is_smartcard;
+ char *s;
- if ((s = has_leading_keyword (line, "KEYINFO ")) && !*serialno)
+ if ((s = has_leading_keyword (line, "KEYINFO")) && data)
{
- s = strchr (s, ' ');
- if (s && s[1] == 'T' && s[2] == ' ' && s[3])
+ /* Parse the arguments:
+ * 0 1 2 3 4 5
+ * <keygrip> <type> <serialno> <idstr> <cached> <protection>
+ */
+ char *fields[6];
+
+ if (split_fields (s, fields, DIM (fields)) == 6)
{
- s += 3;
- s2 = strchr (s, ' ');
- if ( s2 > s )
- {
- *serialno = xtrymalloc ((s2 - s)+1);
- if (*serialno)
- {
- memcpy (*serialno, s, s2 - s);
- (*serialno)[s2 - s] = 0;
- }
- }
+ is_smartcard = (fields[1][0] == 'T');
+ if (is_smartcard && !data->serialno && strcmp (fields[2], "-"))
+ data->serialno = xtrystrdup (fields[2]);
+ /* 'P' for protected, 'C' for clear */
+ data->cleartext = (fields[5][0] == 'C');
}
}
return 0;
/* Return the serial number for a secret key. If the returned serial
number is NULL, the key is not stored on a smartcard. Caller needs
- to free R_SERIALNO. */
+ to free R_SERIALNO.
+
+ if r_cleartext is not NULL, the referenced int will be set to 1 if
+ the agent's copy of the key is stored in the clear, or 0 otherwise
+*/
gpg_error_t
-agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip, char **r_serialno)
+agent_get_keyinfo (ctrl_t ctrl, const char *hexkeygrip,
+ char **r_serialno, int *r_cleartext)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
- char *serialno = NULL;
+ struct keyinfo_data_parm_s keyinfo;
+
+ memset (&keyinfo, 0,sizeof keyinfo);
*r_serialno = NULL;
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);
- if (!err && serialno)
+ keyinfo_status_cb, &keyinfo);
+ if (!err && keyinfo.serialno)
{
/* Sanity check for bad characters. */
- if (strpbrk (serialno, ":\n\r"))
+ if (strpbrk (keyinfo.serialno, ":\n\r"))
err = GPG_ERR_INV_VALUE;
}
if (err)
- xfree (serialno);
+ xfree (keyinfo.serialno);
else
- *r_serialno = serialno;
+ {
+ *r_serialno = keyinfo.serialno;
+ if (r_cleartext)
+ *r_cleartext = keyinfo.cleartext;
+ }
return err;
}
cache_nonce_status_cb (void *opaque, const char *line)
{
struct cache_nonce_parm_s *parm = opaque;
- const char *keyword = line;
- int keywordlen;
-
- for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
- ;
- while (spacep (line))
- line++;
+ const char *s;
- if (keywordlen == 11 && !memcmp (keyword, "CACHE_NONCE", keywordlen))
+ if ((s = has_leading_keyword (line, "CACHE_NONCE")))
{
if (parm->cache_nonce_addr)
{
xfree (*parm->cache_nonce_addr);
- *parm->cache_nonce_addr = xtrystrdup (line);
+ *parm->cache_nonce_addr = xtrystrdup (s);
}
}
- else if (keywordlen == 12 && !memcmp (keyword, "PASSWD_NONCE", keywordlen))
+ else if ((s = has_leading_keyword (line, "PASSWD_NONCE")))
{
if (parm->passwd_nonce_addr)
{
xfree (*parm->passwd_nonce_addr);
- *parm->passwd_nonce_addr = xtrystrdup (line);
+ *parm->passwd_nonce_addr = xtrystrdup (s);
}
}
+ else if ((s = has_leading_keyword (line, "PROGRESS")))
+ {
+ if (opt.enable_progress_filter)
+ write_status_text (STATUS_PROGRESS, s);
+ }
return 0;
}
err = assuan_send_data (parm->dflt->ctx,
parm->keyparms, strlen (parm->keyparms));
}
+ else if (has_leading_keyword (line, "NEWPASSWD") && parm->passphrase)
+ {
+ err = assuan_send_data (parm->dflt->ctx,
+ parm->passphrase, strlen (parm->passphrase));
+ }
else
err = default_inq_cb (parm->dflt, line);
/* Call the agent to generate a new key. KEYPARMS is the usual
S-expression giving the parameters of the key. gpg-agent passes it
gcry_pk_genkey. If NO_PROTECTION is true the agent is advised not
- to protect the generated key. */
+ to protect the generated key. If NO_PROTECTION is not set and
+ PASSPHRASE is not NULL the agent is requested to protect the key
+ with that passphrase instead of asking for one. */
gpg_error_t
-agent_genkey (ctrl_t ctrl, char **cache_nonce_addr,
- const char *keyparms, int no_protection, gcry_sexp_t *r_pubkey)
+agent_genkey (ctrl_t ctrl, char **cache_nonce_addr, char **passwd_nonce_addr,
+ const char *keyparms, int no_protection,
+ const char *passphrase, gcry_sexp_t *r_pubkey)
{
gpg_error_t err;
struct genkey_parm_s gk_parm;
return err;
dfltparm.ctx = agent_ctx;
- err = assuan_transact (agent_ctx, "RESET",
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (err)
- return err;
+ if (passwd_nonce_addr && *passwd_nonce_addr)
+ ; /* A RESET would flush the passwd nonce cache. */
+ else
+ {
+ err = assuan_transact (agent_ctx, "RESET",
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ if (err)
+ return err;
+ }
init_membuf (&data, 1024);
gk_parm.dflt = &dfltparm;
gk_parm.keyparms = keyparms;
- snprintf (line, sizeof line, "GENKEY%s%s%s",
- no_protection? " --no-protection":"",
+ gk_parm.passphrase = passphrase;
+ snprintf (line, sizeof line, "GENKEY%s%s%s%s%s",
+ no_protection? " --no-protection" :
+ passphrase ? " --inq-passwd" :
+ /* */ "",
+ passwd_nonce_addr && *passwd_nonce_addr? " --passwd-nonce=":"",
+ passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
cache_nonce_addr && *cache_nonce_addr? " ":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"");
cn_parm.cache_nonce_addr = cache_nonce_addr;
cn_parm.passwd_nonce_addr = NULL;
err = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
inq_genkey_parms, &gk_parm,
cache_nonce_status_cb, &cn_parm);
if (err)
if (err)
return err;
- snprintf (line, DIM(line)-1, "%sREADKEY %s", fromcard? "SCD ":"", hexkeygrip);
+ snprintf (line, DIM(line), "READKEY %s%s", fromcard? "--card ":"",
+ hexkeygrip);
init_membuf (&data, 1024);
err = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
default_inq_cb, &dfltparm,
NULL, NULL);
if (err)
if (err)
return err;
- snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SIGKEY %s", keygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
return err;
if (desc)
{
- snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SETKEYDESC %s", desc);
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
snprintf (line, sizeof line, "PKSIGN%s%s",
cache_nonce? " -- ":"",
cache_nonce? cache_nonce:"");
+
+ if (DBG_CLOCK)
+ log_clock ("enter signing");
err = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
default_inq_cb, &dfltparm,
NULL, NULL);
+ if (DBG_CLOCK)
+ log_clock ("leave signing");
+
if (err)
xfree (get_membuf (&data, NULL));
else
if (desc)
{
- snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SETKEYDESC %s", desc);
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
if (err)
return err;
err = assuan_transact (agent_ctx, "PKDECRYPT",
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
inq_ciphertext_cb, &parm,
padding_info_cb, r_padding);
xfree (parm.ciphertext);
buf = get_membuf (&data, &len);
if (!buf)
return gpg_error_from_syserror ();
- assert (len); /* (we forced Nul termination.) */
+ log_assert (len); /* (we forced Nul termination.) */
if (*buf != '(')
{
return err;
dfltparm.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,
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
default_inq_cb, &dfltparm,
NULL, NULL);
if (err)
/* Call the agent to import a key into the agent. */
gpg_error_t
agent_import_key (ctrl_t ctrl, const char *desc, char **cache_nonce_addr,
- const void *key, size_t keylen, int unattended)
+ const void *key, size_t keylen, int unattended, int force,
+ u32 *keyid, u32 *mainkeyid, int pubkey_algo)
{
gpg_error_t err;
struct import_key_parm_s parm;
memset (&dfltparm, 0, sizeof dfltparm);
dfltparm.ctrl = ctrl;
+ dfltparm.keyinfo.keyid = keyid;
+ dfltparm.keyinfo.mainkeyid = mainkeyid;
+ dfltparm.keyinfo.pubkey_algo = pubkey_algo;
err = start_agent (ctrl, 0);
if (err)
if (desc)
{
- snprintf (line, DIM(line)-1, "SETKEYDESC %s", desc);
- line[DIM(line)-1] = 0;
+ snprintf (line, DIM(line), "SETKEYDESC %s", desc);
err = assuan_transact (agent_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (err)
parm.key = key;
parm.keylen = keylen;
- snprintf (line, sizeof line, "IMPORT_KEY%s%s%s",
+ snprintf (line, sizeof line, "IMPORT_KEY%s%s%s%s",
unattended? " --unattended":"",
+ force? " --force":"",
cache_nonce_addr && *cache_nonce_addr? " ":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"");
cn_parm.cache_nonce_addr = cache_nonce_addr;
\f
/* Receive a secret key from the agent. HEXKEYGRIP is the hexified
keygrip, DESC a prompt to be displayed with the agent's passphrase
- question (needs to be plus+percent escaped). If CACHE_NONCE_ADDR
- is not NULL the agent is advised to first try a passphrase
- associated with that nonce. On success the key is stored as a
- canonical S-expression at R_RESULT and R_RESULTLEN. */
+ question (needs to be plus+percent escaped). if OPENPGP_PROTECTED
+ is not zero, ensure that the key material is returned in RFC
+ 4880-compatible passphrased-protected form. If CACHE_NONCE_ADDR is
+ not NULL the agent is advised to first try a passphrase associated
+ with that nonce. On success the key is stored as a canonical
+ S-expression at R_RESULT and R_RESULTLEN. */
gpg_error_t
agent_export_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
- char **cache_nonce_addr,
- unsigned char **r_result, size_t *r_resultlen)
+ int openpgp_protected, char **cache_nonce_addr,
+ unsigned char **r_result, size_t *r_resultlen,
+ u32 *keyid, u32 *mainkeyid, int pubkey_algo)
{
gpg_error_t err;
struct cache_nonce_parm_s cn_parm;
memset (&dfltparm, 0, sizeof dfltparm);
dfltparm.ctrl = ctrl;
+ dfltparm.keyinfo.keyid = keyid;
+ dfltparm.keyinfo.mainkeyid = mainkeyid;
+ dfltparm.keyinfo.pubkey_algo = pubkey_algo;
*r_result = NULL;
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 --openpgp %s%s %s",
+ snprintf (line, DIM(line), "EXPORT_KEY %s%s%s %s",
+ openpgp_protected ? "--openpgp ":"",
cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
hexkeygrip);
cn_parm.cache_nonce_addr = cache_nonce_addr;
cn_parm.passwd_nonce_addr = NULL;
err = assuan_transact (agent_ctx, line,
- membuf_data_cb, &data,
+ put_membuf_cb, &data,
default_inq_cb, &dfltparm,
cache_nonce_status_cb, &cn_parm);
if (err)
\f
/* Ask the agent to delete the key identified by HEXKEYGRIP. If DESC
is not NULL, display DESC instead of the default description
- message. */
+ message. If FORCE is true the agent is advised not to ask for
+ confirmation. */
gpg_error_t
-agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc)
+agent_delete_key (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+ int force)
{
gpg_error_t err;
char line[ASSUAN_LINELENGTH];
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, "DELETE_KEY %s", hexkeygrip);
+ snprintf (line, DIM(line), "DELETE_KEY%s %s",
+ force? " --force":"", hexkeygrip);
err = assuan_transact (agent_ctx, line, NULL, NULL,
default_inq_cb, &dfltparm,
NULL, NULL);
\f
/* Ask the agent to change the passphrase of the key identified by
- HEXKEYGRIP. If DESC is not NULL, display DESC instead of the
- default description message. If CACHE_NONCE_ADDR is not NULL the
- agent is advised to first try a passphrase associated with that
- nonce. If PASSWD_NONCE_ADDR is not NULL the agent will try to use
- the passphrase associated with that nonce. */
+ * HEXKEYGRIP. If DESC is not NULL, display DESC instead of the
+ * default description message. If CACHE_NONCE_ADDR is not NULL the
+ * agent is advised to first try a passphrase associated with that
+ * nonce. If PASSWD_NONCE_ADDR is not NULL the agent will try to use
+ * the passphrase associated with that nonce for the new passphrase.
+ * If VERIFY is true the passphrase is only verified. */
gpg_error_t
-agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc,
+agent_passwd (ctrl_t ctrl, const char *hexkeygrip, const char *desc, int verify,
char **cache_nonce_addr, char **passwd_nonce_addr)
{
gpg_error_t err;
if (!hexkeygrip || strlen (hexkeygrip) != 40)
return gpg_error (GPG_ERR_INV_VALUE);
-
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, "PASSWD %s%s %s%s %s",
- cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
- cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
- passwd_nonce_addr && *passwd_nonce_addr? "--passwd-nonce=":"",
- passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
- hexkeygrip);
+ if (verify)
+ snprintf (line, DIM(line), "PASSWD %s%s --verify %s",
+ cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+ cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+ hexkeygrip);
+ else
+ snprintf (line, DIM(line), "PASSWD %s%s %s%s %s",
+ cache_nonce_addr && *cache_nonce_addr? "--cache-nonce=":"",
+ cache_nonce_addr && *cache_nonce_addr? *cache_nonce_addr:"",
+ passwd_nonce_addr && *passwd_nonce_addr? "--passwd-nonce=":"",
+ passwd_nonce_addr && *passwd_nonce_addr? *passwd_nonce_addr:"",
+ hexkeygrip);
cn_parm.cache_nonce_addr = cache_nonce_addr;
cn_parm.passwd_nonce_addr = passwd_nonce_addr;
err = assuan_transact (agent_ctx, line, NULL, NULL,
return err;
}
+
/* Return the version reported by gpg-agent. */
gpg_error_t
agent_get_version (ctrl_t ctrl, char **r_version)
{
gpg_error_t err;
- membuf_t data;
err = start_agent (ctrl, 0);
if (err)
return err;
- init_membuf (&data, 64);
- err = assuan_transact (agent_ctx, "GETINFO version",
- membuf_data_cb, &data,
- NULL, NULL, NULL, NULL);
- if (err)
- {
- xfree (get_membuf (&data, NULL));
- *r_version = NULL;
- }
- else
- {
- put_membuf (&data, "", 1);
- *r_version = get_membuf (&data, NULL);
- if (!*r_version)
- err = gpg_error_from_syserror ();
- }
+ err = get_assuan_server_version (agent_ctx, 0, r_version);
return err;
}