Return the balance of a Geldkarte.

This commit is contained in:
Werner Koch 2009-01-27 16:38:33 +00:00
parent 51e4831685
commit 92cb022675
2 changed files with 90 additions and 18 deletions

View File

@ -1,5 +1,7 @@
2009-01-27 Werner Koch <wk@g10code.com>
* app-geldkarte.c: Changed to use an AID.
* app.c (app_munge_serialno): Add case for no serialno.
(app_get_serial_and_stamp): Ditto.

View File

@ -20,10 +20,9 @@
/* This is a read-only application to quickly dump information of a
German Geldkarte (debit card for small amounts).
Because this application does no use an AID it is best to test for
it after the test for other applications.
German Geldkarte (debit card for small amounts). We only support
newer Geldkarte (with the AID DF_BOERSE_NEU) issued since 2000 or
even earlier.
*/
@ -58,6 +57,9 @@ struct app_local_s
unsigned int currency_mult100;
unsigned char chipid;
unsigned char osvers;
int balance;
int maxamount;
int maxamount1;
};
@ -109,11 +111,6 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
err = send_one_string (ctrl, name, ld->country);
else if (!strcmp (name, "X-CURRENCY"))
err = send_one_string (ctrl, name, ld->currency);
else if (!strcmp (name, "X-CRNCMULT"))
{
snprintf (numbuf, sizeof numbuf, "%u", ld->currency_mult100);
err = send_one_string (ctrl, name, numbuf);
}
else if (!strcmp (name, "X-ZKACHIPID"))
{
snprintf (numbuf, sizeof numbuf, "0x%02X", ld->chipid);
@ -124,6 +121,24 @@ do_getattr (app_t app, ctrl_t ctrl, const char *name)
snprintf (numbuf, sizeof numbuf, "0x%02X", ld->osvers);
err = send_one_string (ctrl, name, numbuf);
}
else if (!strcmp (name, "X-BALANCE"))
{
snprintf (numbuf, sizeof numbuf, "%.2f",
(double)ld->balance / 100 * ld->currency_mult100);
err = send_one_string (ctrl, name, numbuf);
}
else if (!strcmp (name, "X-MAXAMOUNT"))
{
snprintf (numbuf, sizeof numbuf, "%.2f",
(double)ld->maxamount / 100 * ld->currency_mult100);
err = send_one_string (ctrl, name, numbuf);
}
else if (!strcmp (name, "X-MAXAMOUNT1"))
{
snprintf (numbuf, sizeof numbuf, "%.2f",
(double)ld->maxamount1 / 100 * ld->currency_mult100);
err = send_one_string (ctrl, name, numbuf);
}
else
err = gpg_error (GPG_ERR_INV_NAME);
@ -142,9 +157,11 @@ do_learn_status (app_t app, ctrl_t ctrl)
"X-VALIDFROM",
"X-COUNTRY",
"X-CURRENCY",
"X-CRNCMULT",
"X-ZKACHIPID",
"X-OSVERSION",
"X-BALANCE",
"X-MAXAMOUNT",
"X-MAXAMOUNT1",
NULL
};
gpg_error_t err = 0;
@ -235,12 +252,28 @@ copy_bcd (const unsigned char *string, size_t length)
}
/* Convert the BCD number at STING of LENGTH into an integer and store
that at RESULT. Return 0 on success. */
static gpg_error_t
bcd_to_int (const unsigned char *string, size_t length, int *result)
{
char *tmp;
tmp = copy_bcd (string, length);
if (!tmp)
return gpg_error (GPG_ERR_BAD_DATA);
*result = strtol (tmp, NULL, 10);
xfree (tmp);
return 0;
}
/* Select the Geldkarte application. */
gpg_error_t
app_select_geldkarte (app_t app)
{
static unsigned char const aid[] =
{ 0xD2, 0x76, 0x00, 0x00, 0x25, 0x45, 0x50, 0x02, 0x00 };
gpg_error_t err;
int slot = app->slot;
unsigned char *result = NULL;
@ -248,16 +281,16 @@ app_select_geldkarte (app_t app)
struct app_local_s *ld;
const char *banktype;
err = iso7816_select_file (slot, 0x3f00, 1, NULL, NULL);
err = iso7816_select_application (slot, aid, sizeof aid, 0);
if (err)
goto leave; /* Oops. */
/* Read short EF 0xbc. We require this record to be at least 24
bytes with the the first byte 0x67 and a correct the filler
byte. */
err = iso7816_read_record (slot, 1, 1, 0xbc, &result, &resultlen);
goto leave;
/* Read the first record of EF_ID (SFI=0x17). We require this
record to be at least 24 bytes with the the first byte 0x67 and a
correct filler byte. */
err = iso7816_read_record (slot, 1, 1, ((0x17 << 3)|4), &result, &resultlen);
if (err)
goto leave; /* No such record or other error - not a Geldkarte. */
goto leave; /* Oops - not a Geldkarte. */
if (resultlen < 24 || *result != 0x67 || result[22])
{
err = gpg_error (GPG_ERR_NOT_FOUND);
@ -280,6 +313,23 @@ app_select_geldkarte (app_t app)
app->apptype = "GELDKARTE";
app->fnc.deinit = do_deinit;
/* If we don't have a serialno yet construct it from the EF_ID. */
if (!app->serialno)
{
app->serialno = xtrymalloc (10);
if (!app->serialno)
{
err = gpg_error_from_syserror ();
goto leave;
}
memcpy (app->serialno, result, 10);
app->serialnolen = 10;
err = app_munge_serialno (app);
if (err)
goto leave;
}
app->app_local = ld = xtrycalloc (1, sizeof *app->app_local);
if (!app->app_local)
{
@ -324,6 +374,26 @@ app_select_geldkarte (app_t app)
ld->chipid = result[21];
ld->osvers = result[23];
/* Read the first record of EF_BETRAG (SFI=0x18). */
xfree (result);
err = iso7816_read_record (slot, 1, 1, ((0x18 << 3)|4), &result, &resultlen);
if (err)
goto leave; /* It does not make sense to continue. */
if (resultlen < 12)
{
err = gpg_error (GPG_ERR_NOT_FOUND);
goto leave;
}
err = bcd_to_int (result+0, 3, &ld->balance);
if (!err)
err = bcd_to_int (result+3, 3, &ld->maxamount);
if (!err)
err = bcd_to_int (result+6, 3, &ld->maxamount1);
/* The next 3 bytes are the maximum amount chargable without using a
MAC. This is usually 0. */
if (err)
goto leave;
/* Setup the rest of the methods. */
app->fnc.learn_status = do_learn_status;
app->fnc.getattr = do_getattr;