do_genkey (app_t app, ctrl_t ctrl,  const char *keynostr, unsigned int flags,
           time_t createtime,
           gpg_error_t (*pincb)(void*, const char *, char **),
           void *pincb_arg)
{
  int rc;
  char numbuf[30];
  unsigned char fprbuf[20];
  const unsigned char *keydata, *m, *e;
  unsigned char *buffer = NULL;
  size_t buflen, keydatalen, mlen, elen;
  time_t created_at;
  int keyno = atoi (keynostr);
  int force = (flags & 1);
  time_t start_at;
  int exmode;
  int le_value;
  unsigned int keybits;

  if (keyno < 1 || keyno > 3)
    return gpg_error (GPG_ERR_INV_ID);
  keyno--;

  /* We flush the cache to increase the traffic before a key
     generation.  This _might_ help a card to gather more entropy. */
  flush_cache (app);

  /* Obviously we need to remove the cached public key.  */
  xfree (app->app_local->pk[keyno].key);
  app->app_local->pk[keyno].key = NULL;
  app->app_local->pk[keyno].keylen = 0;
  app->app_local->pk[keyno].read_done = 0;

  /* Check whether a key already exists.  */
  rc = does_key_exist (app, keyno, 1, force);
  if (rc)
    return rc;

  /* Because we send the key parameter back via status lines we need
     to put a limit on the max. allowed keysize.  2048 bit will
     already lead to a 527 byte long status line and thus a 4096 bit
     key would exceed the Assuan line length limit.  */
  keybits = app->app_local->keyattr[keyno].rsa.n_bits;
  if (keybits > 4096)
    return gpg_error (GPG_ERR_TOO_LARGE);

  /* Prepare for key generation by verifying the Admin PIN.  */
  rc = verify_chv3 (app, pincb, pincb_arg);
  if (rc)
    goto leave;

  /* Test whether we will need extended length mode.  (1900 is an
     arbitrary length which for sure fits into a short apdu.)  */
  if (app->app_local->cardcap.ext_lc_le && keybits > 1900)
    {
      exmode = 1;    /* Use extended length w/o a limit.  */
      le_value = app->app_local->extcap.max_rsp_data;
      /* No need to check le_value because it comes from a 16 bit
         value and thus can't create an overflow on a 32 bit
         system.  */
    }
  else
    {
      exmode = 0;
      le_value = 256; /* Use legacy value. */
    }

  log_info (_("please wait while key is being generated ...\n"));
  start_at = time (NULL);
  rc = iso7816_generate_keypair
/* # warning key generation temporary replaced by reading an existing key. */
/*   rc = iso7816_read_public_key */
    (app->slot, exmode,
     (const unsigned char*)(keyno == 0? "\xB6" :
                            keyno == 1? "\xB8" : "\xA4"), 2,
     le_value,
     &buffer, &buflen);
  if (rc)
    {
      rc = gpg_error (GPG_ERR_CARD);
      log_error (_("generating key failed\n"));
      goto leave;
    }
  log_info (_("key generation completed (%d seconds)\n"),
            (int)(time (NULL) - start_at));

  keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen);
  if (!keydata)
    {
      rc = gpg_error (GPG_ERR_CARD);
      log_error (_("response does not contain the public key data\n"));
      goto leave;
    }

  m = find_tlv (keydata, keydatalen, 0x0081, &mlen);
  if (!m)
    {
      rc = gpg_error (GPG_ERR_CARD);
      log_error (_("response does not contain the RSA modulus\n"));
      goto leave;
    }
  /* log_printhex ("RSA n:", m, mlen); */
  send_key_data (ctrl, "n", m, mlen);

  e = find_tlv (keydata, keydatalen, 0x0082, &elen);
  if (!e)
    {
      rc = gpg_error (GPG_ERR_CARD);
      log_error (_("response does not contain the RSA public exponent\n"));
      goto leave;
    }
  /* log_printhex ("RSA e:", e, elen); */
  send_key_data (ctrl, "e", e, elen);

  created_at = createtime? createtime : gnupg_get_time ();
  sprintf (numbuf, "%lu", (unsigned long)created_at);
  send_status_info (ctrl, "KEY-CREATED-AT",
                    numbuf, (size_t)strlen(numbuf), NULL, 0);

  rc = store_fpr (app, keyno, (u32)created_at, fprbuf, KEY_TYPE_RSA,
                  m, mlen, e, elen);
  if (rc)
    goto leave;
  send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);


 leave:
  xfree (buffer);
  return rc;
}