diff options
-rw-r--r-- | scd/ChangeLog | 14 | ||||
-rw-r--r-- | scd/apdu.c | 4 | ||||
-rw-r--r-- | scd/app-nks.c | 4 | ||||
-rw-r--r-- | scd/app-openpgp.c | 2 | ||||
-rw-r--r-- | scd/app.c | 2 | ||||
-rw-r--r-- | scd/card-dinsig.c | 4 | ||||
-rw-r--r-- | scd/card-p15.c | 12 | ||||
-rw-r--r-- | scd/card.c | 8 | ||||
-rw-r--r-- | scd/ccid-driver.c | 14 | ||||
-rw-r--r-- | scd/command.c | 6 | ||||
-rw-r--r-- | scd/iso7816.c | 24 | ||||
-rw-r--r-- | scd/iso7816.h | 1 | ||||
-rw-r--r-- | scd/sc-investigate.c | 143 | ||||
-rw-r--r-- | scd/scdaemon.h | 8 |
14 files changed, 200 insertions, 46 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog index 66ceebd22..a9296cbbb 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,17 @@ +2004-03-11 Werner Koch <wk@gnupg.org> + + * scdaemon.h (out_of_core): Removed. Replaced callers by standard + gpg_error function. + + * apdu.c, iso7816.c, ccid-driver.c [GNUPG_SCD_MAIN_HEADER]: Allow + to include a header defined by the compiler. This helps us to + reuse the source in other software. + +2004-03-10 Werner Koch <wk@gnupg.org> + + * iso7816.c (iso7816_read_record): New arg SHORT_EF. Changed all + callers. + 2004-02-18 Werner Koch <wk@gnupg.org> * sc-investigate.c (main): Setup the used character set. diff --git a/scd/apdu.c b/scd/apdu.c index e5295f566..7843fd566 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -28,7 +28,9 @@ # include <opensc/opensc.h> #endif -#if GNUPG_MAJOR_VERSION == 1 +#if defined(GNUPG_SCD_MAIN_HEADER) +#include GNUPG_SCD_MAIN_HEADER +#elif GNUPG_MAJOR_VERSION == 1 /* This is used with GnuPG version < 1.9. The code has been source copied from the current GnuPG >= 1.9 and is maintained over there. */ diff --git a/scd/app-nks.c b/scd/app-nks.c index 2ceb537a2..a4b6e3a15 100644 --- a/scd/app-nks.c +++ b/scd/app-nks.c @@ -130,10 +130,10 @@ keygripstr_from_pk_file (int slot, int fid, char *r_gripstr) err = iso7816_select_file (slot, fid, 0, NULL, NULL); if (err) return err; - err = iso7816_read_record (slot, 1, 1, &buffer[0], &buflen[0]); + err = iso7816_read_record (slot, 1, 1, 0, &buffer[0], &buflen[0]); if (err) return err; - err = iso7816_read_record (slot, 2, 1, &buffer[1], &buflen[1]); + err = iso7816_read_record (slot, 2, 1, 0, &buffer[1], &buflen[1]); if (err) { xfree (buffer[0]); diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c index 021d6a52c..7782b8e1c 100644 --- a/scd/app-openpgp.c +++ b/scd/app-openpgp.c @@ -245,7 +245,7 @@ store_fpr (int slot, int keynumber, u32 timestamp, n = 6 + 2 + mlen + 2 + elen; p = buffer = xtrymalloc (3 + n); if (!buffer) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); *p++ = 0x99; /* ctb */ *p++ = n >> 8; /* 2 byte length header */ @@ -47,7 +47,7 @@ select_application (ctrl_t ctrl, int slot, const char *name) app = xtrycalloc (1, sizeof *app); if (!app) { - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); log_info ("error allocating context: %s\n", gpg_strerror (rc)); return NULL; } diff --git a/scd/card-dinsig.c b/scd/card-dinsig.c index bb070d5f0..df09bfb57 100644 --- a/scd/card-dinsig.c +++ b/scd/card-dinsig.c @@ -141,7 +141,7 @@ dinsig_enum_keypairs (CARD card, int idx, { *keyid = xtrymalloc (17); if (!*keyid) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); if (!idx) strcpy (*keyid, "DINSIG-DF01.C000"); else @@ -193,7 +193,7 @@ dinsig_read_cert (CARD card, const char *certidstr, buf = xtrymalloc (file->size); if (!buf) { - gpg_error_t tmperr = out_of_core (); + gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno)); sc_file_free (file); return tmperr; } diff --git a/scd/card-p15.c b/scd/card-p15.c index 239e75045..ae3ef148f 100644 --- a/scd/card-p15.c +++ b/scd/card-p15.c @@ -53,7 +53,7 @@ init_private_data (CARD card) priv = xtrycalloc (1, sizeof *priv); if (!priv) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); /* OpenSC (0.7.0) is a bit strange in that the get_objects functions tries to be a bit too clever and implicitly does an enumeration @@ -179,7 +179,7 @@ p15_enum_keypairs (CARD card, int idx, *keyid = p = xtrymalloc (9+pinfo->id.len*2+1); if (!*keyid) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); p = stpcpy (p, "P15-5015."); for (i=0; i < pinfo->id.len; i++, p += 2) sprintf (p, "%02X", pinfo->id.value[i]); @@ -217,7 +217,7 @@ p15_enum_certs (CARD card, int idx, char **certid, int *type) *certid = p = xtrymalloc (9+cinfo->id.len*2+1); if (!*certid) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); p = stpcpy (p, "P15-5015."); for (i=0; i < cinfo->id.len; i++, p += 2) sprintf (p, "%02X", cinfo->id.value[i]); @@ -304,7 +304,7 @@ p15_read_cert (CARD card, const char *certidstr, *cert = xtrymalloc (certder->data_len); if (!*cert) { - gpg_error_t tmperr = out_of_core (); + gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno)); sc_pkcs15_free_certificate (certder); return tmperr; } @@ -400,7 +400,7 @@ p15_sign (CARD card, const char *keyidstr, int hashalgo, outbuflen = 1024; outbuf = xtrymalloc (outbuflen); if (!outbuf) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); rc = sc_pkcs15_compute_signature (card->p15card, keyobj, cryptflags, @@ -462,7 +462,7 @@ p15_decipher (CARD card, const char *keyidstr, outbuflen = indatalen < 256? 256 : indatalen; outbuf = xtrymalloc (outbuflen); if (!outbuf) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); rc = sc_pkcs15_decipher (card->p15card, keyobj, 0, diff --git a/scd/card.c b/scd/card.c index 53c89f3a4..8366dcb1c 100644 --- a/scd/card.c +++ b/scd/card.c @@ -108,7 +108,7 @@ card_open (CARD *rcard) card = xtrycalloc (1, sizeof *card); if (!card) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); card->reader = 0; rc = sc_establish_context (&card->ctx, "scdaemon"); @@ -275,7 +275,7 @@ find_iccsn (const unsigned char *buffer, size_t length, char **serial) *serial = p = xtrymalloc (2*n+1); if (!*serial) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); for (; n; n--, p += 2, s++) sprintf (p, "%02X", *s); *p = 0; @@ -389,7 +389,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) *serial = NULL; p = xtrymalloc (strlen (efser) + 7); if (!p) - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); else { strcpy (p, "FF0100"); @@ -405,7 +405,7 @@ card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp) { xfree (*serial); *serial = NULL; - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); } else { diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index ca5620176..b398e3ce3 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -87,16 +87,24 @@ #define DRVNAME "ccid-driver: " -#ifdef GNUPG_MAJOR_VERSION /* This source is used within GnuPG. */ +/* Depending on how this source is used we either define our error + output to go to stderr or to the jnlib based logging functions. We + use the latter when GNUPG_MAJOR_VERSION is defines or when both, + GNUPG_SCD_MAIN_HEADER and HAVE_JNLIB_LOGGING are defined. +*/ +#if defined(GNUPG_MAJOR_VERSION) \ + || (defined(GNUPG_SCD_MAIN_HEADER) && defined(HAVE_JNLIB_LOGGING)) -# if GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */ +#if defined(GNUPG_SCD_MAIN_HEADER) +# include GNUPG_SCD_MAIN_HEADER +#elif GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */ # include "options.h" # include "util.h" # include "memory.h" # include "cardglue.h" # else /* This is the modularized GnuPG 1.9 or later. */ # include "scdaemon.h" -# endif +#endif /* Disable all debugging output for now. */ #undef DBG_CARD_IO diff --git a/scd/command.c b/scd/command.c index d148ddb5a..4746e11b5 100644 --- a/scd/command.c +++ b/scd/command.c @@ -351,7 +351,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) buf = xtrymalloc (40 + 1 + strlen (certid) + 1); if (!buf) - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); else { sprintf (buf, "%d %s", certtype, certid); @@ -389,7 +389,7 @@ cmd_learn (ASSUAN_CONTEXT ctx, char *line) buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1); if (!buf) - rc = out_of_core (); + rc = gpg_error (gpg_err_code_from_errno (errno)); else { int i; @@ -577,7 +577,7 @@ pin_cb (void *opaque, const char *info, char **retstr) rc = asprintf (&command, "NEEDPIN %s", info); if (rc < 0) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); /* FIXME: Write an inquire function which returns the result in secure memory */ diff --git a/scd/iso7816.c b/scd/iso7816.c index 1ee9b55e7..d7d3c126b 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -24,7 +24,9 @@ #include <stdlib.h> #include <string.h> -#if GNUPG_MAJOR_VERSION == 1 +#if defined(GNUPG_SCD_MAIN_HEADER) +#include GNUPG_SCD_MAIN_HEADER +#elif GNUPG_MAJOR_VERSION == 1 /* This is used with GnuPG version < 1.9. The code has been source copied from the current GnuPG >= 1.9 and is maintained over there. */ @@ -200,7 +202,7 @@ iso7816_change_reference_data (int slot, int chvno, buf = xtrymalloc (oldchvlen + newchvlen); if (!buf) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); if (oldchvlen) memcpy (buf, oldchv, oldchvlen); memcpy (buf+oldchvlen, newchv, newchvlen); @@ -341,7 +343,8 @@ iso7816_decipher (int slot, const unsigned char *data, size_t datalen, /* We need to prepend the padding indicator. */ buf = xtrymalloc (datalen + 1); if (!buf) - return out_of_core (); + return gpg_error (gpg_err_code_from_errno (errno)); + *buf = padind; /* Padding indicator. */ memcpy (buf+1, data, datalen); sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf, @@ -550,11 +553,13 @@ iso7816_read_binary (int slot, size_t offset, size_t nmax, /* Perform a READ RECORD command. RECNO gives the record number to read with 0 indicating the current record. RECCOUNT must be 1 (not - all cards support reading of more than one record). The result is - stored in a newly allocated buffer at the address passed by RESULT. - Returns the length of this data at the address of RESULTLEN. */ + all cards support reading of more than one record). SHORT_EF + should be 0 to read the current EF or contain a short EF. The + result is stored in a newly allocated buffer at the address passed + by RESULT. Returns the length of this data at the address of + RESULTLEN. */ gpg_error_t -iso7816_read_record (int slot, int recno, int reccount, +iso7816_read_record (int slot, int recno, int reccount, int short_ef, unsigned char **result, size_t *resultlen) { int sw; @@ -568,7 +573,8 @@ iso7816_read_record (int slot, int recno, int reccount, /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus we check for this limit. */ - if (recno < 0 || recno > 255 || reccount != 1) + if (recno < 0 || recno > 255 || reccount != 1 + || short_ef < 0 || short_ef > 254 ) return gpg_error (GPG_ERR_INV_VALUE); buffer = NULL; @@ -577,7 +583,7 @@ iso7816_read_record (int slot, int recno, int reccount, with an Le of 0. */ sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD, recno, - 0x04, + short_ef? short_ef : 0x04, -1, NULL, 254, &buffer, &bufferlen); diff --git a/scd/iso7816.h b/scd/iso7816.h index 937326b6d..8f2b150e6 100644 --- a/scd/iso7816.h +++ b/scd/iso7816.h @@ -67,6 +67,7 @@ gpg_error_t iso7816_get_challenge (int slot, gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax, unsigned char **result, size_t *resultlen); gpg_error_t iso7816_read_record (int slot, int recno, int reccount, + int short_ef, unsigned char **result, size_t *resultlen); #endif /*ISO7816_H*/ diff --git a/scd/sc-investigate.c b/scd/sc-investigate.c index 6f8b330b1..3882e1dfd 100644 --- a/scd/sc-investigate.c +++ b/scd/sc-investigate.c @@ -50,8 +50,10 @@ enum cmd_and_opt_values { oInteractive = 'i', oVerbose = 'v', + oQuiet = 'q', oReaderPort = 500, octapiDriver, + oDebug, oDebugAll, @@ -68,6 +70,7 @@ static ARGPARSE_OPTS opts[] = { { 301, NULL, 0, "@Options:\n " }, { oInteractive, "interactive", 0, "start in interactive explorer mode"}, + { oQuiet, "quiet", 0, "quiet" }, { oVerbose, "verbose", 0, "verbose" }, { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"}, { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"}, @@ -86,7 +89,7 @@ static ARGPARSE_OPTS opts[] = { static void interactive_shell (int slot); - +static void dump_other_cards (int slot); static const char * my_strusage (int level) @@ -168,6 +171,7 @@ main (int argc, char **argv ) switch (pargs.r_opt) { case oVerbose: opt.verbose++; break; + case oQuiet: opt.quiet++; break; case oDebug: opt.debug |= pargs.r.ret_ulong; break; case oDebugAll: opt.debug = ~0; break; case oReaderPort: reader_port = pargs.r.ret_str; break; @@ -191,7 +195,7 @@ main (int argc, char **argv ) if (slot == -1) exit (1); - if (!gen_random) + if (!gen_random && !opt.quiet) { rc = atr_dump (slot, stdout); if (rc) @@ -210,12 +214,17 @@ main (int argc, char **argv ) rc = app_select_openpgp (&appbuf); if (rc) { - log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc)); + if (!opt.quiet) + log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc)); memset (&appbuf, 0, sizeof appbuf); appbuf.slot = slot; rc = app_select_dinsig (&appbuf); if (rc) - log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc)); + { + if (!opt.quiet) + log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc)); + dump_other_cards (slot); + } else { appbuf.initialized = 1; @@ -398,6 +407,7 @@ interactive_shell (int slot) cmdAPP, cmdREAD, cmdREADREC, + cmdREADSHORTREC, cmdDEBUG, cmdVERIFY, cmdCHANGEREF, @@ -425,6 +435,7 @@ interactive_shell (int slot) { "rb" , cmdREAD, NULL }, { "readrec", cmdREADREC, "read record(s)" }, { "rr" , cmdREADREC, NULL }, + { "rsr" , cmdREADSHORTREC, "readshortrec RECNO SHORT_EF" }, { "verify" , cmdVERIFY, "verify CHVNO PIN" }, { "ver" , cmdVERIFY, NULL }, { "changeref", cmdCHANGEREF, "change reference data" }, @@ -559,7 +570,8 @@ interactive_shell (int slot) for (i=1, err=0; !err; i++) { xfree (result); result = NULL; - err = iso7816_read_record (slot, i, 1, &result, &resultlen); + err = iso7816_read_record (slot, i, 1, 0, + &result, &resultlen); if (!err) dump_buffer (result, resultlen); } @@ -568,13 +580,31 @@ interactive_shell (int slot) } else { - err = iso7816_read_record (slot, arg_number, 1, + err = iso7816_read_record (slot, arg_number, 1, 0, &result, &resultlen); if (!err) dump_or_store_buffer (arg_string, result, resultlen); } break; + case cmdREADSHORTREC: + { + int short_ef; + + short_ef = strtol (arg_next, NULL, 0); + + if (short_ef < 1 || short_ef > 254) + printf ("error: short EF must be between 1 and 254\n"); + else + { + err = iso7816_read_record (slot, arg_number, 1, short_ef, + &result, &resultlen); + if (!err) + dump_or_store_buffer (arg_string, result, resultlen); + } + } + break; + case cmdVERIFY: if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31) printf ("error: invalid CHVNO\n"); @@ -637,3 +667,104 @@ interactive_shell (int slot) ; } + + +/* Figure out whether the current card is a German Geldkarte and print + what we know about it. */ +static int +dump_geldkarte (int slot) +{ + unsigned char *r = NULL; + size_t rlen; + const char *t; + + if (iso7816_read_record (slot, 1, 1, 0xbc, &r, &rlen)) + return -1; + /* We require that the record is at least 24 bytes, the first byte + is 0x67 and the filler byte is correct. */ + if (rlen < 24 || *r != 0x67 || r[22]) + return -1; + + /* The short Bankleitzahl consists of 3 bytes at offset 1. */ + switch (r[1]) + { + case 0x21: t = "Oeffentlich-rechtliche oder private Bank"; break; + case 0x22: t = "Privat- oder Geschäftsbank"; break; + case 0x25: t = "Sparkasse"; break; + case 0x26: + case 0x29: t = "Genossenschaftsbank"; break; + default: + xfree (r); + return -1; /* Probably not a Geldkarte. */ + } + + printf ("KBLZ .....: %02X-%02X%02X (%s)\n", r[1], r[2], r[3], t); + printf ("Card-No ..: %02X%02X%02X%02X%02X\n", r[4], r[5], r[6], r[7], r[8]); + +/* Byte 10 enthält im linken Halbbyte eine Prüfziffer, die nach dem */ +/* Verfahren 'Luhn formula for computing modulus 10' über die Ziffern der */ +/* ersten 9 Byte berechnet ist. */ + +/* Das rechte Halbbyte wird zu 'D' gesetzt. */ + +/* Für die Berechnung der Luhn-Prüfziffer sind die folgenden Schritte */ +/* durchzuführen: */ + +/* Schritt 1: Mit der rechtesten Ziffer beginnend ist einschließlich dieser */ +/* Ziffer jede übernächste Ziffer zu verdoppeln (mit 2 multiplizieren). */ + +/* Schritt 2: Die einzelnen Ziffern der Produkte aus Schritt 1 und die bei */ +/* diesen Multiplikationen unberührt gebliebenen Ziffern sind zu addieren. */ + +/* Schritt 3: Das Ergebnis der Addition aus Schritt 2 ist von dem auf die */ +/* nächst höhere Zahl mit der Einerstelle 0 aufgerundeten Ergebnis der */ +/* Addition aus Schritt 2 abzuziehen. Wenn das Ergebnis der Addition aus */ +/* Schritt 2 bereits eine Zahl mit der Einerstelle 0 ergibt (z.B. 30, 40, */ +/* usw.), ist die Prüfziffer 0. */ + +/* Beispiel: Kartennummer ohne Prüfziffer: 992 839 871 */ + +/* 9 9 2 8 3 9 8 7 1 */ + +/* x 2 x 2 x 2 x 2 x 2 Schritt 1 */ + +/* 18 4 6 16 2 */ + +/* 1+8 +9 +4 +8 +6 +9 +1+6 +7 +2 = 61 Schritt 2 */ + +/* 70-61 = 9 Schritt 3 */ + +/* Prüfziffer zu 992 839 871 = 9 */ + + + printf ("Expires at: %02X/%02X\n", r[11], r[10] ); + printf ("Valid from: %02X.%02X.%02X\n", r[14], r[13], r[12]); + printf ("Country ..: %02X%02X\n", r[15], r[16]); + printf ("Currency .: %c%c%c\n", isascii (r[17])? r[17]:' ', + isascii (r[18])? r[18]:' ', isascii (r[19])? r[19]:' '); + printf ("Cur.-Mult : %s\n", + r[20] == 0x01? "0.01": + r[20] == 0x02? "0.1": + r[20] == 0x04? "1": + r[20] == 0x08? "10": + r[20] == 0x10? "100": + r[20] == 0x20? "1000": "?"); + printf ("ZKA ChipID: %02X\n", r[21]); + printf ("OS version: %02X\n", r[23]); + + xfree (r); + return 0; +} + + + +/* Try to figure out the type of teh card and dump its contents. */ +static void +dump_other_cards (int slot) +{ + + if (!dump_geldkarte (slot)) + return; + +} + diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 2bbf271da..098738508 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -33,14 +33,6 @@ #include "../common/util.h" #include "../common/errors.h" -/* Convenience funcion to be used instead of returning the old - GNUPG_Out_Of_Core. */ -static __inline__ gpg_error_t -out_of_core (void) -{ - return gpg_error (gpg_err_code_from_errno (errno)); -} - #define MAX_DIGEST_LEN 24 |