aboutsummaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
Diffstat (limited to 'agent')
-rw-r--r--agent/Makefile.am2
-rw-r--r--agent/agent.h13
-rw-r--r--agent/call-tkd.c370
-rw-r--r--agent/command.c80
-rw-r--r--agent/divert-tkd.c45
-rw-r--r--agent/findkey.c66
-rw-r--r--agent/gpg-agent.c6
-rw-r--r--agent/keyformat.txt12
-rw-r--r--agent/pksign.c4
-rw-r--r--agent/protect.c22
10 files changed, 586 insertions, 34 deletions
diff --git a/agent/Makefile.am b/agent/Makefile.am
index 4da1ea9d8..587aa7ae8 100644
--- a/agent/Makefile.am
+++ b/agent/Makefile.am
@@ -56,8 +56,10 @@ gpg_agent_SOURCES = \
protect.c \
trustlist.c \
divert-scd.c \
+ divert-tkd.c \
cvt-openpgp.c cvt-openpgp.h \
call-scd.c \
+ call-tkd.c \
call-daemon.c \
$(tpm2_sources) \
learncard.c
diff --git a/agent/agent.h b/agent/agent.h
index 4e7452eee..54076223d 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -60,6 +60,7 @@
enum daemon_type
{
DAEMON_SCD,
+ DAEMON_TKD,
DAEMON_TPM2D,
DAEMON_MAX_TYPE
};
@@ -660,6 +661,11 @@ int divert_generic_cmd (ctrl_t ctrl,
gpg_error_t divert_writekey (ctrl_t ctrl, int force, const char *serialno,
const char *keyref,
const char *keydata, size_t keydatalen);
+/*-- divert-tkd.c --*/
+int divert_tkd_pksign (ctrl_t ctrl,
+ const unsigned char *digest, size_t digestlen,
+ unsigned char **r_sig, size_t *r_siglen);
+int divert_tkd_cmd (ctrl_t ctrl, const char *cmdline);
/*-- call-daemon.c --*/
gpg_error_t daemon_start (enum daemon_type type, ctrl_t ctrl);
@@ -730,6 +736,13 @@ void agent_card_free_keyinfo (struct card_key_info_s *l);
gpg_error_t agent_card_keyinfo (ctrl_t ctrl, const char *keygrip,
int cap, struct card_key_info_s **result);
+/*-- call-tkd.c --*/
+int agent_tkd_pksign (ctrl_t ctrl,
+ const unsigned char *indata, size_t indatalen,
+ unsigned char **r_buf, size_t *r_buflen);
+int agent_tkd_readkey (ctrl_t ctrl, const char *keygrip,
+ unsigned char **r_buf, size_t *r_buflen);
+int agent_tkd_cmd (ctrl_t ctrl, const char *cmdline);
/*-- learncard.c --*/
int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);
diff --git a/agent/call-tkd.c b/agent/call-tkd.c
new file mode 100644
index 000000000..e0c85e9eb
--- /dev/null
+++ b/agent/call-tkd.c
@@ -0,0 +1,370 @@
+/* call-tkd.c - fork of the tkdaemon to do TK operations
+ * Copyright (C) 2001, 2002, 2005, 2007, 2010,
+ * 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2013 Werner Koch
+ *
+ * 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * 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 <https://www.gnu.org/licenses/>.
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "agent.h"
+#include <assuan.h>
+#include "../common/strlist.h"
+#include "../common/sexp-parse.h"
+#include "../common/i18n.h"
+
+static int
+start_tkd (ctrl_t ctrl)
+{
+ return daemon_start (DAEMON_TKD, ctrl);
+}
+
+static int
+unlock_tkd (ctrl_t ctrl, gpg_error_t err)
+{
+ return daemon_unlock (DAEMON_TKD, ctrl, err);
+}
+
+static assuan_context_t
+daemon_ctx (ctrl_t ctrl)
+{
+ return daemon_type_ctx (DAEMON_TKD, ctrl);
+}
+
+struct inq_parm_s {
+ assuan_context_t ctx;
+ gpg_error_t (*getpin_cb)(ctrl_t, const char *, char **);
+ ctrl_t ctrl;
+ /* The next fields are used by inq_keydata. */
+ const unsigned char *keydata;
+ size_t keydatalen;
+ /* following only used by inq_extra */
+ const unsigned char *extra;
+ size_t extralen;
+ char *pin;
+};
+
+static gpg_error_t
+inq_needpin (void *opaque, const char *line)
+{
+ struct inq_parm_s *parm = opaque;
+ char *pin = NULL;
+ gpg_error_t rc;
+ const char *s;
+
+ if ((s = has_leading_keyword (line, "NEEDPIN")))
+ {
+ rc = parm->getpin_cb (parm->ctrl, s, &pin);
+ if (!rc)
+ rc = assuan_send_data (parm->ctx, pin, strlen(pin));
+ parm->pin = pin;
+ }
+ else
+ {
+ log_error ("unsupported inquiry '%s'\n", line);
+ rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
+ }
+
+ return rc;
+}
+
+static gpg_error_t
+inq_extra (void *opaque, const char *line)
+{
+ struct inq_parm_s *parm = opaque;
+
+ if (has_leading_keyword (line, "EXTRA"))
+ return assuan_send_data (parm->ctx, parm->extra, parm->extralen);
+ else
+ return inq_needpin (opaque, line);
+}
+
+static gpg_error_t
+pin_cb (ctrl_t ctrl, const char *prompt, char **passphrase)
+{
+ char hexgrip[2*KEYGRIP_LEN + 1];
+
+ bin2hex (ctrl->keygrip, KEYGRIP_LEN, hexgrip);
+ *passphrase = agent_get_cache (ctrl, hexgrip, CACHE_MODE_USER);
+ if (*passphrase)
+ return 0;
+ return agent_get_passphrase (ctrl, passphrase,
+ _("Please enter your passphrase, so that the "
+ "secret key can be unlocked for this session"),
+ prompt, NULL, 0,
+ hexgrip, CACHE_MODE_USER, NULL);
+}
+
+/* Read a key with KEYGRIP and return it in a malloced buffer pointed
+ * to by R_BUF as a valid S-expression. If R_BUFLEN is not NULL the
+ * length is stored there. */
+int
+agent_tkd_readkey (ctrl_t ctrl, const char *keygrip,
+ unsigned char **r_buf, size_t *r_buflen)
+{
+ int rc;
+ char line[ASSUAN_LINELENGTH];
+ membuf_t data;
+ size_t buflen;
+ struct inq_parm_s inqparm;
+
+ *r_buf = NULL;
+ if (r_buflen)
+ *r_buflen = 0;
+
+ rc = start_tkd (ctrl);
+ if (rc)
+ return rc;
+
+ init_membuf (&data, 1024);
+
+ inqparm.ctx = daemon_ctx (ctrl);
+ inqparm.getpin_cb = pin_cb;
+ inqparm.ctrl = ctrl;
+ inqparm.pin = NULL;
+
+ snprintf (line, DIM(line), "READKEY %s", keygrip);
+ rc = assuan_transact (daemon_ctx (ctrl), line,
+ put_membuf_cb, &data,
+ inq_needpin, &inqparm,
+ NULL, NULL);
+ if (rc)
+ {
+ xfree (get_membuf (&data, &buflen));
+ return unlock_tkd (ctrl, rc);
+ }
+ *r_buf = get_membuf (&data, &buflen);
+ if (!*r_buf)
+ return unlock_tkd (ctrl, gpg_error (GPG_ERR_ENOMEM));
+
+ if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL))
+ {
+ xfree (*r_buf); *r_buf = NULL;
+ return unlock_tkd (ctrl, gpg_error (GPG_ERR_INV_VALUE));
+ }
+ if (r_buflen)
+ *r_buflen = buflen;
+
+ return unlock_tkd (ctrl, 0);
+}
+
+
+/* Helper returning a command option to describe the used hash
+ algorithm. See scd/command.c:cmd_pksign. */
+static const char *
+hash_algo_option (int algo)
+{
+ switch (algo)
+ {
+ case GCRY_MD_MD5 : return "--hash=md5";
+ case GCRY_MD_RMD160: return "--hash=rmd160";
+ case GCRY_MD_SHA1 : return "--hash=sha1";
+ case GCRY_MD_SHA224: return "--hash=sha224";
+ case GCRY_MD_SHA256: return "--hash=sha256";
+ case GCRY_MD_SHA384: return "--hash=sha384";
+ case GCRY_MD_SHA512: return "--hash=sha512";
+ default: return "";
+ }
+}
+
+
+int
+agent_tkd_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen,
+ unsigned char **r_sig, size_t *r_siglen)
+{
+ int rc;
+ char line[ASSUAN_LINELENGTH];
+ membuf_t data;
+ struct inq_parm_s inqparm;
+ char hexgrip[2*KEYGRIP_LEN + 1];
+
+ rc = start_tkd (ctrl);
+ if (rc)
+ return rc;
+
+ init_membuf (&data, 1024);
+
+ inqparm.ctx = daemon_ctx (ctrl);
+ inqparm.getpin_cb = pin_cb;
+ inqparm.pin = NULL;
+ inqparm.ctrl = ctrl;
+ inqparm.extra = digest;
+ inqparm.extralen = digestlen;
+
+ bin2hex (ctrl->keygrip, KEYGRIP_LEN, hexgrip);
+ snprintf (line, sizeof(line), "PKSIGN %s %s",
+ hash_algo_option (ctrl->digest.algo), hexgrip);
+
+ rc = assuan_transact (daemon_ctx (ctrl), line,
+ put_membuf_cb, &data,
+ inq_extra, &inqparm,
+ NULL, NULL);
+ if (!rc)
+ {
+ bin2hex (ctrl->keygrip, KEYGRIP_LEN, hexgrip);
+ agent_put_cache (ctrl, hexgrip, CACHE_MODE_USER, inqparm.pin, 0);
+ }
+
+ xfree (inqparm.pin);
+
+ if (rc)
+ {
+ size_t len;
+ xfree (get_membuf (&data, &len));
+ return unlock_tkd (ctrl, rc);
+ }
+
+ *r_sig = get_membuf (&data, r_siglen);
+
+ return unlock_tkd (ctrl, 0);
+}
+
+/* This handler is a helper for pincache_put_cb but may also be called
+ * directly for that status code with ARGS being the arguments after
+ * the status keyword (and with white space removed). */
+static gpg_error_t
+handle_pincache_put (const char *args)
+{
+ gpg_error_t err;
+ const char *s, *key, *pin;
+ char *keybuf = NULL;
+ size_t keylen;
+
+ key = s = args;
+ while (*s && !spacep (s))
+ s++;
+ keylen = s - key;
+ if (keylen < 3)
+ {
+ /* At least we need 2 slashes and slot number. */
+ log_error ("%s: ignoring invalid key\n", __func__);
+ err = 0;
+ goto leave;
+ }
+
+ keybuf = xtrymalloc (keylen+1);
+ if (!keybuf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ memcpy (keybuf, key, keylen);
+ keybuf[keylen] = 0;
+ key = keybuf;
+
+ while (spacep (s))
+ s++;
+ pin = s;
+ if (!*pin)
+ {
+ /* No value - flush the cache. The cache module knows aboput
+ * the structure of the key to flush only parts. */
+ log_debug ("%s: flushing cache '%s'\n", __func__, key);
+ agent_put_cache (NULL, key, CACHE_MODE_PIN, NULL, -1);
+ err = 0;
+ goto leave;
+ }
+
+ log_debug ("%s: caching '%s'->'%s'\n", __func__, key, pin);
+ agent_put_cache (NULL, key, CACHE_MODE_PIN, pin, -1);
+ err = 0;
+
+ leave:
+ xfree (keybuf);
+ return err;
+}
+
+static gpg_error_t
+pass_status_thru (void *opaque, const char *line)
+{
+ gpg_error_t err = 0;
+ assuan_context_t ctx = opaque;
+ char keyword[200];
+ int i;
+
+ if (line[0] == '#' && (!line[1] || spacep (line+1)))
+ {
+ /* We are called in convey comments mode. Now, if we see a
+ comment marker as keyword we forward the line verbatim to the
+ the caller. This way the comment lines from scdaemon won't
+ appear as status lines with keyword '#'. */
+ assuan_write_line (ctx, line);
+ }
+ else
+ {
+ for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
+ keyword[i] = *line;
+ keyword[i] = 0;
+
+ /* Truncate any remaining keyword stuff. */
+ for (; *line && !spacep (line); line++)
+ ;
+ while (spacep (line))
+ line++;
+
+ /* We do not want to pass PINCACHE_PUT through. */
+ if (!strcmp (keyword, "PINCACHE_PUT"))
+ err = handle_pincache_put (line);
+ else
+ assuan_write_status (ctx, keyword, line);
+ }
+ return err;
+}
+
+static gpg_error_t
+pass_data_thru (void *opaque, const void *buffer, size_t length)
+{
+ assuan_context_t ctx = opaque;
+
+ assuan_send_data (ctx, buffer, length);
+ return 0;
+}
+
+int
+agent_tkd_cmd (ctrl_t ctrl, const char *cmdline)
+{
+ int rc;
+ struct inq_parm_s inqparm;
+ int saveflag;
+
+ rc = start_tkd (ctrl);
+ if (rc)
+ return rc;
+
+ inqparm.ctx = daemon_ctx (ctrl);
+ inqparm.getpin_cb = pin_cb;
+ inqparm.pin = NULL;
+
+ saveflag = assuan_get_flag (daemon_ctx (ctrl), ASSUAN_CONVEY_COMMENTS);
+ assuan_set_flag (daemon_ctx (ctrl), ASSUAN_CONVEY_COMMENTS, 1);
+ rc = assuan_transact (daemon_ctx (ctrl), cmdline,
+ pass_data_thru, daemon_ctx (ctrl),
+ inq_needpin, &inqparm,
+ pass_status_thru, daemon_ctx (ctrl));
+
+ assuan_set_flag (daemon_ctx (ctrl), ASSUAN_CONVEY_COMMENTS, saveflag);
+
+ return unlock_tkd (ctrl, rc);
+}
diff --git a/agent/command.c b/agent/command.c
index 2e996d096..9351ef615 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -1297,6 +1297,7 @@ cmd_keyattr (assuan_context_t ctx, char *line)
static const char hlp_readkey[] =
"READKEY [--no-data] [--format=ssh] <hexstring_with_keygrip>\n"
" --card <keyid>\n"
+ " --token <hexstring_with_keygrip>\n"
"\n"
"Return the public key for the given keygrip or keyid.\n"
"With --card, private key file with card information will be created.";
@@ -1309,13 +1310,14 @@ cmd_readkey (assuan_context_t ctx, char *line)
gcry_sexp_t s_pkey = NULL;
unsigned char *pkbuf = NULL;
size_t pkbuflen;
- int opt_card, opt_no_data, opt_format_ssh;
+ int opt_card, opt_token, opt_no_data, opt_format_ssh;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
opt_no_data = has_option (line, "--no-data");
opt_card = has_option (line, "--card");
+ opt_token = has_option (line, "--token");
opt_format_ssh = has_option (line, "--format=ssh");
line = skip_options (line);
@@ -1367,6 +1369,34 @@ cmd_readkey (assuan_context_t ctx, char *line)
xfree (serialno);
xfree (keyidbuf);
}
+ else if (opt_token)
+ {
+ const char *keygrip = line;
+
+ rc = agent_tkd_readkey (ctrl, keygrip, &pkbuf, &pkbuflen);
+ if (rc)
+ goto leave;
+ rc = gcry_sexp_sscan (&s_pkey, NULL, (char*)pkbuf, pkbuflen);
+ if (rc)
+ goto leave;
+
+ if (!gcry_pk_get_keygrip (s_pkey, grip))
+ {
+ rc = gcry_pk_testkey (s_pkey);
+ if (rc == 0)
+ rc = gpg_error (GPG_ERR_INTERNAL);
+
+ goto leave;
+ }
+
+ if (agent_key_available (grip))
+ {
+ /* (Shadow)-key is not available in our key storage. */
+ rc = agent_write_shadow_key (grip, NULL, NULL, pkbuf, 0);
+ if (rc)
+ goto leave;
+ }
+ }
else
{
rc = parse_keygrip (ctx, line, grip);
@@ -2648,6 +2678,53 @@ cmd_scd (assuan_context_t ctx, char *line)
}
+static const char hlp_tkd[] =
+ "TKD <commands to pass to the tkdaemon>\n"
+ " \n"
+ "This is a general quote command to redirect everything to the\n"
+ "TKdaemon.";
+static gpg_error_t
+cmd_tkd (assuan_context_t ctx, char *line)
+{
+ int rc;
+#ifdef BUILD_WITH_TKDAEMON
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+
+ if (ctrl->restricted)
+ {
+ const char *argv[5];
+ int argc;
+ char *l;
+
+ l = xtrystrdup (line);
+ if (!l)
+ return gpg_error_from_syserror ();
+
+ argc = split_fields (l, argv, DIM (argv));
+
+ /* These commands are allowed. */
+ if ((argc >= 1 && !strcmp (argv[0], "SLOTLIST"))
+ || (argc == 2
+ && !strcmp (argv[0], "GETINFO")
+ && !strcmp (argv[1], "version"))
+ || (argc == 2
+ && !strcmp (argv[0], "KEYINFO")
+ && !strcmp (argv[1], "--list=encr")))
+ xfree (l);
+ else
+ {
+ xfree (l);
+ return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
+ }
+ }
+
+ rc = divert_tkd_cmd (ctrl, line);
+#else
+ (void)ctx; (void)line;
+ rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
+#endif
+ return rc;
+}
static const char hlp_keywrap_key[] =
"KEYWRAP_KEY [--clear] <mode>\n"
@@ -4198,6 +4275,7 @@ register_commands (assuan_context_t ctx)
{ "INPUT", NULL },
{ "OUTPUT", NULL },
{ "SCD", cmd_scd, hlp_scd },
+ { "TKD", cmd_tkd, hlp_tkd },
{ "KEYWRAP_KEY", cmd_keywrap_key, hlp_keywrap_key },
{ "IMPORT_KEY", cmd_import_key, hlp_import_key },
{ "EXPORT_KEY", cmd_export_key, hlp_export_key },
diff --git a/agent/divert-tkd.c b/agent/divert-tkd.c
new file mode 100644
index 000000000..3fd1872f1
--- /dev/null
+++ b/agent/divert-tkd.c
@@ -0,0 +1,45 @@
+/* divert-tkd.c - divert operations to the tkdaemon
+ * Copyright (C) 2002, 2003, 2009 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 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * 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 <https://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include "agent.h"
+#include "../common/i18n.h"
+#include "../common/sexp-parse.h"
+
+int
+divert_tkd_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen,
+ unsigned char **r_sig, size_t *r_siglen)
+{
+ return agent_tkd_pksign (ctrl, digest, digestlen, r_sig, r_siglen);
+}
+
+int
+divert_tkd_cmd (ctrl_t ctrl, const char *cmdline)
+{
+ return agent_tkd_cmd (ctrl, cmdline);
+}
diff --git a/agent/findkey.c b/agent/findkey.c
index 098d5224f..3544764d0 100644
--- a/agent/findkey.c
+++ b/agent/findkey.c
@@ -1309,24 +1309,36 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
err = agent_get_shadow_info_type (buf, &s, &shadow_type);
if (!err)
{
- n = gcry_sexp_canon_len (s, 0, NULL,NULL);
- log_assert (n);
- *shadow_info = xtrymalloc (n);
- if (!*shadow_info)
+ if (!s)
{
- err = out_of_core ();
- goto shadow_error;
+ *shadow_info = xstrdup ("tkd");
+ if (!*shadow_info)
+ {
+ err = out_of_core ();
+ goto shadow_error;
+ }
}
else
{
- memcpy (*shadow_info, s, n);
- /*
- * When it's a key on card (not on tpm2), maks sure
- * it's available.
- */
- if (strcmp (shadow_type, "t1-v1") == 0 && !grip)
- err = prompt_for_card (ctrl, ctrl->keygrip,
- keymeta, *shadow_info);
+ n = gcry_sexp_canon_len (s, 0, NULL,NULL);
+ log_assert (n);
+ *shadow_info = xtrymalloc (n);
+ if (!*shadow_info)
+ {
+ err = out_of_core ();
+ goto shadow_error;
+ }
+ else
+ {
+ memcpy (*shadow_info, s, n);
+ /*
+ * When it's a key on card (not on tpm2), make sure
+ * it's available.
+ */
+ if (strcmp (shadow_type, "t1-v1") == 0 && !grip)
+ err = prompt_for_card (ctrl, ctrl->keygrip,
+ keymeta, *shadow_info);
+ }
}
}
else
@@ -1801,16 +1813,22 @@ agent_write_shadow_key (const unsigned char *grip,
unsigned char *shdkey;
size_t len;
- /* Just in case some caller did not parse the stuff correctly, skip
- * leading spaces. */
- while (spacep (serialno))
- serialno++;
- while (spacep (keyid))
- keyid++;
-
- shadow_info = make_shadow_info (serialno, keyid);
- if (!shadow_info)
- return gpg_error_from_syserror ();
+ if (serialno == NULL && keyid == NULL)
+ /* It's a token, identified by the keygrip. */
+ shadow_info = NULL;
+ else
+ {
+ /* Just in case some caller did not parse the stuff correctly, skip
+ * leading spaces. */
+ while (spacep (serialno))
+ serialno++;
+ while (spacep (keyid))
+ keyid++;
+
+ shadow_info = make_shadow_info (serialno, keyid);
+ if (!shadow_info)
+ return gpg_error_from_syserror ();
+ }
err = agent_shadow_key (pkbuf, shadow_info, &shdkey);
xfree (shadow_info);
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 1db422737..11815b4b5 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -104,6 +104,7 @@ enum cmd_and_opt_values
oLCmessages,
oXauthority,
oScdaemonProgram,
+ oTkdaemonProgram,
oTpm2daemonProgram,
oDefCacheTTL,
oDefCacheTTLSSH,
@@ -207,6 +208,8 @@ static gpgrt_opt_t opts[] = {
/* */ N_("do not use the SCdaemon") ),
ARGPARSE_s_s (oScdaemonProgram, "scdaemon-program",
/* */ N_("|PGM|use PGM as the SCdaemon program") ),
+ ARGPARSE_s_s (oTkdaemonProgram, "tkdaemon-program",
+ /* */ N_("|PGM|use PGM as the TKdaemon program") ),
ARGPARSE_s_s (oTpm2daemonProgram, "tpm2daemon-program",
/* */ N_("|PGM|use PGM as the tpm2daemon program") ),
ARGPARSE_s_n (oDisableCheckOwnSocket, "disable-check-own-socket", "@"),
@@ -942,6 +945,9 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
case oScdaemonProgram:
opt.daemon_program[DAEMON_SCD] = pargs->r.ret_str;
break;
+ case oTkdaemonProgram:
+ opt.daemon_program[DAEMON_TKD] = pargs->r.ret_str;
+ break;
case oDisableScdaemon: opt.disable_daemon[DAEMON_SCD] = 1; break;
case oDisableCheckOwnSocket: disable_check_own_socket = 1; break;
diff --git a/agent/keyformat.txt b/agent/keyformat.txt
index bbcaa7e2c..b8b814f88 100644
--- a/agent/keyformat.txt
+++ b/agent/keyformat.txt
@@ -342,9 +342,11 @@ to keys stored on a token:
(comment whatever)
)
-The currently used protocols are "t1-v1" (token info version 1) and
-"tpm2-v1" (TPM format key information). The second list with the
-information has this layout for "t1-v1":
+The currently used protocols are "t1-v1" (token info version 1),
+"tpm2-v1" (TPM format key information), and "tkd-v1" (token daemon
+info version 1).
+
+The second list with the information has this layout for "t1-v1":
(card_serial_number id_string_of_key fixed_pin_length)
@@ -353,13 +355,15 @@ the PIN; a value of 0 indicates that this information is not
available. The rationale for this field is that some pinpad equipped
readers don't allow passing a variable length PIN.
-This is the (info) layout for "tpm2-v1":
+For "tpm2-v1", the layout of the (info) is:
(parent tpm_private_string tpm_public_string)
Although this precise format is encapsulated inside the tpm2daemon
itself and nothing in gpg ever uses this.
+For "tkd-v1", the layout of the (info) part is nothing.
+
More items may be added to the list.
** OpenPGP Private Key Transfer Format
diff --git a/agent/pksign.c b/agent/pksign.c
index dfed0e398..1ee278aac 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -392,7 +392,9 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
}
{
- if (agent_is_tpm2_key (s_skey))
+ if (!strcmp (shadow_info, "tkd"))
+ err = divert_tkd_pksign (ctrl, data, datalen, &buf, &len);
+ else if (agent_is_tpm2_key (s_skey))
err = divert_tpm2_pksign (ctrl,
data, datalen,
ctrl->digest.algo,
diff --git a/agent/protect.c b/agent/protect.c
index 7197cf7e6..a40be0f9a 100644
--- a/agent/protect.c
+++ b/agent/protect.c
@@ -1477,10 +1477,15 @@ agent_shadow_key_type (const unsigned char *pubkey,
int depth = 0;
char *p;
size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL);
- size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL);
+ size_t shadow_info_len;
- if (!pubkey_len || !shadow_info_len)
+ if (!pubkey_len)
return gpg_error (GPG_ERR_INV_VALUE);
+ if (shadow_info)
+ shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL);
+ else
+ shadow_info_len = 0;
+
s = pubkey;
if (*s != '(')
return gpg_error (GPG_ERR_INV_SEXP);
@@ -1536,7 +1541,8 @@ agent_shadow_key_type (const unsigned char *pubkey,
memcpy (p, pubkey+14, point - (pubkey+14));
p += point - (pubkey+14);
p += sprintf (p, "(8:shadowed%d:%s", (int)strlen(type), type);
- memcpy (p, shadow_info, shadow_info_len);
+ if (shadow_info_len)
+ memcpy (p, shadow_info, shadow_info_len);
p += shadow_info_len;
*p++ = ')';
memcpy (p, point, pubkey_len - (point - pubkey));
@@ -1550,7 +1556,10 @@ agent_shadow_key (const unsigned char *pubkey,
const unsigned char *shadow_info,
unsigned char **result)
{
- return agent_shadow_key_type (pubkey, shadow_info, "t1-v1", result);
+ if (shadow_info)
+ return agent_shadow_key_type (pubkey, shadow_info, "t1-v1", result);
+ else
+ return agent_shadow_key_type (pubkey, NULL, "tkd-v1", result);
}
/* Parse a canonical encoded shadowed key and return a pointer to the
@@ -1620,6 +1629,11 @@ agent_get_shadow_info_type (const unsigned char *shadowkey,
if (shadow_info)
*shadow_info = s;
}
+ else if (smatch(&s, n, "tkd-v1"))
+ {
+ if (shadow_info)
+ *shadow_info = NULL;
+ }
else
return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
s = saved_s;