From 874bc970ba6ec243ff474ef090242e0f7be6a7bc Mon Sep 17 00:00:00 2001 From: NIIBE Yutaka Date: Thu, 25 Apr 2019 14:49:49 +0900 Subject: [PATCH] scd: Add new command: KEYINFO. * scd/app-common.h (struct app_ctx_s): Add with_keygrip function. * scd/app-openpgp.c (do_with_keygrip): New. * scd/app.c (app_do_with_keygrip): New. * scd/command.c (cmd_keyinfo): New. (send_keyinfo): New. -- KEYGRIP_ACTION_LOOKUP is not yet used. It will be used for directly asking PK* action to determine an APP. Signed-off-by: NIIBE Yutaka --- scd/app-common.h | 10 +++++++ scd/app-openpgp.c | 54 +++++++++++++++++++++++++++++++++++ scd/app.c | 21 ++++++++++++++ scd/command.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++- scd/scdaemon.h | 2 ++ 5 files changed, 159 insertions(+), 1 deletion(-) diff --git a/scd/app-common.h b/scd/app-common.h index 6bb8eba50..8a25cda55 100644 --- a/scd/app-common.h +++ b/scd/app-common.h @@ -126,9 +126,18 @@ struct app_ctx_s { gpg_error_t (*check_pin) (app_t app, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); + int (*with_keygrip) (app_t app, ctrl_t ctrl, int action, + const char *keygrip_str); } fnc; }; +enum + { + KEYGRIP_ACTION_SEND_DATA, + KEYGRIP_ACTION_WRITE_STATUS, + KEYGRIP_ACTION_LOOKUP + }; + /*-- app-help.c --*/ unsigned int app_help_count_bits (const unsigned char *a, size_t len); gpg_error_t app_help_get_keygrip_string_pk (const void *pk, size_t pklen, @@ -206,6 +215,7 @@ gpg_error_t app_change_pin (app_t app, ctrl_t ctrl, gpg_error_t app_check_pin (app_t app, ctrl_t ctrl, const char *keyidstr, gpg_error_t (*pincb)(void*, const char *, char **), void *pincb_arg); +app_t app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str); /*-- app-openpgp.c --*/ diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 02d388695..c1c90350b 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -4945,6 +4945,59 @@ do_check_pin (app_t app, const char *keyidstr, return verify_chv2 (app, pincb, pincb_arg); } +static int +do_with_keygrip (app_t app, ctrl_t ctrl, int action, const char *keygrip_str) +{ + int i; + + if (action == KEYGRIP_ACTION_LOOKUP) + { + if (keygrip_str == NULL) + return 1; + + for (i = 0; i < 3; i++) + if (app->app_local->pk[i].read_done + && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str)) + return 0; /* Found */ + + return 1; + } + else + { + char idbuf[50]; + char buf[65]; + int data = (action == KEYGRIP_ACTION_SEND_DATA); + + if (DIM (buf) < 2 * app->serialnolen + 1) + return 0; + + bin2hex (app->serialno, app->serialnolen, buf); + + if (keygrip_str == NULL) + { + for (i = 0; i < 3; i++) + if (app->app_local->pk[i].read_done) + { + sprintf (idbuf, "OPENPGP.%d", i+1); + send_keyinfo (ctrl, data, + app->app_local->pk[i].keygrip_str,buf, idbuf); + } + } + else + { + for (i = 0; i < 3; i++) + if (app->app_local->pk[i].read_done + && !strcmp (keygrip_str, app->app_local->pk[i].keygrip_str)) + { + sprintf (idbuf, "OPENPGP.%d", i+1); + send_keyinfo (ctrl, data, keygrip_str, buf, idbuf); + return 0; + } + } + + return 1; + } +} /* Show information about card capabilities. */ static void @@ -5327,6 +5380,7 @@ app_select_openpgp (app_t app) app->fnc.decipher = do_decipher; app->fnc.change_pin = do_change_pin; app->fnc.check_pin = do_check_pin; + app->fnc.with_keygrip = do_with_keygrip; } leave: diff --git a/scd/app.c b/scd/app.c index 1f3808fd4..4fe60cbbb 100644 --- a/scd/app.c +++ b/scd/app.c @@ -1290,3 +1290,24 @@ app_send_card_list (ctrl_t ctrl) } npth_mutex_unlock (&app_list_lock); } + +/* Execute an action for each app. ACTION can be one of: + KEYGRIP_ACTION_SEND_DATA: send data if KEYGRIP_STR matches + KEYGRIP_ACTION_WRITE_STATUS: write status if KEYGRIP_STR matches + KEYGRIP_ACTION_LOOKUP: Return matching APP + */ +app_t +app_do_with_keygrip (ctrl_t ctrl, int action, const char *keygrip_str) +{ + app_t a; + + npth_mutex_lock (&app_list_lock); + + for (a = app_top; a; a = a->next) + if (a->fnc.with_keygrip + && !a->fnc.with_keygrip (a, ctrl, action, keygrip_str)) + break; + + npth_mutex_unlock (&app_list_lock); + return a; +} diff --git a/scd/command.c b/scd/command.c index 28c739d93..33e1985b3 100644 --- a/scd/command.c +++ b/scd/command.c @@ -424,7 +424,7 @@ cmd_learn (assuan_context_t ctx, char *line) serial = app_get_serialno (ctrl->app_ctx); if (!serial) - return gpg_error (GPG_ERR_INV_VALUE); + return gpg_error (GPG_ERR_INV_VALUE); rc = assuan_write_status (ctx, "SERIALNO", serial); if (rc < 0) @@ -1757,6 +1757,76 @@ cmd_killscd (assuan_context_t ctx, char *line) } +static const char hlp_keyinfo[] = + "KEYINFO [--list] [--data] \n" + "\n" + "Return information about the key specified by the KEYGRIP. If the\n" + "key is not available GPG_ERR_NOT_FOUND is returned. If the option\n" + "--list is given the keygrip is ignored and information about all\n" + "available keys are returned. Unless --data is given, the\n" + "information is returned as a status line using the format:\n" + "\n" + " KEYINFO T \n" + "\n" + "KEYGRIP is the keygrip.\n" + "\n" + "SERIALNO is an ASCII string with the serial number of the\n" + " smartcard. If the serial number is not known a single\n" + " dash '-' is used instead.\n" + "\n" + "IDSTR is the IDSTR used to distinguish keys on a smartcard. If it\n" + " is not known a dash is used instead.\n" + "\n" + "More information may be added in the future."; +static gpg_error_t +cmd_keyinfo (assuan_context_t ctx, char *line) +{ + int list_mode; + int opt_data; + int action; + char *keygrip_str; + ctrl_t ctrl = assuan_get_pointer (ctx); + + list_mode = has_option (line, "--list"); + opt_data = has_option (line, "--data"); + line = skip_options (line); + + if (list_mode) + keygrip_str = NULL; + else + keygrip_str = line; + + if (opt_data) + action = KEYGRIP_ACTION_SEND_DATA; + else + action = KEYGRIP_ACTION_WRITE_STATUS; + + app_do_with_keygrip (ctrl, action, keygrip_str); + + return 0; +} + +void +send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, + const char *serialno, const char *idstr) +{ + char *string; + assuan_context_t ctx = ctrl->server_local->assuan_ctx; + + string = xtryasprintf ("%s T %s %s\n", keygrip_str, + serialno? serialno : "-", + idstr? idstr : "-"); + if (!string) + return; + + if (!data) + assuan_write_status (ctx, "KEYINFO", string); + else + assuan_send_data (ctx, string, strlen (string)); + + xfree (string); + return; +} /* Tell the assuan library about our commands */ static int @@ -1792,6 +1862,7 @@ register_commands (assuan_context_t ctx) { "DISCONNECT", cmd_disconnect,hlp_disconnect }, { "APDU", cmd_apdu, hlp_apdu }, { "KILLSCD", cmd_killscd, hlp_killscd }, + { "KEYINFO", cmd_keyinfo, hlp_keyinfo }, { NULL } }; int i, rc; diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 73589ade8..230653b11 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -125,6 +125,8 @@ void send_status_info (ctrl_t ctrl, const char *keyword, ...) void send_status_direct (ctrl_t ctrl, const char *keyword, const char *args); gpg_error_t send_status_printf (ctrl_t ctrl, const char *keyword, const char *format, ...) GPGRT_ATTR_PRINTF(3,4); +void send_keyinfo (ctrl_t ctrl, int data, const char *keygrip_str, + const char *serialno, const char *idstr); void popup_prompt (void *opaque, int on); void send_client_notifications (app_t app, int removal);