app_select_openpgp (app_t app)
{
  static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
  int slot = app->slot;
  int rc;
  unsigned char *buffer;
  size_t buflen;
  void *relptr;

  /* Note that the card can't cope with P2=0xCO, thus we need to pass a
     special flag value. */
  rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001);
  if (!rc)
    {
      unsigned int manufacturer;

      app->apptype = "OPENPGP";

      app->did_chv1 = 0;
      app->did_chv2 = 0;
      app->did_chv3 = 0;
      app->app_local = NULL;

      /* The OpenPGP card returns the serial number as part of the
         AID; because we prefer to use OpenPGP serial numbers, we
         replace a possibly already set one from a EF.GDO with this
         one.  Note, that for current OpenPGP cards, no EF.GDO exists
         and thus it won't matter at all. */
      rc = iso7816_get_data (slot, 0, 0x004F, &buffer, &buflen);
      if (rc)
        goto leave;
      if (opt.verbose)
        {
          log_info ("AID: ");
          log_printhex ("", buffer, buflen);
        }

      app->card_version = buffer[6] << 8;
      app->card_version |= buffer[7];
      manufacturer = (buffer[8]<<8 | buffer[9]);

      xfree (app->serialno);
      app->serialno = buffer;
      app->serialnolen = buflen;
      buffer = NULL;
      app->app_local = xtrycalloc (1, sizeof *app->app_local);
      if (!app->app_local)
        {
          rc = gpg_error (gpg_err_code_from_errno (errno));
          goto leave;
        }

      app->app_local->manufacturer = manufacturer;

      if (app->card_version >= 0x0200)
        app->app_local->extcap.is_v2 = 1;


      /* Read the historical bytes.  */
      relptr = get_one_do (app, 0x5f52, &buffer, &buflen, NULL);
      if (relptr)
        {
          if (opt.verbose)
            {
              log_info ("Historical Bytes: ");
              log_printhex ("", buffer, buflen);
            }
          parse_historical (app->app_local, buffer, buflen);
          xfree (relptr);
        }

      /* Read the force-chv1 flag.  */
      relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
      if (!relptr)
        {
          log_error (_("can't access %s - invalid OpenPGP card?\n"),
                     "CHV Status Bytes");
          goto leave;
        }
      app->force_chv1 = (buflen && *buffer == 0);
      xfree (relptr);

      /* Read the extended capabilities.  */
      relptr = get_one_do (app, 0x00C0, &buffer, &buflen, NULL);
      if (!relptr)
        {
          log_error (_("can't access %s - invalid OpenPGP card?\n"),
                     "Extended Capability Flags" );
          goto leave;
        }
      if (buflen)
        {
          app->app_local->extcap.sm_supported     = !!(*buffer & 0x80);
          app->app_local->extcap.get_challenge    = !!(*buffer & 0x40);
          app->app_local->extcap.key_import       = !!(*buffer & 0x20);
          app->app_local->extcap.change_force_chv = !!(*buffer & 0x10);
          app->app_local->extcap.private_dos      = !!(*buffer & 0x08);
          app->app_local->extcap.algo_attr_change = !!(*buffer & 0x04);
        }
      if (buflen >= 10)
        {
          /* Available with v2 cards.  */
          app->app_local->extcap.sm_aes128     = (buffer[1] == 1);
          app->app_local->extcap.max_get_challenge
                                               = (buffer[2] << 8 | buffer[3]);
          app->app_local->extcap.max_certlen_3 = (buffer[4] << 8 | buffer[5]);
          app->app_local->extcap.max_cmd_data  = (buffer[6] << 8 | buffer[7]);
          app->app_local->extcap.max_rsp_data  = (buffer[8] << 8 | buffer[9]);
        }
      xfree (relptr);

      /* Some of the first cards accidently don't set the
         CHANGE_FORCE_CHV bit but allow it anyway. */
      if (app->card_version <= 0x0100 && manufacturer == 1)
        app->app_local->extcap.change_force_chv = 1;

      parse_login_data (app);

      if (opt.verbose)
        show_caps (app->app_local);

      parse_algorithm_attribute (app, 0);
      parse_algorithm_attribute (app, 1);
      parse_algorithm_attribute (app, 2);

      if (opt.verbose > 1)
        dump_all_do (slot);

      app->fnc.deinit = do_deinit;
      app->fnc.learn_status = do_learn_status;
      app->fnc.readcert = do_readcert;
      app->fnc.readkey = do_readkey;
      app->fnc.getattr = do_getattr;
      app->fnc.setattr = do_setattr;
      app->fnc.writecert = do_writecert;
      app->fnc.writekey = do_writekey;
      app->fnc.genkey = do_genkey;
      app->fnc.sign = do_sign;
      app->fnc.auth = do_auth;
      app->fnc.decipher = do_decipher;
      app->fnc.change_pin = do_change_pin;
      app->fnc.check_pin = do_check_pin;
   }

leave:
  if (rc)
    do_deinit (app);
  return rc;
}
app_select_openpgp (app_t app)
{
  static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
  int slot = app->slot;
  int rc;
  unsigned char *buffer;
  size_t buflen;
  void *relptr;

   
  rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001);
  if (!rc)
    {
      unsigned int manufacturer;

      app->apptype = "OPENPGP";

      app->did_chv1 = 0;
      app->did_chv2 = 0;
      app->did_chv3 = 0;
      app->app_local = NULL;

       
      rc = iso7816_get_data (slot, 0, 0x004F, &buffer, &buflen);
      if (rc)
        goto leave;
      if (opt.verbose)
        {
          log_info ("AID: ");
          log_printhex ("", buffer, buflen);
        }

      app->card_version = buffer[6] << 8;
      app->card_version |= buffer[7];
      manufacturer = (buffer[8]<<8 | buffer[9]);

      xfree (app->serialno);
      app->serialno = buffer;
      app->serialnolen = buflen;
      buffer = NULL;
      app->app_local = xtrycalloc (1, sizeof *app->app_local);
      if (!app->app_local)
        {
          rc = gpg_error (gpg_err_code_from_errno (errno));
          goto leave;
        }

      app->app_local->manufacturer = manufacturer;

      if (app->card_version >= 0x0200)
        app->app_local->extcap.is_v2 = 1;


       
      relptr = get_one_do (app, 0x5f52, &buffer, &buflen, NULL);
      if (relptr)
        {
          if (opt.verbose)
            {
              log_info ("Historical Bytes: ");
              log_printhex ("", buffer, buflen);
            }
          parse_historical (app->app_local, buffer, buflen);
          xfree (relptr);
        }

       
      relptr = get_one_do (app, 0x00C4, &buffer, &buflen, NULL);
      if (!relptr)
        {
          log_error (_("can't access %s - invalid OpenPGP card?\n"),
                     "CHV Status Bytes");
          goto leave;
        }
      app->force_chv1 = (buflen && *buffer == 0);
      xfree (relptr);

       
      relptr = get_one_do (app, 0x00C0, &buffer, &buflen, NULL);
      if (!relptr)
        {
          log_error (_("can't access %s - invalid OpenPGP card?\n"),
                     "Extended Capability Flags" );
          goto leave;
        }
      if (buflen)
        {
          app->app_local->extcap.sm_supported     = !!(*buffer & 0x80);
          app->app_local->extcap.get_challenge    = !!(*buffer & 0x40);
          app->app_local->extcap.key_import       = !!(*buffer & 0x20);
          app->app_local->extcap.change_force_chv = !!(*buffer & 0x10);
          app->app_local->extcap.private_dos      = !!(*buffer & 0x08);
          app->app_local->extcap.algo_attr_change = !!(*buffer & 0x04);
        }
      if (buflen >= 10)
        {
           
          app->app_local->extcap.sm_aes128     = (buffer[1] == 1);
          app->app_local->extcap.max_get_challenge
                                               = (buffer[2] << 8 | buffer[3]);
          app->app_local->extcap.max_certlen_3 = (buffer[4] << 8 | buffer[5]);
          app->app_local->extcap.max_cmd_data  = (buffer[6] << 8 | buffer[7]);
          app->app_local->extcap.max_rsp_data  = (buffer[8] << 8 | buffer[9]);
        }
      xfree (relptr);

       
      if (app->card_version <= 0x0100 && manufacturer == 1)
        app->app_local->extcap.change_force_chv = 1;

      parse_login_data (app);

      if (opt.verbose)
        show_caps (app->app_local);

      parse_algorithm_attribute (app, 0);
      parse_algorithm_attribute (app, 1);
      parse_algorithm_attribute (app, 2);

      if (opt.verbose > 1)
        dump_all_do (slot);

      app->fnc.deinit = do_deinit;
      app->fnc.learn_status = do_learn_status;
      app->fnc.readcert = do_readcert;
      app->fnc.readkey = do_readkey;
      app->fnc.getattr = do_getattr;
      app->fnc.setattr = do_setattr;
      app->fnc.writecert = do_writecert;
      app->fnc.writekey = do_writekey;
      app->fnc.genkey = do_genkey;
      app->fnc.sign = do_sign;
      app->fnc.auth = do_auth;
      app->fnc.decipher = do_decipher;
      app->fnc.change_pin = do_change_pin;
      app->fnc.check_pin = do_check_pin;
   }

leave:
  if (rc)
    do_deinit (app);
  return rc;
}