verify_a_chv (app_t app,
              gpg_error_t (*pincb)(void*, const char *, char **),
              void *pincb_arg,
              int chvno, unsigned long sigcount, char **pinvalue)
{
  int rc = 0;
  char *prompt_buffer = NULL;
  const char *prompt;
  pininfo_t pininfo;
  int minlen = 6;

  assert (chvno == 1 || chvno == 2);

  *pinvalue = NULL;

  if (chvno == 2 && app->app_local->flags.def_chv2)
    {
      /* Special case for def_chv2 mechanism. */
      if (opt.verbose)
        log_info (_("using default PIN as %s\n"), "CHV2");
      rc = iso7816_verify (app->slot, 0x82, "123456", 6);
      if (rc)
        {
          /* Verification of CHV2 with the default PIN failed,
             although the card pretends to have the default PIN set as
             CHV2.  We better disable the def_chv2 flag now. */
          log_info (_("failed to use default PIN as %s: %s"
                      " - disabling further default use\n"),
                    "CHV2", gpg_strerror (rc));
          app->app_local->flags.def_chv2 = 0;
        }
      return rc;
    }

  memset (&pininfo, 0, sizeof pininfo);
  pininfo.fixedlen = -1;
  pininfo.minlen = minlen;


  if (chvno == 1)
    {
#define PROMPTSTRING  _("||Please enter the PIN%%0A[sigs done: %lu]")
      size_t promptsize = strlen (PROMPTSTRING) + 50;

      prompt_buffer = xtrymalloc (promptsize);
      if (!prompt_buffer)
        return gpg_error_from_syserror ();
      snprintf (prompt_buffer, promptsize-1, PROMPTSTRING, sigcount);
      prompt = prompt_buffer;
#undef PROMPTSTRING
    }
  else
    prompt = _("||Please enter the PIN");


  if (!opt.disable_pinpad
      && !iso7816_check_pinpad (app->slot, ISO7816_VERIFY, &pininfo)
      && !check_pinpad_request (app, &pininfo, 0))
    {
      /* The reader supports the verify command through the pinpad.
         Note that the pincb appends a text to the prompt telling the
         user to use the pinpad. */
      rc = pincb (pincb_arg, prompt, NULL);
      prompt = NULL;
      xfree (prompt_buffer);
      prompt_buffer = NULL;
      if (rc)
        {
          log_info (_("PIN callback returned error: %s\n"),
                    gpg_strerror (rc));
          return rc;
        }
      rc = iso7816_verify_kp (app->slot, 0x80+chvno, &pininfo);
      /* Dismiss the prompt. */
      pincb (pincb_arg, NULL, NULL);

      assert (!*pinvalue);
    }
  else
    {
      /* The reader has no pinpad or we don't want to use it. */
      rc = pincb (pincb_arg, prompt, pinvalue);
      prompt = NULL;
      xfree (prompt_buffer);
      prompt_buffer = NULL;
      if (rc)
        {
          log_info (_("PIN callback returned error: %s\n"),
                    gpg_strerror (rc));
          return rc;
        }

      if (strlen (*pinvalue) < minlen)
        {
          log_error (_("PIN for CHV%d is too short;"
                       " minimum length is %d\n"), chvno, minlen);
          xfree (*pinvalue);
          *pinvalue = NULL;
          return gpg_error (GPG_ERR_BAD_PIN);
        }

      rc = iso7816_verify (app->slot, 0x80+chvno,
                           *pinvalue, strlen (*pinvalue));
    }

  if (rc)
    {
      log_error (_("verify CHV%d failed: %s\n"), chvno, gpg_strerror (rc));
      xfree (*pinvalue);
      *pinvalue = NULL;
      flush_cache_after_error (app);
    }

  return rc;
}