diff options
| author | NIIBE Yutaka <[email protected]> | 2026-10-23 07:58:08 +0200 |
|---|---|---|
| committer | NIIBE Yutaka <[email protected]> | 2026-10-23 07:58:08 +0200 |
| commit | facf699862fa48e2a539894990b02bdb9427f4df (patch) | |
| tree | fb5a2f375a4124a3da2dd0e41ee139e3cb73a632 | |
| parent | gpg: Fix colon listing for ietf25 and ietf27 curves. (diff) | |
| download | gnupg-facf699862fa48e2a539894990b02bdb9427f4df.tar.gz gnupg-facf699862fa48e2a539894990b02bdb9427f4df.zip | |
scd: Add askpin_inquiry for app-openpgp, not enabled for now.
* scd/app-openpgp.c (struct verify_info): New.
(pincheck_cb): New.
(USE_ASKPIN_INQUIR): Please enable this macro when ready.
(verify_a_chv): Use pincheck_cb.
[USE_ASKPIN_INQUIR] (verify_a_chv): Use askpin_inquiry.
* scd/command.c (askpin_inquiry): New.
* scd/scdaemon.h (askpin_inquiry): New.
--
GnuPG-bug-id: 8353
Signed-off-by: NIIBE Yutaka <[email protected]>
| -rw-r--r-- | scd/app-openpgp.c | 206 | ||||
| -rw-r--r-- | scd/command.c | 69 | ||||
| -rw-r--r-- | scd/scdaemon.h | 3 |
3 files changed, 196 insertions, 82 deletions
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 6b5008b09..b60f535b2 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -2756,6 +2756,112 @@ build_enter_pin_prompt (app_t app, int chvno, const char *firstline, } +struct verify_info { + app_t app; + ctrl_t ctrl; + int chvno; + int minlen; + int sync_chv; +}; + +static gpg_error_t +pincheck_cb (void *arg, const char *pin) +{ + struct verify_info *v = arg; + gpg_error_t err = 0; + char *pinvalue = NULL; + size_t pinvaluelen = 0; + + if (strlen (pin) < v->minlen) + { + log_error (_("PIN for CHV%d is too short;" + " minimum length is %d\n"), v->chvno, v->minlen); + err = gpg_error (GPG_ERR_BAD_PIN); + goto leave; + } + + err = pin2hash_if_kdf (v->app, v->chvno, pin, &pinvalue, &pinvaluelen); + if (!err) + err = iso7816_verify (app_get_slot (v->app), 0x80 + v->chvno, + pinvalue, pinvaluelen); + if (!err) + cache_pin (v->app, v->ctrl, v->chvno, pin); + else + { + log_error (_("verify CHV%d failed: %s\n"), v->chvno, gpg_strerror (err)); + flush_cache_after_error (v->app); + goto leave; + } + + if (v->sync_chv) + { + app_t app = v->app; + ctrl_t ctrl = v->ctrl; + + if (v->chvno == 1) + { + app->did_chv1 = 1; + /* For cards with versions < 2 we want to keep CHV1 and CHV2 in + sync, thus we verify CHV2 here using the given PIN. Cards + with version2 to not have the need for a separate CHV2 and + internally use just one. Obviously we can't do that if the + pinpad has been used. */ + if (!app->did_chv2 && pinvalue && !app->app_local->extcap.is_v2) + { + err = iso7816_verify (app_get_slot (app), 0x82, + pinvalue, pinvaluelen); + if (gpg_err_code (err) == GPG_ERR_BAD_PIN) + err = gpg_error (GPG_ERR_PIN_NOT_SYNCED); + if (err) + { + log_error (_("verify CHV%d failed: %s\n"), 2, + gpg_strerror (err)); + flush_cache_after_error (app); + } + else + { + app->did_chv2 = 1; + cache_pin (app, ctrl, 2, pin); + } + } + } + else if (v->chvno == 2) + { + app->did_chv2 = 1; + if (!app->did_chv1 && !app->force_chv1 + && pinvalue && !opt.pcsc_shared) + { + /* For convenience we verify CHV1 here too. We do this only if + the card is not configured to require a verification before + each CHV1 controlled operation (force_chv1) and if we are not + using the pinpad (PINVALUE == NULL). */ + err = iso7816_verify (app_get_slot (app), 0x81, + pinvalue, pinvaluelen); + if (gpg_err_code (err) == GPG_ERR_BAD_PIN) + err = gpg_error (GPG_ERR_PIN_NOT_SYNCED); + if (err) + { + log_error (_("verify CHV%d failed: %s\n"), 1, + gpg_strerror (err)); + flush_cache_after_error (app); + } + else + { + app->did_chv1 = 1; + cache_pin (app, ctrl, 1, pin); + } + } + } + } + + leave: + wipe_and_free (pinvalue, pinvaluelen); + + return err; +} + + +#undef USE_ASKPIN_INQUIRY /* <-- Remove this macro when ready. */ /* Verify a CHV either using the pinentry or if possible by using a pinpad. CHVNO must be either 1 or 2. SIGCOUNT is only used with CHV1. PINVALUE is the address of a pointer which will receive a @@ -2777,9 +2883,8 @@ verify_a_chv (app_t app, ctrl_t ctrl, int minlen = 6; int remaining; const char *firstline = _("||Please unlock the card"); - char *pinvalue = NULL; - size_t pinlen = 0; char *pin = NULL; + struct verify_info v; log_assert (chvno == 1 || chvno == 2); @@ -2843,92 +2948,29 @@ verify_a_chv (app_t app, ctrl_t ctrl, * get the PIN from the cache. With less remaining tries it is * better to let the user know about failed attempts (which * might be due to a bug in the PIN cache handling). */ + v.app = app; + v.ctrl = ctrl; + v.chvno = chvno; + v.minlen = minlen; + v.sync_chv = sync_chv; + if (remaining >= 3 && pin_from_cache (app, ctrl, chvno, &pin)) - rc = 0; + rc = pincheck_cb (&v, pin); else - rc = askpin (ctrl, prompt, &pin); - xfree (prompt); - prompt = NULL; - if (rc) { - log_info (_("askpin returned error: %s\n"), gpg_strerror (rc)); - return rc; - } - - if (strlen (pin) < minlen) - { - log_error (_("PIN for CHV%d is too short;" - " minimum length is %d\n"), chvno, minlen); - wipe_and_free_string (pin); - return gpg_error (GPG_ERR_BAD_PIN); +#ifdef USE_ASKPIN_INQUIRY + rc = askpin_inquiry (ctrl, prompt, pincheck_cb, &v); +#else + rc = askpin (ctrl, prompt, &pin); + if (!rc) + rc = pincheck_cb (&v, pin); +#endif } - - rc = pin2hash_if_kdf (app, chvno, pin, &pinvalue, &pinlen); - if (!rc) - rc = iso7816_verify (app_get_slot (app), - 0x80 + chvno, pinvalue, pinlen); - if (!rc) - cache_pin (app, ctrl, chvno, pin); - + xfree (prompt); + prompt = NULL; if (rc) - { - log_error (_("verify CHV%d failed: %s\n"), chvno, gpg_strerror (rc)); - flush_cache_after_error (app); - } - else if (sync_chv) - { - if (chvno == 1) - { - app->did_chv1 = 1; - /* For cards with versions < 2 we want to keep CHV1 and CHV2 in - sync, thus we verify CHV2 here using the given PIN. Cards - with version2 to not have the need for a separate CHV2 and - internally use just one. Obviously we can't do that if the - pinpad has been used. */ - if (!app->did_chv2 && pinvalue && !app->app_local->extcap.is_v2) - { - rc = iso7816_verify (app_get_slot (app), 0x82, pinvalue, pinlen); - if (gpg_err_code (rc) == GPG_ERR_BAD_PIN) - rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); - if (rc) - { - log_error (_("verify CHV%d failed: %s\n"), 2, gpg_strerror (rc)); - flush_cache_after_error (app); - } - else - { - app->did_chv2 = 1; - cache_pin (app, ctrl, 2, pin); - } - } - } - else if (chvno == 2) - { - app->did_chv2 = 1; - if (!app->did_chv1 && !app->force_chv1 && pinvalue && !opt.pcsc_shared) - { - /* For convenience we verify CHV1 here too. We do this only if - the card is not configured to require a verification before - each CHV1 controlled operation (force_chv1) and if we are not - using the pinpad (PINVALUE == NULL). */ - rc = iso7816_verify (app_get_slot (app), 0x81, pinvalue, pinlen); - if (gpg_err_code (rc) == GPG_ERR_BAD_PIN) - rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED); - if (rc) - { - log_error (_("verify CHV%d failed: %s\n"), 1, gpg_strerror (rc)); - flush_cache_after_error (app); - } - else - { - app->did_chv1 = 1; - cache_pin (app, ctrl, 1, pin); - } - } - } - } + log_info ("askpin_inquiry returned error: %s\n", gpg_strerror (rc)); wipe_and_free_string (pin); - wipe_and_free (pinvalue, pinlen); return rc; } diff --git a/scd/command.c b/scd/command.c index 1f1fc3953..68371bd8c 100644 --- a/scd/command.c +++ b/scd/command.c @@ -1044,6 +1044,75 @@ askpin (ctrl_t ctrl, const char *info, char **retstr) } +gpg_error_t +askpin_inquiry (ctrl_t ctrl, const char *info, + gpg_error_t (*check_cb) (void *arg, const char *pin), + void *check_cb_arg) +{ + gpg_error_t err; + assuan_context_t ctx = ctrl->server_local->assuan_ctx; + char *command; + int rc; + unsigned char *value = NULL; + size_t valuelen = 0; + + if (DBG_IPC) + log_debug ("asking for PIN '%s'\n", info); + + rc = gpgrt_asprintf (&command, "ASKPIN %s", info); + if (rc < 0) + return gpg_error (gpg_err_code_from_errno (errno)); + + /* See the comment in askpin for use of secure memory. */ + assuan_begin_confidential (ctx); + err = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN); + assuan_end_confidential (ctx); + xfree (command); + if (err) + return err; + + while (1) + { + /* We require that the returned value is an UTF-8 string */ + if (!value || !valuelen || value[valuelen-1]) + { + xfree (value); + assuan_inquire (ctx, "FINISHPIN", NULL, NULL, 0); + /* The error from assuan_inquire swallowed if any.*/ + return gpg_error (GPG_ERR_INV_RESPONSE); + } + + err = (*check_cb) (check_cb_arg, (const char *)value); + wipememory (value, valuelen); + xfree (value); + value = NULL; + valuelen = 0; + if (!err) + { + /* Authentication succeed. */ + err = assuan_inquire (ctx, "FINISHPIN", NULL, NULL, 0); + break; + } + else if (gpg_err_code (err) != GPG_ERR_BAD_PIN) + { + /* Something goes wrong. */ + assuan_inquire (ctx, "FINISHPIN", NULL, NULL, 0); + /* The error from assuan_inquire swallowed if any.*/ + return err; + } + + /* Here, it means check_cb returned GPG_ERR_BAD_PIN. */ + assuan_begin_confidential (ctx); + err = assuan_inquire (ctx, "NEXTPIN", &value, &valuelen, MAXLEN_PIN); + assuan_end_confidential (ctx); + if (err) + return err; + } + + return err; +} + + static const char hlp_pksign[] = "PKSIGN [--hash=[rmd160|sha{1,224,256,384,512}|md5|none]] <hexified_id>\n" "\n" diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 2b3c4d2c3..424ca031a 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -164,6 +164,9 @@ gpg_error_t pincache_get (ctrl_t ctrl, int slot, const char *appname, void popup_prompt (void *opaque, int on); gpg_error_t askpin (ctrl_t ctrl, const char *info, char **retstr); +gpg_error_t askpin_inquiry (ctrl_t ctrl, const char *info, + gpg_error_t (*check_cb) (void *arg, const char *pin), + void *check_cb_arg); gpg_error_t pinpad_prompt (ctrl_t ctrl, const char *info); |
