mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Add a Geldkarte gadget application.
Minor other changes.
This commit is contained in:
parent
7b33b9324a
commit
51e4831685
3
AUTHORS
3
AUTHORS
@ -1,5 +1,6 @@
|
||||
Program: GnuPG
|
||||
Maintainer: Werner Koch <wk@gnupg.org>
|
||||
Homepage: http://www.gnupg.org
|
||||
Maintainer: Werner Koch <wk@gnupg.org>
|
||||
Bug reports: <bug-gnupg@gnu.org>
|
||||
Security related bug reports: <security@gnupg.org>
|
||||
License: GPLv3+
|
||||
|
@ -1,3 +1,7 @@
|
||||
2009-01-26 Werner Koch <wk@g10code.com>
|
||||
|
||||
* card-util.c (card_status): Detect a Geldkarte.
|
||||
|
||||
2009-01-13 Werner Koch <wk@g10code.com>
|
||||
|
||||
* call-agent.c (dummy_data_cb): New.
|
||||
|
@ -387,6 +387,12 @@ card_status (FILE *fp, char *serialno, size_t serialnobuflen)
|
||||
fputs ("pkcs15-card:\n", fp);
|
||||
log_info ("this is a PKCS#15 compliant card\n");
|
||||
}
|
||||
else if (info.apptype && !strcmp (info.apptype, "GELDKARTE"))
|
||||
{
|
||||
if (opt.with_colons)
|
||||
fputs ("geldkarte-card:\n", fp);
|
||||
log_info ("this is a Geldkarte compliant card\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opt.with_colons)
|
||||
|
@ -1,3 +1,8 @@
|
||||
2009-01-22 Werner Koch <wk@g10code.com>
|
||||
|
||||
* t-support.c (gpg_err_code_from_errno)
|
||||
(gpg_err_code_from_syserror): New.
|
||||
|
||||
2008-11-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* argparse.c (arg_parse): Fix last change.
|
||||
|
@ -22,9 +22,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "t-support.h"
|
||||
|
||||
|
||||
/* Replacements for the malloc functions as used here. */
|
||||
|
||||
static void
|
||||
@ -107,3 +109,31 @@ gcry_free (void *a)
|
||||
if (a)
|
||||
free (a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Stubs for gpg-error functions required because some compilers do
|
||||
not eliminate the supposed-to-be-unused-inline-functions and thus
|
||||
require functions called from these inline fucntions. Although we
|
||||
do not use gpg-error, gpg-error.h may get included via gcrypt.h if
|
||||
it happens to be used used in libjnlib-config.h. */
|
||||
int
|
||||
gpg_err_code_from_errno (int err)
|
||||
{
|
||||
assert (!"stub function");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve the error code directly from the ERRNO variable. This
|
||||
returns GPG_ERR_UNKNOWN_ERRNO if the system error is not mapped
|
||||
(report this) and GPG_ERR_MISSING_ERRNO if ERRNO has the value 0. */
|
||||
int
|
||||
gpg_err_code_from_syserror (void)
|
||||
{
|
||||
assert (!"stub function");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
2009-01-22 Werner Koch <wk@g10code.com>
|
||||
|
||||
* Makefile.am (gpg2keys_curl_LDADD, gpg2keys_hkp_LDADD): Add all
|
||||
standard libs.
|
||||
|
||||
2008-10-20 Werner Koch <wk@g10code.com>
|
||||
|
||||
* curl-shim.c (curl_global_init): Mark usused arg.
|
||||
|
@ -1,4 +1,6 @@
|
||||
# Copyright (C) 2001, 2002, 2004, 2005, 2006 Free Software Foundation, Inc.
|
||||
# Makefile.am - Makefile for keyservers
|
||||
# Copyright (C) 2001, 2002, 2004, 2005, 2006,
|
||||
# 2009 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of GnuPG.
|
||||
#
|
||||
@ -66,14 +68,17 @@ gpg2keys_hkp_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
gpg2keys_hkp_LDADD = $(common_libs) $(GPG_ERROR_LIBS) $(NETLIBS) $(DNSLIBS) \
|
||||
$(other_libs)
|
||||
else
|
||||
# Note that we need to include all other libs here as well because
|
||||
# some compilers don't care about inline fucntions and insert
|
||||
# references to symbols used in unused inline functions.
|
||||
gpg2keys_curl_CPPFLAGS = $(LIBCURL_CPPFLAGS) $(AM_CPPFLAGS)
|
||||
gpg2keys_curl_LDADD = $(LIBCURL) $(GETOPT)
|
||||
gpg2keys_curl_LDADD = $(common_libs) $(GPG_ERROR_LIBS) $(NETLIBS) $(DNSLIBS) \
|
||||
$(other_libs) $(LIBCURL) $(GETOPT)
|
||||
gpg2keys_hkp_CPPFLAGS = $(LIBCURL_CPPFLAGS) $(AM_CPPFLAGS)
|
||||
gpg2keys_hkp_LDADD = $(LIBCURL) $(GETOPT)
|
||||
gpg2keys_hkp_LDADD = $(common_libs) $(GPG_ERROR_LIBS) $(NETLIBS) $(DNSLIBS) \
|
||||
$(other_libs) $(LIBCURL) $(GETOPT)
|
||||
endif
|
||||
|
||||
# Make sure that all libs are build before we use them. This is
|
||||
# important for things like make -j2.
|
||||
$(PROGRAMS): $(common_libs)
|
||||
|
||||
|
||||
|
@ -1,3 +1,14 @@
|
||||
2009-01-27 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app.c (app_munge_serialno): Add case for no serialno.
|
||||
(app_get_serial_and_stamp): Ditto.
|
||||
|
||||
2009-01-26 Werner Koch <wk@g10code.com>
|
||||
|
||||
* app-geldkarte.c: New.
|
||||
* Makefile.am (card_apps): Add new file.
|
||||
* app.c (select_application): Test for geldkarte.
|
||||
|
||||
2009-01-12 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command.c (send_client_notifications) [HAVE_W32_SYSTEM]: Fix
|
||||
|
@ -30,7 +30,7 @@ AM_CFLAGS = $(LIBGCRYPT_CFLAGS) \
|
||||
$(KSBA_CFLAGS) $(LIBASSUAN_PTH_CFLAGS) $(PTH_CFLAGS)
|
||||
|
||||
|
||||
card_apps = app-openpgp.c app-nks.c app-dinsig.c app-p15.c
|
||||
card_apps = app-openpgp.c app-nks.c app-dinsig.c app-p15.c app-geldkarte.c
|
||||
|
||||
scdaemon_SOURCES = \
|
||||
scdaemon.c scdaemon.h \
|
||||
|
@ -207,6 +207,9 @@ gpg_error_t app_select_dinsig (app_t app);
|
||||
/*-- app-p15.c --*/
|
||||
gpg_error_t app_select_p15 (app_t app);
|
||||
|
||||
/*-- app-geldkarte.c --*/
|
||||
gpg_error_t app_select_geldkarte (app_t app);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
337
scd/app-geldkarte.c
Normal file
337
scd/app-geldkarte.c
Normal file
@ -0,0 +1,337 @@
|
||||
/* app-geldkarte.c - The German Geldkarte application
|
||||
* Copyright (C) 2004 g10 Code GmbH
|
||||
* Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <time.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "scdaemon.h"
|
||||
|
||||
#include "i18n.h"
|
||||
#include "iso7816.h"
|
||||
#include "app-common.h"
|
||||
#include "tlv.h"
|
||||
|
||||
|
||||
|
||||
/* Object with application (i.e. Geldkarte) specific data. */
|
||||
struct app_local_s
|
||||
{
|
||||
char kblz[2+1+4+1];
|
||||
const char *banktype;
|
||||
char *cardno;
|
||||
char expires[7+1];
|
||||
char validfrom[10+1];
|
||||
char *country;
|
||||
char currency[3+1];
|
||||
unsigned int currency_mult100;
|
||||
unsigned char chipid;
|
||||
unsigned char osvers;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* Deconstructor. */
|
||||
static void
|
||||
do_deinit (app_t app)
|
||||
{
|
||||
if (app && app->app_local)
|
||||
{
|
||||
xfree (app->app_local->cardno);
|
||||
xfree (app->app_local->country);
|
||||
xfree (app->app_local);
|
||||
app->app_local = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
send_one_string (ctrl_t ctrl, const char *name, const char *string)
|
||||
{
|
||||
if (!name || !string)
|
||||
return 0;
|
||||
send_status_info (ctrl, name, string, strlen (string), NULL, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Implement the GETATTR command. This is similar to the LEARN
|
||||
command but returns just one value via the status interface. */
|
||||
static gpg_error_t
|
||||
do_getattr (app_t app, ctrl_t ctrl, const char *name)
|
||||
{
|
||||
gpg_error_t err;
|
||||
struct app_local_s *ld = app->app_local;
|
||||
char numbuf[100];
|
||||
|
||||
if (!strcmp (name, "X-KBLZ"))
|
||||
err = send_one_string (ctrl, name, ld->kblz);
|
||||
else if (!strcmp (name, "X-BANKINFO"))
|
||||
err = send_one_string (ctrl, name, ld->banktype);
|
||||
else if (!strcmp (name, "X-CARDNO"))
|
||||
err = send_one_string (ctrl, name, ld->cardno);
|
||||
else if (!strcmp (name, "X-EXPIRES"))
|
||||
err = send_one_string (ctrl, name, ld->expires);
|
||||
else if (!strcmp (name, "X-VALIDFROM"))
|
||||
err = send_one_string (ctrl, name, ld->validfrom);
|
||||
else if (!strcmp (name, "X-COUNTRY"))
|
||||
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);
|
||||
err = send_one_string (ctrl, name, numbuf);
|
||||
}
|
||||
else if (!strcmp (name, "X-OSVERSION"))
|
||||
{
|
||||
snprintf (numbuf, sizeof numbuf, "0x%02X", ld->osvers);
|
||||
err = send_one_string (ctrl, name, numbuf);
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_INV_NAME);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
do_learn_status (app_t app, ctrl_t ctrl)
|
||||
{
|
||||
static const char *names[] = {
|
||||
"X-KBLZ",
|
||||
"X-BANKINFO",
|
||||
"X-CARDNO",
|
||||
"X-EXPIRES",
|
||||
"X-VALIDFROM",
|
||||
"X-COUNTRY",
|
||||
"X-CURRENCY",
|
||||
"X-CRNCMULT",
|
||||
"X-ZKACHIPID",
|
||||
"X-OSVERSION",
|
||||
NULL
|
||||
};
|
||||
gpg_error_t err = 0;
|
||||
int idx;
|
||||
|
||||
for (idx=0; names[idx] && !err; idx++)
|
||||
err = do_getattr (app, ctrl, names[idx]);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
copy_bcd (const unsigned char *string, size_t length)
|
||||
{
|
||||
const unsigned char *s;
|
||||
size_t n;
|
||||
size_t needed;
|
||||
char *buffer, *dst;
|
||||
|
||||
if (!length)
|
||||
return xtrystrdup ("");
|
||||
|
||||
/* Skip leading zeroes. */
|
||||
for (; length && !*string; length--, string++)
|
||||
;
|
||||
s = string;
|
||||
n = length;
|
||||
needed = 0;
|
||||
for (; n ; n--, s++)
|
||||
{
|
||||
if (!needed && !(*s & 0xf0))
|
||||
; /* Skip the leading zero in the first nibble. */
|
||||
else
|
||||
{
|
||||
if ( ((*s >> 4) & 0x0f) > 9 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
needed++;
|
||||
}
|
||||
if ( n == 1 && (*s & 0x0f) > 9 )
|
||||
; /* Ignore the last digit if it has the sign. */
|
||||
else
|
||||
{
|
||||
needed++;
|
||||
if ( (*s & 0x0f) > 9 )
|
||||
{
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (!needed) /* If it is all zero, print a "0". */
|
||||
needed++;
|
||||
|
||||
buffer = dst = xtrymalloc (needed+1);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
s = string;
|
||||
n = length;
|
||||
needed = 0;
|
||||
for (; n ; n--, s++)
|
||||
{
|
||||
if (!needed && !(*s & 0xf0))
|
||||
; /* Skip the leading zero in the first nibble. */
|
||||
else
|
||||
{
|
||||
*dst++ = '0' + ((*s >> 4) & 0x0f);
|
||||
needed++;
|
||||
}
|
||||
|
||||
if ( n == 1 && (*s & 0x0f) > 9 )
|
||||
; /* Ignore the last digit if it has the sign. */
|
||||
else
|
||||
{
|
||||
*dst++ = '0' + (*s & 0x0f);
|
||||
needed++;
|
||||
}
|
||||
}
|
||||
if (!needed)
|
||||
*dst++ = '0';
|
||||
*dst = 0;
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Select the Geldkarte application. */
|
||||
gpg_error_t
|
||||
app_select_geldkarte (app_t app)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int slot = app->slot;
|
||||
unsigned char *result = NULL;
|
||||
size_t resultlen;
|
||||
struct app_local_s *ld;
|
||||
const char *banktype;
|
||||
|
||||
err = iso7816_select_file (slot, 0x3f00, 1, NULL, NULL);
|
||||
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);
|
||||
if (err)
|
||||
goto leave; /* No such record or other error - not a Geldkarte. */
|
||||
if (resultlen < 24 || *result != 0x67 || result[22])
|
||||
{
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* The short Bankleitzahl consists of 3 bytes at offset 1. */
|
||||
switch (result[1])
|
||||
{
|
||||
case 0x21: banktype = "Oeffentlich-rechtliche oder private Bank"; break;
|
||||
case 0x22: banktype = "Privat- oder Geschaeftsbank"; break;
|
||||
case 0x25: banktype = "Sparkasse"; break;
|
||||
case 0x26:
|
||||
case 0x29: banktype = "Genossenschaftsbank"; break;
|
||||
default:
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
goto leave; /* Probably not a Geldkarte. */
|
||||
}
|
||||
|
||||
app->apptype = "GELDKARTE";
|
||||
app->fnc.deinit = do_deinit;
|
||||
|
||||
app->app_local = ld = xtrycalloc (1, sizeof *app->app_local);
|
||||
if (!app->app_local)
|
||||
{
|
||||
err = gpg_err_code_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
snprintf (ld->kblz, sizeof ld->kblz, "%02X-%02X%02X",
|
||||
result[1], result[2], result[3]);
|
||||
ld->banktype = banktype;
|
||||
ld->cardno = copy_bcd (result+4, 5);
|
||||
if (!ld->cardno)
|
||||
{
|
||||
err = gpg_err_code_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
snprintf (ld->expires, sizeof ld->expires, "20%02X-%02X",
|
||||
result[10], result[11]);
|
||||
snprintf (ld->validfrom, sizeof ld->validfrom, "20%02X-%02X-%02X",
|
||||
result[12], result[13], result[14]);
|
||||
|
||||
ld->country = copy_bcd (result+15, 2);
|
||||
if (!ld->country)
|
||||
{
|
||||
err = gpg_err_code_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
snprintf (ld->currency, sizeof ld->currency, "%c%c%c",
|
||||
isascii (result[17])? result[17]:' ',
|
||||
isascii (result[18])? result[18]:' ',
|
||||
isascii (result[19])? result[19]:' ');
|
||||
|
||||
ld->currency_mult100 = (result[20] == 0x01? 1:
|
||||
result[20] == 0x02? 10:
|
||||
result[20] == 0x04? 100:
|
||||
result[20] == 0x08? 1000:
|
||||
result[20] == 0x10? 10000:
|
||||
result[20] == 0x20? 100000:0);
|
||||
|
||||
ld->chipid = result[21];
|
||||
ld->osvers = result[23];
|
||||
|
||||
/* Setup the rest of the methods. */
|
||||
app->fnc.learn_status = do_learn_status;
|
||||
app->fnc.getattr = do_getattr;
|
||||
|
||||
|
||||
leave:
|
||||
xfree (result);
|
||||
if (err)
|
||||
do_deinit (app);
|
||||
return err;
|
||||
}
|
21
scd/app.c
21
scd/app.c
@ -352,6 +352,9 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
|
||||
err = app_select_p15 (app);
|
||||
if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
|
||||
err = app_select_dinsig (app);
|
||||
if (err && is_app_allowed ("geldkarte")
|
||||
&& (!name || !strcmp (name, "geldkarte")))
|
||||
err = app_select_geldkarte (app);
|
||||
if (err && name)
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
|
||||
@ -440,6 +443,7 @@ release_application (app_t app)
|
||||
FF 00 00 = For serial numbers starting with an FF
|
||||
FF 01 00 = Some german p15 cards return an empty serial number so the
|
||||
serial number from the EF(TokenInfo) is used instead.
|
||||
FF 7F 00 = No serialno.
|
||||
|
||||
All other serial number not starting with FF are used as they are.
|
||||
*/
|
||||
@ -452,13 +456,23 @@ app_munge_serialno (app_t app)
|
||||
requires that we put our default prefix "FF0000" in front. */
|
||||
unsigned char *p = xtrymalloc (app->serialnolen + 3);
|
||||
if (!p)
|
||||
return gpg_error (gpg_err_code_from_errno (errno));
|
||||
return gpg_error_from_syserror ();
|
||||
memcpy (p, "\xff\0", 3);
|
||||
memcpy (p+3, app->serialno, app->serialnolen);
|
||||
app->serialnolen += 3;
|
||||
xfree (app->serialno);
|
||||
app->serialno = p;
|
||||
}
|
||||
else if (!app->serialnolen)
|
||||
{
|
||||
unsigned char *p = xtrymalloc (3);
|
||||
if (!p)
|
||||
return gpg_error_from_syserror ();
|
||||
memcpy (p, "\xff\x7f", 3);
|
||||
app->serialnolen = 3;
|
||||
xfree (app->serialno);
|
||||
app->serialno = p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -482,7 +496,10 @@ app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
|
||||
if (stamp)
|
||||
*stamp = 0; /* not available */
|
||||
|
||||
buf = bin2hex (app->serialno, app->serialnolen, NULL);
|
||||
if (!app->serialnolen)
|
||||
buf = xtrystrdup ("FF7F00");
|
||||
else
|
||||
buf = bin2hex (app->serialno, app->serialnolen, NULL);
|
||||
if (!buf)
|
||||
return gpg_error_from_syserror ();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user