From 4c74236dc766963e49eddb53a1802a3b9ce163d7 Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Mon, 20 Mar 2023 13:42:47 +0900 Subject: [PATCH] agent: Add TKD command support. Signed-off-by: NIIBE Yutaka --- agent/agent.h | 2 + agent/call-tkd.c | 130 ++++++++++++++++++++++++++++++++++++++++++++- agent/command.c | 48 +++++++++++++++++ agent/divert-tkd.c | 6 +++ 4 files changed, 185 insertions(+), 1 deletion(-) diff --git a/agent/agent.h b/agent/agent.h index 90a6d0d3f..ee3b74eee 100644 --- a/agent/agent.h +++ b/agent/agent.h @@ -672,6 +672,7 @@ gpg_error_t divert_writekey (ctrl_t ctrl, int force, const char *serialno, 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); @@ -748,6 +749,7 @@ int agent_tkd_pksign (ctrl_t ctrl, 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 index 44857ba89..e0c85e9eb 100644 --- a/agent/call-tkd.c +++ b/agent/call-tkd.c @@ -208,10 +208,10 @@ agent_tkd_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen, inqparm.ctx = daemon_ctx (ctrl); inqparm.getpin_cb = pin_cb; + inqparm.pin = NULL; inqparm.ctrl = ctrl; inqparm.extra = digest; inqparm.extralen = digestlen; - inqparm.pin = NULL; bin2hex (ctrl->keygrip, KEYGRIP_LEN, hexgrip); snprintf (line, sizeof(line), "PKSIGN %s %s", @@ -240,3 +240,131 @@ agent_tkd_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen, 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 1dc77b43e..59f81a9fa 100644 --- a/agent/command.c +++ b/agent/command.c @@ -2684,6 +2684,53 @@ cmd_scd (assuan_context_t ctx, char *line) } +static const char hlp_tkd[] = + "TKD \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] \n" @@ -4234,6 +4281,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 index c61bef240..3fd1872f1 100644 --- a/agent/divert-tkd.c +++ b/agent/divert-tkd.c @@ -37,3 +37,9 @@ divert_tkd_pksign (ctrl_t ctrl, const unsigned char *digest, size_t digestlen, { 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); +}