aboutsummaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2005-07-27 14:18:59 +0000
committerWerner Koch <[email protected]>2005-07-27 14:18:59 +0000
commitcd570629b28f7fe08dba6366a399439a58eecc50 (patch)
tree3d23aea0d919c7ed53a3ad0d3c373cf7b0ca42a3 /scd
parentAdd a note that CVS is beeing migrated to Subversion (diff)
downloadgnupg-cd570629b28f7fe08dba6366a399439a58eecc50.tar.gz
gnupg-cd570629b28f7fe08dba6366a399439a58eecc50.zip
Removed directories which are only used by the 1.9 branch
Diffstat (limited to '')
-rw-r--r--scd/ChangeLog242
-rw-r--r--scd/Makefile.am72
-rw-r--r--scd/apdu.c558
-rw-r--r--scd/apdu.h73
-rw-r--r--scd/app-common.h128
-rw-r--r--scd/app-openpgp.c1482
-rw-r--r--scd/app.c278
-rw-r--r--scd/atr.c287
-rw-r--r--scd/atr.h28
-rw-r--r--scd/card-common.h73
-rw-r--r--scd/card-dinsig.c260
-rw-r--r--scd/card-p15.c502
-rw-r--r--scd/card.c564
-rw-r--r--scd/command.c1034
-rw-r--r--scd/iso7816.c371
-rw-r--r--scd/iso7816.h56
-rw-r--r--scd/sc-copykeys.c731
-rw-r--r--scd/sc-investigate.c209
-rw-r--r--scd/scdaemon.c638
-rw-r--r--scd/scdaemon.h127
20 files changed, 0 insertions, 7713 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog
deleted file mode 100644
index ad4b0518c..000000000
--- a/scd/ChangeLog
+++ /dev/null
@@ -1,242 +0,0 @@
-2003-07-31 Werner Koch <[email protected]>
-
- * Makefile.am (scdaemon_LDADD): Added INTLLIBS.
-
-2003-07-28 Werner Koch <[email protected]>
-
- * app-openpgp.c (do_setattr): Change implementation. Allow all
- useful DOs.
-
-2003-07-27 Werner Koch <[email protected]>
-
- Adjusted for gcry_mpi_print and gcry_mpi_scan API change.
-
-2003-07-24 Werner Koch <[email protected]>
-
- * app-openpgp.c (do_learn_status): Print more status information.
- (app_select_openpgp): Store the card version.
- (store_fpr): Add argument card_version and fix DOs for old cards.
- (app_openpgp_storekey): Likewise.
-
-2003-07-23 Werner Koch <[email protected]>
-
- * command.c (cmd_pkauth): New.
- (cmd_setdata): Check whether data was given at all to avoid
- passing 0 to malloc.
-
- * app.c (app_auth): New.
- * app-openpgp.c (do_auth): New.
-
-2003-07-22 Werner Koch <[email protected]>
-
- * command.c (cmd_passwd): New.
- * app.c (app_change_pin): New.
- * app-openpgp.c (do_change_pin): New.
- * iso7816.c (iso7816_reset_retry_counter): Implemented.
-
- * sc-investigate.c (main): New option --gen-random.
- * iso7816.c (iso7816_get_challenge): Don't create APDUs with a
- length larger than 255.
-
-2003-07-17 Werner Koch <[email protected]>
-
- * command.c (cmd_random): New command RANDOM.
-
- * iso7816.c (map_sw): New. Use it in this file to return
- meaningful error messages. Changed all public fucntions to return
- a gpg_error_t.
- (iso7816_change_reference_data): New.
- * apdu.c (apdu_open_reader): Use faked status words for soem
- system errors.
-
-2003-07-16 Werner Koch <[email protected]>
-
- * apdu.c (apdu_send_simple): Use apdu_send_le so that we can
- specify not to send Le as it should be.
-
-2003-07-15 Werner Koch <[email protected]>
-
- * Makefile.am: Add sc-copykeys program.
- * sc-copykeys.c: New.
- * app-openpgp.c (app_openpgp_storekey): New.
- (app_openpgp_cardinfo): New.
- (count_bits): New.
- (store_fpr): And use it here to get the actual length in bit.
-
-2003-07-03 Werner Koch <[email protected]>
-
- * app-openpgp.c (do_setattr): Add setting of the URL.
- (app_select_openpgp): Dump card data only in very verbose mode.
- (do_decipher): New.
-
-2003-07-02 Werner Koch <[email protected]>
-
- * app-openpgp.c (get_sig_counter): New.
- (do_sign): Print the signature counter and enable the PIN callback.
- (do_genkey): Implement the PIN callback.
-
-2003-07-01 Werner Koch <[email protected]>
-
- * app-openpgp.c (store_fpr): Fixed fingerprint calculation.
-
-2003-06-26 Werner Koch <[email protected]>
-
- * app-openpgp.c (find_tlv): Fixed length header parsing.
-
- * app.c (app_genkey): New.
- * command.c (cmd_genkey): New.
-
-2003-06-25 Werner Koch <[email protected]>
-
- * command.c (percent_plus_unescape): New.
- (cmd_setattr): New.
-
-2003-06-24 Werner Koch <[email protected]>
-
- * command.c (send_status_info): New.
-
- * app-openpgp.c (app_select_openpgp): Replace SLOT arg by APP arg
- and setup the function pointers in APP on success. Changed callers.
- * app.c: New.
- * app-common.h: New.
- * scdaemon.h (APP): New type to handle applications.
- (server_control_s): Add an APP context field.
-
- * command.c (cmd_serialno): Handle applications.
- (cmd_pksign): Ditto.
- (cmd_pkdecrypt): Ditto.
- (reset_notify): Ditto.
- (cmd_learn): For now return error for application contexts.
- (cmd_readcert): Ditto.
- (cmd_readkey): Ditto.
-
-2003-06-04 Werner Koch <[email protected]>
-
- * card.c (map_sc_err): Renamed gpg_make_err to gpg_err_make.
-
- Renamed error codes from INVALID to INV and removed _ERROR suffixes.
-
-2003-06-03 Werner Koch <[email protected]>
-
- Changed all error codes in all files to the new libgpg-error scheme.
-
- * scdaemon.h: Include gpg-error.h and errno.h
- * card.c (map_sc_err): Use unknown for the error source.
- * Makefile.am: Link with libgpg-error
-
-2003-05-14 Werner Koch <[email protected]>
-
- * atr.c, atr.h: New.
- * sc-investigate.c: Dump the ATR in a human readable format.
-
-2003-05-08 Werner Koch <[email protected]>
-
- * scdaemon.h (DBG_CARD_IO_VALUE): New.
-
- * sc-investigate.c: New.
- * scdaemon.c (main): Removed --print-atr option.
-
- * iso7816.c, iso7816.h, app-openpgp.c: New.
-
-2003-04-29 Werner Koch <[email protected]>
-
- * scdaemon.c: New options --print-atr and --reader-port
- * apdu.c, apdu.h: New
-
- * card.c, card-p15.c, card-dinsig.c: Allow build without OpenSC.
-
- * Makefile.am (LDFLAGS): Removed.
-
- * command.c (register_commands): Adjusted for new Assuan semantics.
-
-2002-08-21 Werner Koch <[email protected]>
-
- * scdaemon.c (main): New option --daemon so that the program is
- not accidently started in the background.
-
-2002-08-16 Werner Koch <[email protected]>
-
- * scdaemon.c: Include i18n.h.
-
- * card-common.h (struct p15_private_s): Forward declaration. Add
- it to card_ctx_s.
- * card.c (card_close): Make sure private data is released.
- (card_enum_certs): New.
- * card-p15.c (p15_release_private_data): New.
- (init_private_data): New to work around an OpenSC weirdness.
- (p15_enum_keypairs): Do an OpenSC get_objects only once.
- (p15_enum_certs): New.
- (card_p15_bind): Bind new function.
- * command.c (cmd_learn): Return information about the certificates.
-
-2002-08-09 Werner Koch <[email protected]>
-
- * card.c (card_get_serial_and_stamp): Use the tokeinfo serial
- number as a fallback. Add a special prefix for serial numbers.
-
-2002-07-30 Werner Koch <[email protected]>
-
- Changes to cope with OpenSC 0.7.0:
-
- * card.c: Removed the check for the packed opensc version.
- Changed include file names of opensc.
- (map_sc_err): Adjusted error codes for new opensc version.
- * card-p15.c: Changed include filename of opensc.
- * card-dinsig.c: Ditto.
-
- * card-p15.c (p15_decipher): Add flags argument to OpenSC call.
-
-2002-07-24 Werner Koch <[email protected]>
-
- * card.c (find_simple_tlv, find_iccsn): New.
- (card_get_serial_and_stamp): Improved serial number parser.
-
-2002-06-27 Werner Koch <[email protected]>
-
- * scdaemon.c (main): Use GNUPG_DEFAULT_HOMEDIR constant.
-
-2002-06-15 Werner Koch <[email protected]>
-
- * card-dinsig.c: Documented some stuff from the DIN norm.
-
-2002-04-15 Werner Koch <[email protected]>
-
- * command.c (cmd_pksign, cmd_pkdecrypt): Use a copy of the key ID.
-
-2002-04-12 Werner Koch <[email protected]>
-
- * scdaemon.c: New option --debug-sc N.
- * card.c (card_open): set it here.
-
- * card-p15.c (p15_prepare_key): Factored out common code from ...
- (p15_sign, p15_decipher): here and made the decryption work the
- regular way.
-
-2002-04-10 Werner Koch <[email protected]>
-
- * card.c (card_open): Return immediately when no reader is available.
-
-2002-03-27 Werner Koch <[email protected]>
-
- * card.c (card_open, card_close): Adjusted for changes in OpenSC.
-
-2002-03-10 Werner Koch <[email protected]>
-
- * card-p15.c, card-dinsig.c, card-common.h: New.
- * card.c: Factored most code out to the new modules, so that we
- can better support different types of card applications.
-
-2002-01-26 Werner Koch <[email protected]>
-
- * scdaemon.c scdaemon.h, command.c: New. Based on the code from
- the gpg-agent.
-
- Copyright 2002 Free Software Foundation, Inc.
-
- This file is free software; as a special exception the author gives
- unlimited permission to copy and/or distribute it, with or without
- modifications, as long as this notice is preserved.
-
- This file is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
- implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
diff --git a/scd/Makefile.am b/scd/Makefile.am
deleted file mode 100644
index 0771beb60..000000000
--- a/scd/Makefile.am
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (C) 2002, 2003 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 2 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, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
-
-## Process this file with automake to produce Makefile.in
-
-localedir = $(datadir)/locale
-INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\"
-
-bin_PROGRAMS = scdaemon sc-investigate sc-copykeys
-
-AM_CPPFLAGS = -I$(top_srcdir)/common $(OPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \
- $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS)
-
-scdaemon_SOURCES = \
- scdaemon.c scdaemon.h \
- command.c card.c \
- card-common.h \
- card-p15.c card-dinsig.c \
- apdu.c apdu.h \
- iso7816.c iso7816.h \
- app.c app-common.h \
- app-openpgp.c
-
-scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \
- $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \
- -lgpg-error @INTLLIBS@ -ldl
-
-sc_investigate_SOURCES = \
- sc-investigate.c scdaemon.h \
- apdu.c apdu.h \
- iso7816.c iso7816.h \
- app.c app-common.h \
- app-openpgp.c \
- atr.c atr.h
-
-sc_investigate_LDADD = \
- ../jnlib/libjnlib.a ../common/libcommon.a \
- $(LIBGCRYPT_LIBS) @INTLLIBS@ -lgpg-error -ldl
-
-
-sc_copykeys_SOURCES = \
- sc-copykeys.c scdaemon.h \
- apdu.c apdu.h \
- iso7816.c iso7816.h \
- app.c app-common.h \
- app-openpgp.c \
- atr.c atr.h
-
-sc_copykeys_LDADD = \
- ../jnlib/libjnlib.a ../common/libcommon.a \
- ../common/libsimple-pwquery.a \
- $(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@ -ldl
-
-
-
-
-
diff --git a/scd/apdu.c b/scd/apdu.c
deleted file mode 100644
index 6fec584b9..000000000
--- a/scd/apdu.c
+++ /dev/null
@@ -1,558 +0,0 @@
-/* apdu.c - ISO 7816 APDU functions and low level I/O
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dlfcn.h>
-#include <assert.h>
-
-#include "scdaemon.h"
-#include "apdu.h"
-
-#define HAVE_CTAPI 1
-
-#define MAX_READER 4 /* Number of readers we support concurrently. */
-#define CARD_CONNECT_TIMEOUT 1 /* Number of seconds to wait for
- insertion of the card (1 = don't wait). */
-
-
-
-/* A global table to keep track of active readers. */
-static struct {
- int used; /* True if slot is used. */
- unsigned short port; /* port number0 = unused, 1 - dev/tty */
- int status;
- unsigned char atr[33];
- size_t atrlen;
-} reader_table[MAX_READER];
-
-
-/* ct API function pointer. */
-static char (*CT_init) (unsigned short ctn, unsigned short Pn);
-static char (*CT_data) (unsigned short ctn, unsigned char *dad,
- unsigned char *sad, unsigned short lc,
- unsigned char *cmd, unsigned short *lr,
- unsigned char *rsp);
-static char (*CT_close) (unsigned short ctn);
-
-
-
-
-
-/*
- Helper
- */
-
-
-/* Find an unused reader slot for PORT and put it into the reader
- table. Return -1 on error or the index into the reader table. */
-static int
-new_reader_slot (int port)
-{
- int i, reader = -1;
-
- if (port < 0 || port > 0xffff)
- {
- log_error ("new_reader_slot: invalid port %d requested\n", port);
- return -1;
- }
-
- for (i=0; i < MAX_READER; i++)
- {
- if (reader_table[i].used && reader_table[i].port == port)
- {
- log_error ("new_reader_slot: requested port %d already in use\n",
- reader);
- return -1;
- }
- else if (!reader_table[i].used && reader == -1)
- reader = i;
- }
- if (reader == -1)
- {
- log_error ("new_reader_slot: out of slots\n");
- return -1;
- }
- reader_table[reader].used = 1;
- reader_table[reader].port = port;
- return reader;
-}
-
-
-static void
-dump_reader_status (int reader)
-{
- log_info ("reader %d: %s\n", reader,
- reader_table[reader].status == 1? "Processor ICC present" :
- reader_table[reader].status == 0? "Memory ICC present" :
- "ICC not present" );
-
- if (reader_table[reader].status != -1)
- {
- log_info ("reader %d: ATR=", reader);
- log_printhex ("", reader_table[reader].atr,
- reader_table[reader].atrlen);
- }
-}
-
-
-
-#ifdef HAVE_CTAPI
-/*
- ct API Interface
- */
-
-static const char *
-ct_error_string (int err)
-{
- switch (err)
- {
- case 0: return "okay";
- case -1: return "invalid data";
- case -8: return "ct error";
- case -10: return "transmission error";
- case -11: return "memory allocation error";
- case -128: return "HTSI error";
- default: return "unknown CT-API error";
- }
-}
-
-/* Wait for the card in READER and activate it. Return -1 on error or
- 0 on success. */
-static int
-ct_activate_card (int reader)
-{
- int rc, count;
-
- for (count = 0; count < CARD_CONNECT_TIMEOUT; count++)
- {
- unsigned char dad[1], sad[1], cmd[11], buf[256];
- unsigned short buflen;
-
- if (count)
- sleep (1); /* FIXME: we should use a more reliable timer. */
-
- /* Check whether card has been inserted. */
- dad[0] = 1; /* Destination address: CT. */
- sad[0] = 2; /* Source address: Host. */
-
- cmd[0] = 0x20; /* Class byte. */
- cmd[1] = 0x13; /* Request status. */
- cmd[2] = 0x00; /* From kernel. */
- cmd[3] = 0x80; /* Return card's DO. */
- cmd[4] = 0x00;
-
- buflen = DIM(buf);
-
- rc = CT_data (reader, dad, sad, 5, cmd, &buflen, buf);
- if (rc || buflen < 2 || buf[buflen-2] != 0x90)
- {
- log_error ("ct_activate_card: can't get status of reader %d: %s\n",
- reader, ct_error_string (rc));
- return -1;
- }
-
- if (buf[0] == 0x05)
- { /* Connected, now activate the card. */
- dad[0] = 1; /* Destination address: CT. */
- sad[0] = 2; /* Source address: Host. */
-
- cmd[0] = 0x20; /* Class byte. */
- cmd[1] = 0x12; /* Request ICC. */
- cmd[2] = 0x01; /* From first interface. */
- cmd[3] = 0x01; /* Return card's ATR. */
- cmd[4] = 0x00;
-
- buflen = DIM(buf);
-
- rc = CT_data (reader, dad, sad, 5, cmd, &buflen, buf);
- if (rc || buflen < 2 || buf[buflen-2] != 0x90)
- {
- log_error ("ct_activate_card(%d): activation failed: %s\n",
- reader, ct_error_string (rc));
- return -1;
- }
-
- /* Store the type and the ATR. */
- if (buflen - 2 > DIM (reader_table[0].atr))
- {
- log_error ("ct_activate_card(%d): ATR too long\n", reader);
- return -1;
- }
-
- reader_table[reader].status = buf[buflen - 1];
- memcpy (reader_table[reader].atr, buf, buflen - 2);
- reader_table[reader].atrlen = buflen - 2;
- return 0;
- }
-
- }
-
- log_info ("ct_activate_card(%d): timeout waiting for card\n", reader);
- return -1;
-}
-
-
-/* Open a reader and return an internal handle for it. PORT is a
- non-negative value with the port number of the reader. USB readers
- do have port numbers starting at 32769. */
-static int
-open_ct_reader (int port)
-{
- int rc, reader;
-
- reader = new_reader_slot (port);
- if (reader == -1)
- return reader;
-
- rc = CT_init (reader, (unsigned short)port);
- if (rc)
- {
- log_error ("apdu_open_ct_reader failed on port %d: %s\n",
- port, ct_error_string (rc));
- reader_table[reader].used = 0;
- return -1;
- }
-
- rc = ct_activate_card (reader);
- if (rc)
- {
- reader_table[reader].used = 0;
- return -1;
- }
-
- dump_reader_status (reader);
- return reader;
-}
-
-
-/* Actually send the APDU of length APDULEN to SLOT and return a
- maximum of *BUFLEN data in BUFFER, the actual retruned size will be
- set to BUFLEN. Returns: CT API error code. */
-static int
-ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
- unsigned char *buffer, size_t *buflen)
-{
- int rc;
- unsigned char dad[1], sad[1];
- unsigned short ctbuflen;
-
- dad[0] = 0; /* Destination address: Card. */
- sad[0] = 2; /* Source address: Host. */
- ctbuflen = *buflen;
- if (DBG_CARD_IO)
- log_printhex (" CT_data:", apdu, apdulen);
- rc = CT_data (slot, dad, sad, apdulen, apdu, &ctbuflen, buffer);
- *buflen = ctbuflen;
-
- /* FIXME: map the errorcodes to GNUPG ones, so that they can be
- shared between CTAPI and PCSC. */
- return rc;
-}
-
-
-#endif /*HAVE_CTAPI*/
-
-
-#ifdef HAVE_PCSC
-/*
- PC/SC Interface
- */
-
-
-#endif /*HAVE_PCSC*/
-
-
-/*
- Driver Access
- */
-
-/* Open the reader and return an internal slot number or -1 on
- error. */
-int
-apdu_open_reader (int port)
-{
- static int ct_api_loaded;
-
- if (!ct_api_loaded)
- {
- void *handle;
-
- handle = dlopen ("libtowitoko.so", RTLD_LAZY);
- if (!handle)
- {
- log_error ("apdu_open_reader: failed to open driver: %s",
- dlerror ());
- return -1;
- }
- CT_init = dlsym (handle, "CT_init");
- CT_data = dlsym (handle, "CT_data");
- CT_close = dlsym (handle, "CT_close");
- if (!CT_init || !CT_data || !CT_close)
- {
- log_error ("apdu_open_reader: invalid driver\n");
- dlclose (handle);
- return -1;
- }
- ct_api_loaded = 1;
- }
- return open_ct_reader (port);
-}
-
-
-unsigned char *
-apdu_get_atr (int slot, size_t *atrlen)
-{
- char *buf;
-
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return NULL;
-
- buf = xtrymalloc (reader_table[slot].atrlen);
- if (!buf)
- return NULL;
- memcpy (buf, reader_table[slot].atr, reader_table[slot].atrlen);
- *atrlen = reader_table[slot].atrlen;
- return buf;
-}
-
-
-static const char *
-error_string (int slot, int rc)
-{
-#ifdef HAVE_CTAPI
- return ct_error_string (rc);
-#elif defined(HAVE_PCSC)
- return "?";
-#else
- return "?";
-#endif
-}
-
-
-/* Dispatcher for the actual send_apdu fucntion. */
-static int
-send_apdu (int slot, unsigned char *apdu, size_t apdulen,
- unsigned char *buffer, size_t *buflen)
-{
-#ifdef HAVE_CTAPI
- return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
-#elif defined(HAVE_PCSC)
- return SW_HOST_NO_DRIVER;
-#else
- return SW_HOST_NO_DRIVER;
-#endif
-}
-
-/* Send an APDU to the card in SLOT. The APDU is created from all
- given parameters: CLASS, INS, P0, P1, LC, DATA, LE. A value of -1
- for LC won't sent this field and the data field; in this case DATA
- must also be passed as NULL. The return value is the status word
- or -1 for an invalid SLOT or other non card related error. If
- RETBUF is not NULL, it will receive an allocated buffer with the
- returned data. The length of that data will be put into
- *RETBUFLEN. The caller is reponsible for releasing the buffer even
- in case of errors. */
-int
-apdu_send_le(int slot, int class, int ins, int p0, int p1,
- int lc, const char *data, int le,
- unsigned char **retbuf, size_t *retbuflen)
-{
- unsigned char result[256+10]; /* 10 extra in case of bugs in the driver. */
- size_t resultlen = 256;
- unsigned char apdu[5+256+1];
- size_t apdulen;
- int rc, sw;
-
- if (DBG_CARD_IO)
- log_debug ("send apdu: c=%02X i=%02X p0=%02X p1=%02X lc=%d le=%d\n",
- class, ins, p0, p1, lc, le);
-
- if (lc != -1 && (lc > 255 || lc < 0))
- return SW_WRONG_LENGTH;
- if (le != -1 && (le > 256 || le < 1))
- return SW_WRONG_LENGTH;
- if ((!data && lc != -1) || (data && lc == -1))
- return SW_HOST_INV_VALUE;
-
- apdulen = 0;
- apdu[apdulen++] = class;
- apdu[apdulen++] = ins;
- apdu[apdulen++] = p0;
- apdu[apdulen++] = p1;
- if (lc != -1)
- {
- apdu[apdulen++] = lc;
- memcpy (apdu+apdulen, data, lc);
- apdulen += lc;
- }
- if (le != -1)
- apdu[apdulen++] = le; /* Truncation is okay becuase 0 means 256. */
- assert (sizeof (apdu) >= apdulen);
- /* As safeguard don't pass any garbage from the stack to the driver. */
- memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
- rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
- if (rc || resultlen < 2)
- {
- log_error ("apdu_send_simple(%d) failed: %s\n",
- slot, error_string (slot, rc));
- return SW_HOST_INCOMPLETE_CARD_RESPONSE;
- }
- sw = (result[resultlen-2] << 8) | result[resultlen-1];
- /* store away the returned data but strip the statusword. */
- resultlen -= 2;
- if (DBG_CARD_IO)
- {
- log_debug (" response: sw=%04X datalen=%d\n", sw, resultlen);
- if ( !retbuf && (sw == SW_SUCCESS || (sw & 0xff00) == SW_MORE_DATA))
- log_printhex (" dump: ", result, resultlen);
- }
-
- if (sw == SW_SUCCESS)
- {
- if (retbuf)
- {
- *retbuf = xtrymalloc (resultlen? resultlen : 1);
- if (!*retbuf)
- return SW_HOST_OUT_OF_CORE;
- *retbuflen = resultlen;
- memcpy (*retbuf, result, resultlen);
- }
- }
- else if ((sw & 0xff00) == SW_MORE_DATA)
- {
- unsigned char *p = NULL, *tmp;
- size_t bufsize = 4096;
-
- /* It is likely that we need to return much more data, so we
- start off with a large buffer. */
- if (retbuf)
- {
- *retbuf = p = xtrymalloc (bufsize);
- if (!*retbuf)
- return SW_HOST_OUT_OF_CORE;
- assert (resultlen < bufsize);
- memcpy (p, result, resultlen);
- p += resultlen;
- }
-
- do
- {
- int len = (sw & 0x00ff);
-
- log_debug ("apdu_send_simple(%d): %d more bytes available\n",
- slot, len);
- apdulen = 0;
- apdu[apdulen++] = class;
- apdu[apdulen++] = 0xC0;
- apdu[apdulen++] = 0;
- apdu[apdulen++] = 0;
- apdu[apdulen++] = 64; /* that is 256 bytes for Le */
- memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
- rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
- if (rc || resultlen < 2)
- {
- log_error ("apdu_send_simple(%d) for get response failed: %s\n",
- slot, error_string (slot, rc));
- return SW_HOST_INCOMPLETE_CARD_RESPONSE;
- }
- sw = (result[resultlen-2] << 8) | result[resultlen-1];
- resultlen -= 2;
- if (DBG_CARD_IO)
- {
- log_debug (" more: sw=%04X datalen=%d\n", sw, resultlen);
- if (!retbuf && (sw==SW_SUCCESS || (sw&0xff00)==SW_MORE_DATA))
- log_printhex (" dump: ", result, resultlen);
- }
-
- if ((sw & 0xff00) == SW_MORE_DATA || sw == SW_SUCCESS)
- {
- if (retbuf)
- {
- if (p - *retbuf + resultlen > bufsize)
- {
- bufsize += resultlen > 4096? resultlen: 4096;
- tmp = xtryrealloc (*retbuf, bufsize);
- if (!tmp)
- return SW_HOST_OUT_OF_CORE;
- p = tmp + (p - *retbuf);
- *retbuf = tmp;
- }
- memcpy (p, result, resultlen);
- p += resultlen;
- }
- }
- else
- log_info ("apdu_send_simple(%d) "
- "got unexpected status %04X from get response\n",
- slot, sw);
- }
- while ((sw & 0xff00) == SW_MORE_DATA);
-
- if (retbuf)
- {
- *retbuflen = p - *retbuf;
- tmp = xtryrealloc (*retbuf, *retbuflen);
- if (tmp)
- *retbuf = tmp;
- }
- }
- if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS)
- log_printhex (" dump: ", *retbuf, *retbuflen);
-
- return sw;
-}
-
-/* Send an APDU to the card in SLOT. The APDU is created from all
- given parameters: CLASS, INS, P0, P1, LC, DATA. A value of -1 for
- LC won't sent this field and the data field; in this case DATA must
- also be passed as NULL. The return value is the status word or -1
- for an invalid SLOT or other non card related error. If RETBUF is
- not NULL, it will receive an allocated buffer with the returned
- data. The length of that data will be put into *RETBUFLEN. The
- caller is reponsible for releasing the buffer even in case of
- errors. */
-int
-apdu_send (int slot, int class, int ins, int p0, int p1,
- int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
-{
- return apdu_send_le (slot, class, ins, p0, p1, lc, data, 256,
- retbuf, retbuflen);
-}
-
-/* Send an APDU to the card in SLOT. The APDU is created from all
- given parameters: CLASS, INS, P0, P1, LC, DATA. A value of -1 for
- LC won't sent this field and the data field; in this case DATA must
- also be passed as NULL. The return value is the status word or -1
- for an invalid SLOT or other non card related error. No data will be
- returned. */
-int
-apdu_send_simple (int slot, int class, int ins, int p0, int p1,
- int lc, const char *data)
-{
- return apdu_send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL);
-}
-
-
-
-
diff --git a/scd/apdu.h b/scd/apdu.h
deleted file mode 100644
index 44166a3fe..000000000
--- a/scd/apdu.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* apdu.h - ISO 7816 APDU functions and low level I/O
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef APDU_H
-#define APDU_H
-
-/* ISO 7816 values for the statusword are defined here because they
- should not be visible to the users of the actual ISO command
- API. */
-enum {
- SW_MORE_DATA = 0x6100, /* Note: that the low byte must be
- masked of.*/
- SW_EEPROM_FAILURE = 0x6581,
- SW_WRONG_LENGTH = 0x6700,
- SW_CHV_WRONG = 0x6982,
- SW_CHV_BLOCKED = 0x6983,
- SW_USE_CONDITIONS = 0x6985,
- SW_NOT_SUPPORTED = 0x6a81,
- SW_BAD_PARAMETER = 0x6a80, /* (in the data field) */
- SW_REF_NOT_FOUND = 0x6a88,
- SW_BAD_P0_P1 = 0x6b00,
- SW_INS_NOT_SUP = 0x6d00,
- SW_CLA_NOT_SUP = 0x6e00,
- SW_SUCCESS = 0x9000,
-
- /* The follwoing statuswords are no real ones but used to map host
- OS errors into status words. A status word is 16 bit so that
- those values can't be issued by a card. */
- SW_HOST_OUT_OF_CORE = 0x10001, /* No way yet to differentiate
- between errnos on a failed malloc. */
- SW_HOST_INV_VALUE = 0x10002,
- SW_HOST_INCOMPLETE_CARD_RESPONSE = 0x10003,
-};
-
-
-
-/* Note , that apdu_open_reader returns no status word but -1 on error. */
-int apdu_open_reader (int port);
-unsigned char *apdu_get_atr (int slot, size_t *atrlen);
-
-
-/* The apdu send functions do return status words. */
-int apdu_send_simple (int slot, int class, int ins, int p0, int p1,
- int lc, const char *data);
-int apdu_send (int slot, int class, int ins, int p0, int p1,
- int lc, const char *data,
- unsigned char **retbuf, size_t *retbuflen);
-int apdu_send_le (int slot, int class, int ins, int p0, int p1,
- int lc, const char *data, int le,
- unsigned char **retbuf, size_t *retbuflen);
-
-
-#endif /*APDU_H*/
-
-
-
diff --git a/scd/app-common.h b/scd/app-common.h
deleted file mode 100644
index 282f82715..000000000
--- a/scd/app-common.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* app-common.h - Common declarations for all card applications
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef GNUPG_SCD_APP_COMMON_H
-#define GNUPG_SCD_APP_COMMON_H
-
-struct app_ctx_s {
- int initialized; /* The application has been initialied and the
- function pointers may be used. Note that for
- unsupported operations the particular
- function pointer is set to NULL */
- int slot; /* Used reader. */
- unsigned char *serialno; /* Serialnumber in raw form, allocated. */
- size_t serialnolen; /* Length in octets of serialnumber. */
- unsigned int card_version;
- int did_chv1;
- int did_chv2;
- int did_chv3;
- struct {
- int (*learn_status) (APP app, CTRL ctrl);
- int (*setattr) (APP app, const char *name,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const unsigned char *value, size_t valuelen);
- int (*sign) (APP app,
- const char *keyidstr, int hashalgo,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen );
- int (*auth) (APP app, const char *keyidstr,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen);
- int (*decipher) (APP app, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen);
- int (*genkey) (APP app, CTRL ctrl,
- const char *keynostr, unsigned int flags,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
- int (*change_pin) (APP app, CTRL ctrl,
- const char *chvnostr, int reset_mode,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
- } fnc;
-
-
-};
-
-/*-- app.c --*/
-APP select_application (void);
-int app_get_serial_and_stamp (APP app, char **serial, time_t *stamp);
-int app_write_learn_status (APP app, CTRL ctrl);
-int app_setattr (APP app, const char *name,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const unsigned char *value, size_t valuelen);
-int app_sign (APP app, const char *keyidstr, int hashalgo,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen );
-int app_auth (APP app, const char *keyidstr,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen);
-int app_decipher (APP app, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen );
-int app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
-int app_get_challenge (APP app, size_t nbytes, unsigned char *buffer);
-int app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
-
-
-/*-- app-openpgp.c --*/
-int app_select_openpgp (APP app, unsigned char **sn, size_t *snlen);
-
-int app_openpgp_cardinfo (APP app,
- char **serialno,
- char **disp_name,
- char **pubkey_url,
- unsigned char **fpr1,
- unsigned char **fpr2,
- unsigned char **fpr3);
-int app_openpgp_storekey (APP app, int keyno,
- unsigned char *template, size_t template_len,
- time_t created_at,
- const unsigned char *m, size_t mlen,
- const unsigned char *e, size_t elen,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
-int app_openpgp_readkey (APP app, int keyno,
- unsigned char **m, size_t *mlen,
- unsigned char **e, size_t *elen);
-
-
-#endif /*GNUPG_SCD_APP_COMMON_H*/
-
-
-
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
deleted file mode 100644
index 09a19699d..000000000
--- a/scd/app-openpgp.c
+++ /dev/null
@@ -1,1482 +0,0 @@
-/* app-openpgp.c - The OpenPGP card application.
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#include "scdaemon.h"
-#include "app-common.h"
-#include "iso7816.h"
-
-
-
-static struct {
- int tag;
- int constructed;
- int get_from; /* Constructed DO with this DO or 0 for direct access. */
- int binary;
- char *desc;
-} data_objects[] = {
- { 0x005E, 0, 0, 1, "Login Data" },
- { 0x5F50, 0, 0, 0, "URL" },
- { 0x0065, 1, 0, 1, "Cardholder Related Data"},
- { 0x005B, 0, 0x65, 0, "Name" },
- { 0x5F2D, 0, 0x65, 0, "Language preferences" },
- { 0x5F35, 0, 0x65, 0, "Sex" },
- { 0x006E, 1, 0, 1, "Application Related Data" },
- { 0x004F, 0, 0x6E, 1, "AID" },
- { 0x0073, 1, 0, 1, "Discretionary Data Objects" },
- { 0x0047, 0, 0x6E, 1, "Card Capabilities" },
- { 0x00C0, 0, 0x6E, 1, "Extended Card Capabilities" },
- { 0x00C1, 0, 0x6E, 1, "Algorithm Attributes Signature" },
- { 0x00C2, 0, 0x6E, 1, "Algorithm Attributes Decryption" },
- { 0x00C3, 0, 0x6E, 1, "Algorithm Attributes Authentication" },
- { 0x00C4, 0, 0x6E, 1, "CHV Status Bytes" },
- { 0x00C5, 0, 0x6E, 1, "Fingerprints" },
- { 0x00C6, 0, 0x6E, 1, "CA Fingerprints" },
- { 0x007A, 1, 0, 1, "Security Support Template" },
- { 0x0093, 0, 0x7A, 1, "Digital Signature Counter" },
- { 0 }
-};
-
-
-static unsigned long get_sig_counter (APP app);
-
-
-/* Locate a TLV encoded data object in BUFFER of LENGTH and
- return a pointer to value as well as its length in NBYTES. Return
- NULL if it was not found. Note, that the function does not check
- whether the value fits into the provided buffer.
-
- FIXME: Move this to an extra file, it is mostly duplicated from card.c.
-*/
-static const unsigned char *
-find_tlv (const unsigned char *buffer, size_t length,
- int tag, size_t *nbytes, int nestlevel)
-{
- const unsigned char *s = buffer;
- size_t n = length;
- size_t len;
- int this_tag;
- int composite;
-
- for (;;)
- {
- buffer = s;
- if (n < 2)
- return NULL; /* buffer definitely too short for tag and length. */
- if (!*s || *s == 0xff)
- { /* Skip optional filler between TLV objects. */
- s++;
- n--;
- continue;
- }
- composite = !!(*s & 0x20);
- if ((*s & 0x1f) == 0x1f)
- { /* more tag bytes to follow */
- s++;
- n--;
- if (n < 2)
- return NULL; /* buffer definitely too short for tag and length. */
- if ((*s & 0x1f) == 0x1f)
- return NULL; /* We support only up to 2 bytes. */
- this_tag = (s[-1] << 8) | (s[0] & 0x7f);
- }
- else
- this_tag = s[0];
- len = s[1];
- s += 2; n -= 2;
- if (len < 0x80)
- ;
- else if (len == 0x81)
- { /* One byte length follows. */
- if (!n)
- return NULL; /* we expected 1 more bytes with the length. */
- len = s[0];
- s++; n--;
- }
- else if (len == 0x82)
- { /* Two byte length follows. */
- if (n < 2)
- return NULL; /* we expected 2 more bytes with the length. */
- len = (s[0] << 8) | s[1];
- s += 2; n -= 2;
- }
- else
- return NULL; /* APDU limit is 65535, thus it does not make
- sense to assume longer length fields. */
-
- if (composite && nestlevel < 100)
- { /* Dive into this composite DO after checking for too deep
- nesting. */
- const unsigned char *tmp_s;
- size_t tmp_len;
-
- tmp_s = find_tlv (s, len, tag, &tmp_len, nestlevel+1);
- if (tmp_s)
- {
- *nbytes = tmp_len;
- return tmp_s;
- }
- }
-
- if (this_tag == tag)
- {
- *nbytes = len;
- return s;
- }
- if (len > n)
- return NULL; /* buffer too short to skip to the next tag. */
- s += len; n -= len;
- }
-}
-
-
-/* Get the DO identified by TAG from the card in SLOT and return a
- buffer with its content in RESULT and NBYTES. The return value is
- NULL if not found or a pointer which must be used to release the
- buffer holding value. */
-static void *
-get_one_do (int slot, int tag, unsigned char **result, size_t *nbytes)
-{
- int rc, i;
- unsigned char *buffer;
- size_t buflen;
- unsigned char *value;
- size_t valuelen;
-
- *result = NULL;
- *nbytes = 0;
- for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++)
- ;
-
- value = NULL;
- rc = -1;
- if (data_objects[i].tag && data_objects[i].get_from)
- {
- rc = iso7816_get_data (slot, data_objects[i].get_from,
- &buffer, &buflen);
- if (!rc)
- {
- const unsigned char *s;
-
- s = find_tlv (buffer, buflen, tag, &valuelen, 0);
- if (!s)
- value = NULL; /* not found */
- else if (valuelen > buflen - (s - buffer))
- {
- log_error ("warning: constructed DO too short\n");
- value = NULL;
- xfree (buffer); buffer = NULL;
- }
- else
- value = buffer + (s - buffer);
- }
- }
-
- if (!value) /* Not in a constructed DO, try simple. */
- {
- rc = iso7816_get_data (slot, tag, &buffer, &buflen);
- if (!rc)
- {
- value = buffer;
- valuelen = buflen;
- }
- }
-
- if (!rc)
- {
- *nbytes = valuelen;
- *result = value;
- return buffer;
- }
- return NULL;
-}
-
-#if 0 /* not used */
-static void
-dump_one_do (int slot, int tag)
-{
- int rc, i;
- unsigned char *buffer;
- size_t buflen;
- const char *desc;
- int binary;
- const unsigned char *value;
- size_t valuelen;
-
- for (i=0; data_objects[i].tag && data_objects[i].tag != tag; i++)
- ;
- desc = data_objects[i].tag? data_objects[i].desc : "?";
- binary = data_objects[i].tag? data_objects[i].binary : 1;
-
- value = NULL;
- rc = -1;
- if (data_objects[i].tag && data_objects[i].get_from)
- {
- rc = iso7816_get_data (slot, data_objects[i].get_from,
- &buffer, &buflen);
- if (!rc)
- {
- value = find_tlv (buffer, buflen, tag, &valuelen, 0);
- if (!value)
- ; /* not found */
- else if (valuelen > buflen - (value - buffer))
- {
- log_error ("warning: constructed DO too short\n");
- value = NULL;
- xfree (buffer); buffer = NULL;
- }
- }
- }
-
- if (!value) /* Not in a constructed DO, try simple. */
- {
- rc = iso7816_get_data (slot, tag, &buffer, &buflen);
- if (!rc)
- {
- value = buffer;
- valuelen = buflen;
- }
- }
- if (rc == 0x6a88)
- log_info ("DO `%s' not available\n", desc);
- else if (rc)
- log_info ("DO `%s' not available (rc=%04X)\n", desc, rc);
- else
- {
- if (binary)
- {
- log_info ("DO `%s': ", desc);
- log_printhex ("", value, valuelen);
- }
- else
- log_info ("DO `%s': `%.*s'\n",
- desc, (int)valuelen, value); /* FIXME: sanitize */
- xfree (buffer);
- }
-}
-#endif /*not used*/
-
-
-static void
-dump_all_do (int slot)
-{
- int rc, i, j;
- unsigned char *buffer;
- size_t buflen;
-
- for (i=0; data_objects[i].tag; i++)
- {
- if (data_objects[i].get_from)
- continue;
-
- rc = iso7816_get_data (slot, data_objects[i].tag, &buffer, &buflen);
- if (rc == 0x6a88)
- ;
- else if (rc)
- log_info ("DO `%s' not available (rc=%04X)\n",
- data_objects[i].desc, rc);
- else
- {
- if (data_objects[i].binary)
- {
- log_info ("DO `%s': ", data_objects[i].desc);
- log_printhex ("", buffer, buflen);
- }
- else
- log_info ("DO `%s': `%.*s'\n",
- data_objects[i].desc,
- (int)buflen, buffer); /* FIXME: sanitize */
- }
-
- if (data_objects[i].constructed)
- {
- for (j=0; data_objects[j].tag; j++)
- {
- const unsigned char *value;
- size_t valuelen;
-
- if (j==i || data_objects[i].tag != data_objects[j].get_from)
- continue;
- value = find_tlv (buffer, buflen,
- data_objects[j].tag, &valuelen, 0);
- if (!value)
- ; /* not found */
- else if (valuelen > buflen - (value - buffer))
- log_error ("warning: constructed DO too short\n");
- else
- {
- if (data_objects[j].binary)
- {
- log_info ("DO `%s': ", data_objects[j].desc);
- log_printhex ("", value, valuelen);
- }
- else
- log_info ("DO `%s': `%.*s'\n",
- data_objects[j].desc,
- (int)valuelen, value); /* FIXME: sanitize */
- }
- }
- }
- xfree (buffer); buffer = NULL;
- }
-}
-
-
-/* Count the number of bits, assuming the A represents an unsigned big
- integer of length LEN bytes. */
-static unsigned int
-count_bits (const unsigned char *a, size_t len)
-{
- unsigned int n = len * 8;
- int i;
-
- for (; len && !*a; len--, a++, n -=8)
- ;
- if (len)
- {
- for (i=7; i && !(*a & (1<<i)); i--)
- n--;
- }
- return n;
-}
-
-/* Note, that FPR must be at least 20 bytes. */
-static int
-store_fpr (int slot, int keynumber, u32 timestamp,
- const unsigned char *m, size_t mlen,
- const unsigned char *e, size_t elen,
- unsigned char *fpr, unsigned int card_version)
-{
- unsigned int n, nbits;
- unsigned char *buffer, *p;
- int rc;
-
- for (; mlen && !*m; mlen--, m++) /* strip leading zeroes */
- ;
- for (; elen && !*e; elen--, e++) /* strip leading zeroes */
- ;
-
- n = 6 + 2 + mlen + 2 + elen;
- p = buffer = xtrymalloc (3 + n);
- if (!buffer)
- return out_of_core ();
-
- *p++ = 0x99; /* ctb */
- *p++ = n >> 8; /* 2 byte length header */
- *p++ = n;
- *p++ = 4; /* key packet version */
- *p++ = timestamp >> 24;
- *p++ = timestamp >> 16;
- *p++ = timestamp >> 8;
- *p++ = timestamp;
- *p++ = 1; /* RSA */
- nbits = count_bits (m, mlen);
- *p++ = nbits >> 8;
- *p++ = nbits;
- memcpy (p, m, mlen); p += mlen;
- nbits = count_bits (e, elen);
- *p++ = nbits >> 8;
- *p++ = nbits;
- memcpy (p, e, elen); p += elen;
-
- log_printhex ("fprbuf:", buffer, n+3);
- gcry_md_hash_buffer (GCRY_MD_SHA1, fpr, buffer, n+3);
-
- xfree (buffer);
-
- rc = iso7816_put_data (slot, (card_version > 0x0007? 0xC7 : 0xC6)
- + keynumber, fpr, 20);
- if (rc)
- log_error ("failed to store the fingerprint: rc=%04X\n", rc);
-
- return rc;
-}
-
-
-static void
-send_fpr_if_not_null (CTRL ctrl, const char *keyword,
- int number, const unsigned char *fpr)
-{
- int i;
- char buf[41];
- char numbuf[25];
-
- for (i=0; i < 20 && !fpr[i]; i++)
- ;
- if (i==20)
- return; /* All zero. */
- for (i=0; i< 20; i++)
- sprintf (buf+2*i, "%02X", fpr[i]);
- if (number == -1)
- *numbuf = 0; /* Don't print the key number */
- else
- sprintf (numbuf, "%d", number);
- send_status_info (ctrl, keyword,
- numbuf, (size_t)strlen(numbuf),
- buf, (size_t)strlen (buf), NULL, 0);
-}
-
-static void
-send_key_data (CTRL ctrl, const char *name,
- const unsigned char *a, size_t alen)
-{
- char *p, *buf = xmalloc (alen*2+1);
-
- for (p=buf; alen; a++, alen--, p += 2)
- sprintf (p, "%02X", *a);
-
- send_status_info (ctrl, "KEY-DATA",
- name, (size_t)strlen(name),
- buf, (size_t)strlen (buf),
- NULL, 0);
- xfree (buf);
-}
-
-
-
-static int
-do_learn_status (APP app, CTRL ctrl)
-{
- void *relptr;
- unsigned char *value;
- size_t valuelen;
- int i;
-
- relptr = get_one_do (app->slot, 0x005B, &value, &valuelen);
- if (relptr)
- {
- send_status_info (ctrl, "DISP-NAME", value, valuelen, NULL, 0);
- xfree (relptr);
- }
- relptr = get_one_do (app->slot, 0x5F2D, &value, &valuelen);
- if (relptr)
- {
- send_status_info (ctrl, "DISP-LANG", value, valuelen, NULL, 0);
- xfree (relptr);
- }
- relptr = get_one_do (app->slot, 0x5F35, &value, &valuelen);
- if (relptr)
- {
- send_status_info (ctrl, "DISP-SEX", value, valuelen, NULL, 0);
- xfree (relptr);
- }
- relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen);
- if (relptr)
- {
- send_status_info (ctrl, "PUBKEY-URL", value, valuelen, NULL, 0);
- xfree (relptr);
- }
- relptr = get_one_do (app->slot, 0x005E, &value, &valuelen);
- if (relptr)
- {
- send_status_info (ctrl, "LOGIN-DATA", value, valuelen, NULL, 0);
- xfree (relptr);
- }
-
- relptr = get_one_do (app->slot, 0x00C5, &value, &valuelen);
- if (relptr && valuelen >= 60)
- {
- for (i=0; i < 3; i++)
- send_fpr_if_not_null (ctrl, "KEY-FPR", i+1, value+i*20);
- }
- xfree (relptr);
- relptr = get_one_do (app->slot, 0x00C6, &value, &valuelen);
- if (relptr && valuelen >= 60)
- {
- for (i=0; i < 3; i++)
- send_fpr_if_not_null (ctrl, "CA-FPR", i+1, value+i*20);
- }
- xfree (relptr);
- relptr = get_one_do (app->slot, 0x00C4, &value, &valuelen);
- if (relptr)
- {
- char numbuf[7*23];
-
- for (i=0,*numbuf=0; i < valuelen && i < 7; i++)
- sprintf (numbuf+strlen (numbuf), " %d", value[i]);
- send_status_info (ctrl, "CHV-STATUS", numbuf, strlen (numbuf), NULL, 0);
- xfree (relptr);
- }
-
- {
- unsigned long ul = get_sig_counter (app);
- char numbuf[23];
-
- sprintf (numbuf, "%lu", ul);
- send_status_info (ctrl, "SIG-COUNTER", numbuf, strlen (numbuf), NULL, 0);
- }
- return 0;
-}
-
-
-/* Handle the SETATTR operation. All arguments are already basically
- checked. */
-static int
-do_setattr (APP app, const char *name,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const unsigned char *value, size_t valuelen)
-{
- gpg_error_t rc;
- int idx;
- static struct {
- const char *name;
- int tag;
- } table[] = {
- { "DISP-NAME", 0x005B },
- { "LOGIN-DATA", 0x005E },
- { "DISP-LANG", 0x5F2D },
- { "DISP-SEX", 0x5F35 },
- { "PUBKEY-URL", 0x5F50 },
- { "CHV-STATUS-1", 0x00C4 },
- { "CA-FPR-1", 0x00CA },
- { "CA-FPR-2", 0x00CB },
- { "CA-FPR-3", 0x00CC },
- { NULL, 0 }
- };
-
-
- for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++)
- ;
- if (!table[idx].name)
- return gpg_error (GPG_ERR_INV_NAME);
-
- if (!app->did_chv3)
- {
- char *pinvalue;
-
- rc = pincb (pincb_arg, "Admin PIN (CHV3)",
- &pinvalue);
-/* pinvalue = xstrdup ("12345678"); */
-/* rc = 0; */
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_error ("verify CHV3 failed\n");
- rc = gpg_error (GPG_ERR_GENERAL);
- return rc;
- }
- app->did_chv3 = 1;
- }
-
- rc = iso7816_put_data (app->slot, table[idx].tag, value, valuelen);
- if (rc)
- log_error ("failed to set `%s': %s\n", table[idx].name, gpg_strerror (rc));
- /* FIXME: If this fails we should *once* try again after
- doing a verify command, so that in case of a problem with
- tracking the verify operation we have a fallback. */
-
- return rc;
-}
-
-/* Handle the PASSWD command. */
-static int
-do_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- int rc = 0;
- int chvno = atoi (chvnostr);
- char *pinvalue;
-
- if (reset_mode && chvno == 3)
- {
- rc = gpg_error (GPG_ERR_INV_ID);
- goto leave;
- }
- else if (reset_mode || chvno == 3)
- {
- rc = pincb (pincb_arg, "Admin PIN", &pinvalue);
- if (rc)
- {
- log_error ("error getting PIN: %s\n", gpg_strerror (rc));
- goto leave;
- }
- rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_error ("verify CHV3 failed: rc=%04X\n", rc);
- goto leave;
- }
- }
- else if (chvno == 1)
- {
- rc = pincb (pincb_arg, "Signature PIN", &pinvalue);
- if (rc)
- {
- log_error ("error getting PIN: %s\n", gpg_strerror (rc));
- goto leave;
- }
- rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_error ("verify CHV1 failed: rc=%04X\n", rc);
- goto leave;
- }
- }
- else if (chvno == 2)
- {
- rc = pincb (pincb_arg, "Decryption PIN", &pinvalue);
- if (rc)
- {
- log_error ("error getting PIN: %s\n", gpg_strerror (rc));
- goto leave;
- }
- rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_error ("verify CHV2 failed: rc=%04X\n", rc);
- goto leave;
- }
- }
- else
- {
- rc = gpg_error (GPG_ERR_INV_ID);
- goto leave;
- }
-
-
- rc = pincb (pincb_arg, chvno == 1? "New Signature PIN" :
- chvno == 2? "New Decryption PIN" :
- chvno == 3? "New Admin PIN" : "?", &pinvalue);
- if (rc)
- {
- log_error ("error getting new PIN: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- if (reset_mode)
- rc = iso7816_reset_retry_counter (app->slot, 0x80 + chvno,
- pinvalue, strlen (pinvalue));
- else
- rc = iso7816_change_reference_data (app->slot, 0x80 + chvno,
- NULL, 0,
- pinvalue, strlen (pinvalue));
- xfree (pinvalue);
-
-
- leave:
- return rc;
-}
-
-
-
-/* Handle the GENKEY command. */
-static int
-do_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- int rc;
- int i;
- char numbuf[30];
- unsigned char fprbuf[20];
- const unsigned char *fpr;
- const unsigned char *keydata, *m, *e;
- unsigned char *buffer;
- size_t buflen, keydatalen, n, mlen, elen;
- time_t created_at;
- int keyno = atoi (keynostr);
- int force = (flags & 1);
- time_t start_at;
-
- if (keyno < 1 || keyno > 3)
- return gpg_error (GPG_ERR_INV_ID);
- keyno--;
-
- rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
- if (rc)
- {
- log_error ("error reading application data\n");
- return gpg_error (GPG_ERR_GENERAL);
- }
- fpr = find_tlv (buffer, buflen, 0x00C5, &n, 0);
- if (!fpr || n != 60)
- {
- rc = gpg_error (GPG_ERR_GENERAL);
- log_error ("error reading fingerprint DO\n");
- goto leave;
- }
- fpr += 20*keyno;
- for (i=0; i < 20 && !fpr[i]; i++)
- ;
- if (i!=20 && !force)
- {
- rc = gpg_error (GPG_ERR_EEXIST);
- log_error ("key already exists\n");
- goto leave;
- }
- else if (i!=20)
- log_info ("existing key will be replaced\n");
- else
- log_info ("generating new key\n");
-
- {
- char *pinvalue;
- rc = pincb (pincb_arg, "Admin PIN", &pinvalue);
- if (rc)
- {
- log_error ("error getting PIN: %s\n", gpg_strerror (rc));
- return rc;
- }
- rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- }
- if (rc)
- {
- log_error ("verify CHV3 failed: rc=%04X\n", rc);
- goto leave;
- }
-
- xfree (buffer); buffer = NULL;
-#if 1
- log_info ("please wait while key is being generated ...\n");
- start_at = time (NULL);
- rc = iso7816_generate_keypair
-#else
-#warning key generation temporary replaced by reading an existing key.
- rc = iso7816_read_public_key
-#endif
- (app->slot,
- keyno == 0? "\xB6" :
- keyno == 1? "\xB8" : "\xA4",
- 2,
- &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, 0);
- 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, 0);
- 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, 0);
- 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 = 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->slot, keyno, (u32)created_at,
- m, mlen, e, elen, fprbuf, app->card_version);
- if (rc)
- goto leave;
- send_fpr_if_not_null (ctrl, "KEY-FPR", -1, fprbuf);
-
-
- leave:
- xfree (buffer);
- return rc;
-}
-
-
-static unsigned long
-get_sig_counter (APP app)
-{
- void *relptr;
- unsigned char *value;
- size_t valuelen;
- unsigned long ul;
-
- relptr = get_one_do (app->slot, 0x0093, &value, &valuelen);
- if (!relptr)
- return 0;
- if (valuelen == 3 )
- ul = (value[0] << 16) | (value[1] << 8) | value[2];
- else
- {
- log_error ("invalid structure of OpenPGP card (DO 0x93)\n");
- ul = 0;
- }
- xfree (relptr);
- return ul;
-}
-
-static int
-compare_fingerprint (APP app, int keyno, unsigned char *sha1fpr)
-{
- const unsigned char *fpr;
- unsigned char *buffer;
- size_t buflen, n;
- int rc, i;
-
- assert (keyno >= 1 && keyno <= 3);
-
- rc = iso7816_get_data (app->slot, 0x006E, &buffer, &buflen);
- if (rc)
- {
- log_error ("error reading application data\n");
- return gpg_error (GPG_ERR_GENERAL);
- }
- fpr = find_tlv (buffer, buflen, 0x00C5, &n, 0);
- if (!fpr || n != 60)
- {
- xfree (buffer);
- log_error ("error reading fingerprint DO\n");
- return gpg_error (GPG_ERR_GENERAL);
- }
- fpr += (keyno-1)*20;
- for (i=0; i < 20; i++)
- if (sha1fpr[i] != fpr[i])
- {
- xfree (buffer);
- return gpg_error (GPG_ERR_WRONG_SECKEY);
- }
- xfree (buffer);
- return 0;
-}
-
-
-
-/* Compute a digital signature on INDATA which is expected to be the
- raw message digest. For this application the KEYIDSTR consists of
- the serialnumber and the fingerprint delimited by a slash.
-
- Note that this fucntion may return the error code
- GPG_ERR_WRONG_CARD to indicate that the card currently present does
- not match the one required for the requested action (e.g. the
- serial number does not match). */
-static int
-do_sign (APP app, const char *keyidstr, int hashalgo,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- static unsigned char sha1_prefix[15] = /* Object ID is 1.3.14.3.2.26 */
- { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
- 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
- static unsigned char rmd160_prefix[15] = /* Object ID is 1.3.36.3.2.1 */
- { 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x24, 0x03,
- 0x02, 0x01, 0x05, 0x00, 0x04, 0x14 };
- int rc;
- unsigned char data[35];
- unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */
- const char *s;
- int n;
- const char *fpr = NULL;
- unsigned long sigcount;
-
- if (!keyidstr || !*keyidstr)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (indatalen != 20)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- /* Check whether an OpenPGP card of any version has been requested. */
- if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
-
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, gpg
- will detect a bogus signature anyway due to the
- verify-after-signing feature. */
- if (fpr)
- {
- for (s=fpr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 40)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* okay */
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=fpr, n=0; n < 20; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
- rc = compare_fingerprint (app, 1, tmp_sn);
- if (rc)
- return rc;
- }
-
- if (hashalgo == GCRY_MD_SHA1)
- memcpy (data, sha1_prefix, 15);
- else if (hashalgo == GCRY_MD_RMD160)
- memcpy (data, rmd160_prefix, 15);
- else
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
- memcpy (data+15, indata, indatalen);
-
- sigcount = get_sig_counter (app);
- log_info ("signatures created so far: %lu\n", sigcount);
-
- /* FIXME: Check whether we are really required to enter the PIN for
- each signature. There is a DO for this. */
- if (!app->did_chv1 || 1)
- {
- char *pinvalue;
-
- {
- char *prompt;
- if (asprintf (&prompt, "Signature PIN [sigs done: %lu]", sigcount) < 0)
- return gpg_error_from_errno (errno);
- rc = pincb (pincb_arg, prompt, &pinvalue);
- free (prompt);
- }
-/* pinvalue = xstrdup ("123456"); */
-/* rc = 0; */
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_error ("verify CHV1 failed\n");
- rc = gpg_error (GPG_ERR_GENERAL);
- return rc;
- }
- app->did_chv1 = 1;
- }
-
- rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
- return rc;
-}
-
-/* Compute a digital signature using the INTERNAL AUTHENTICATE command
- on INDATA which is expected to be the raw message digest. For this
- application the KEYIDSTR consists of the serialnumber and the
- fingerprint delimited by a slash.
-
- Note that this fucntion may return the error code
- GPG_ERR_WRONG_CARD to indicate that the card currently present does
- not match the one required for the requested action (e.g. the
- serial number does not match). */
-static int
-do_auth (APP app, const char *keyidstr,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- int rc;
- unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */
- const char *s;
- int n;
- const char *fpr = NULL;
-
- if (!keyidstr || !*keyidstr)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (indatalen > 50) /* For a 1024 bit key. */
- return gpg_error (GPG_ERR_INV_VALUE);
-
- /* Check whether an OpenPGP card of any version has been requested. */
- if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
-
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, gpg
- will detect a bogus signature anyway due to the
- verify-after-signing feature. */
- if (fpr)
- {
- for (s=fpr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 40)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* okay */
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=fpr, n=0; n < 20; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
- rc = compare_fingerprint (app, 3, tmp_sn);
- if (rc)
- return rc;
- }
-
- if (!app->did_chv2)
- {
- char *pinvalue;
-
- rc = pincb (pincb_arg, "Authentication/Decryption PIN", &pinvalue);
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_error ("verify CHV2 failed\n");
- rc = gpg_error (GPG_ERR_GENERAL);
- return rc;
- }
- app->did_chv2 = 1;
- }
-
- rc = iso7816_internal_authenticate (app->slot, indata, indatalen,
- outdata, outdatalen);
- return rc;
-}
-
-
-static int
-do_decipher (APP app, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- int rc;
- unsigned char tmp_sn[20]; /* actually 16 but we use it also for the fpr. */
- const char *s;
- int n;
- const char *fpr = NULL;
-
- if (!keyidstr || !*keyidstr || !indatalen)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- /* Check whether an OpenPGP card of any version has been requested. */
- if (strlen (keyidstr) < 32 || strncmp (keyidstr, "D27600012401", 12))
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 32)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* no fingerprint given: we allow this for now. */
- else if (*s == '/')
- fpr = s + 1;
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=keyidstr, n=0; n < 16; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
-
- if (app->serialnolen != 16)
- return gpg_error (GPG_ERR_INV_CARD);
- if (memcmp (app->serialno, tmp_sn, 16))
- return gpg_error (GPG_ERR_WRONG_CARD);
-
- /* If a fingerprint has been specified check it against the one on
- the card. This is allows for a meaningful error message in case
- the key on the card has been replaced but the shadow information
- known to gpg was not updated. If there is no fingerprint, the
- decryption will won't produce the right plaintext anyway. */
- if (fpr)
- {
- for (s=fpr, n=0; hexdigitp (s); s++, n++)
- ;
- if (n != 40)
- return gpg_error (GPG_ERR_INV_ID);
- else if (!*s)
- ; /* okay */
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- for (s=fpr, n=0; n < 20; s += 2, n++)
- tmp_sn[n] = xtoi_2 (s);
- rc = compare_fingerprint (app, 2, tmp_sn);
- if (rc)
- return rc;
- }
-
- if (!app->did_chv2)
- {
- char *pinvalue;
-
- rc = pincb (pincb_arg, "Decryption PIN", &pinvalue);
-/* pinvalue = xstrdup ("123456"); */
-/* rc = 0; */
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_error ("verify CHV2 failed\n");
- rc = gpg_error (GPG_ERR_GENERAL);
- return rc;
- }
- app->did_chv2 = 1;
- }
-
- rc = iso7816_decipher (app->slot, indata, indatalen, outdata, outdatalen);
- return rc;
-}
-
-
-
-
-/* Select the OpenPGP application on the card in SLOT. This function
- must be used before any other OpenPGP application functions. */
-int
-app_select_openpgp (APP app, unsigned char **sn, size_t *snlen)
-{
- static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
- int slot = app->slot;
- int rc;
- unsigned char *buffer;
- size_t buflen;
-
- rc = iso7816_select_application (slot, aid, sizeof aid);
- if (!rc)
- {
- /* fixme: get the full AID and check that the version is okay
- with us. */
- rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen);
- if (rc)
- goto leave;
- if (opt.verbose)
- {
- log_info ("got AID: ");
- log_printhex ("", buffer, buflen);
- }
-
- if (sn)
- {
- *sn = buffer;
- *snlen = buflen;
- app->card_version = buffer[6] << 8;
- app->card_version |= buffer[7];
- }
- else
- xfree (buffer);
-
- if (opt.verbose > 1)
- dump_all_do (slot);
-
- app->fnc.learn_status = do_learn_status;
- app->fnc.setattr = do_setattr;
- 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;
- }
-
-leave:
- return rc;
-}
-
-
-
-/* This function is a hack to retrieve essential information about the
- card to be displayed by simple tools. It mostly resembles what the
- LEARN command returns. All parameters return allocated strings or
- buffers or NULL if the data object is not available. All returned
- values are sanitized. */
-int
-app_openpgp_cardinfo (APP app,
- char **serialno,
- char **disp_name,
- char **pubkey_url,
- unsigned char **fpr1,
- unsigned char **fpr2,
- unsigned char **fpr3)
-{
- int rc;
- void *relptr;
- unsigned char *value;
- size_t valuelen;
-
- if (serialno)
- {
- time_t dummy;
-
- *serialno = NULL;
- rc = app_get_serial_and_stamp (app, serialno, &dummy);
- if (rc)
- {
- log_error ("error getting serial number: %s\n", gpg_strerror (rc));
- return rc;
- }
- }
-
- if (disp_name)
- {
- *disp_name = NULL;
- relptr = get_one_do (app->slot, 0x005B, &value, &valuelen);
- if (relptr)
- {
- *disp_name = make_printable_string (value, valuelen, 0);
- xfree (relptr);
- }
- }
-
- if (pubkey_url)
- {
- *pubkey_url = NULL;
- relptr = get_one_do (app->slot, 0x5F50, &value, &valuelen);
- if (relptr)
- {
- *pubkey_url = make_printable_string (value, valuelen, 0);
- xfree (relptr);
- }
- }
-
- if (fpr1)
- *fpr1 = NULL;
- if (fpr2)
- *fpr2 = NULL;
- if (fpr3)
- *fpr3 = NULL;
- relptr = get_one_do (app->slot, 0x00C5, &value, &valuelen);
- if (relptr && valuelen >= 60)
- {
- if (fpr1)
- {
- *fpr1 = xmalloc (20);
- memcpy (*fpr1, value + 0, 20);
- }
- if (fpr2)
- {
- *fpr2 = xmalloc (20);
- memcpy (*fpr2, value + 20, 20);
- }
- if (fpr3)
- {
- *fpr3 = xmalloc (20);
- memcpy (*fpr3, value + 40, 20);
- }
- }
- xfree (relptr);
-
- return 0;
-}
-
-
-
-/* This function is currently only used by the sc-copykeys program to
- store a key on the smartcard. APP ist the application handle,
- KEYNO is the number of the key and PINCB, PINCB_ARG are used to ask
- for the SO PIN. TEMPLATE and TEMPLATE_LEN describe a buffer with
- the key template to store. CREATED_AT is the timestamp used to
- create the fingerprint. M, MLEN is the RSA modulus and E, ELEN the
- RSA public exponent. This function silently overwrites an existing
- key.*/
-int
-app_openpgp_storekey (APP app, int keyno,
- unsigned char *template, size_t template_len,
- time_t created_at,
- const unsigned char *m, size_t mlen,
- const unsigned char *e, size_t elen,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- int rc;
- unsigned char fprbuf[20];
-
- if (keyno < 1 || keyno > 3)
- return gpg_error (GPG_ERR_INV_ID);
- keyno--;
-
- {
- char *pinvalue;
- rc = pincb (pincb_arg, "Admin PIN", &pinvalue);
- if (rc)
- {
- log_error ("error getting PIN: %s\n", gpg_strerror (rc));
- return rc;
- }
- rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- }
- if (rc)
- {
- log_error ("verify CHV3 failed: rc=%04X\n", rc);
- goto leave;
- }
-
- rc = iso7816_put_data (app->slot,
- (app->card_version > 0x0007? 0xE0 : 0xE9) + keyno,
- template, template_len);
- if (rc)
- {
- log_error ("failed to store the key: rc=%04X\n", rc);
- rc = gpg_error (GPG_ERR_CARD);
- goto leave;
- }
-
-/* log_printhex ("RSA n:", m, mlen); */
-/* log_printhex ("RSA e:", e, elen); */
-
- rc = store_fpr (app->slot, keyno, (u32)created_at,
- m, mlen, e, elen, fprbuf, app->card_version);
-
- leave:
- return rc;
-}
-
-
-/* Utility function for external tools: Read the public RSA key at
- KEYNO and return modulus and exponent in (M,MLEN) and (E,ELEN). */
-int
-app_openpgp_readkey (APP app, int keyno, unsigned char **m, size_t *mlen,
- unsigned char **e, size_t *elen)
-{
- int rc;
- const unsigned char *keydata, *a;
- unsigned char *buffer;
- size_t buflen, keydatalen, alen;
-
- *m = NULL;
- *e = NULL;
-
- if (keyno < 1 || keyno > 3)
- return gpg_error (GPG_ERR_INV_ID);
- keyno--;
-
- rc = iso7816_read_public_key(app->slot,
- keyno == 0? "\xB6" :
- keyno == 1? "\xB8" : "\xA4",
- 2,
- &buffer, &buflen);
- if (rc)
- {
- rc = gpg_error (GPG_ERR_CARD);
- log_error ("reading key failed\n");
- goto leave;
- }
-
- keydata = find_tlv (buffer, buflen, 0x7F49, &keydatalen, 0);
- if (!keydata)
- {
- log_error ("response does not contain the public key data\n");
- rc = gpg_error (GPG_ERR_CARD);
- goto leave;
- }
-
- a = find_tlv (keydata, keydatalen, 0x0081, &alen, 0);
- if (!a)
- {
- log_error ("response does not contain the RSA modulus\n");
- rc = gpg_error (GPG_ERR_CARD);
- goto leave;
- }
- *mlen = alen;
- *m = xmalloc (alen);
- memcpy (*m, a, alen);
-
- a = find_tlv (keydata, keydatalen, 0x0082, &alen, 0);
- if (!e)
- {
- log_error ("response does not contain the RSA public exponent\n");
- rc = gpg_error (GPG_ERR_CARD);
- goto leave;
- }
- *elen = alen;
- *e = xmalloc (alen);
- memcpy (*e, a, alen);
-
- leave:
- xfree (buffer);
- if (rc)
- {
- xfree (*m); *m = NULL;
- xfree (*e); *e = NULL;
- }
- return rc;
-}
diff --git a/scd/app.c b/scd/app.c
deleted file mode 100644
index 7a85df336..000000000
--- a/scd/app.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/* app.c - Application selection.
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dlfcn.h>
-
-#include "scdaemon.h"
-#include "app-common.h"
-#include "apdu.h"
-#include "iso7816.h"
-
-/* The select the best fitting application and return a context.
- Returns NULL if no application was found or no card is present. */
-APP
-select_application (void)
-{
- int reader_port = 32768; /* First USB reader. */
- int slot;
- int rc;
- APP app;
-
- slot = apdu_open_reader (reader_port);
- if (slot == -1)
- {
- log_error ("card reader not available\n");
- return NULL;
- }
-
- app = xtrycalloc (1, sizeof *app);
- if (!app)
- {
- rc = out_of_core ();
- log_info ("error allocating context: %s\n", gpg_strerror (rc));
- /*apdu_close_reader (slot);*/
- return NULL;
- }
-
- app->slot = slot;
- rc = app_select_openpgp (app, &app->serialno, &app->serialnolen);
- if (rc)
- {
-/* apdu_close_reader (slot); */
- log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
- xfree (app);
- return NULL;
- }
-
- app->initialized = 1;
- return app;
-}
-
-
-
-/* Retrieve the serial number and the time of the last update of the
- card. The serial number is returned as a malloced string (hex
- encoded) in SERIAL and the time of update is returned in STAMP. If
- no update time is available the returned value is 0. Caller must
- free SERIAL unless the function returns an error. */
-int
-app_get_serial_and_stamp (APP app, char **serial, time_t *stamp)
-{
- unsigned char *buf, *p;
- int i;
-
- if (!app || !serial || !stamp)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- *serial = NULL;
- *stamp = 0; /* not available */
-
- buf = xtrymalloc (app->serialnolen * 2 + 1);
- if (!buf)
- return gpg_error_from_errno (errno);
- for (p=buf, i=0; i < app->serialnolen; p +=2, i++)
- sprintf (p, "%02X", app->serialno[i]);
- *p = 0;
- *serial = buf;
- return 0;
-}
-
-
-/* Write out the application specifig status lines for the LEARN
- command. */
-int
-app_write_learn_status (APP app, CTRL ctrl)
-{
- if (!app)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.learn_status)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- return app->fnc.learn_status (app, ctrl);
-}
-
-
-/* Perform a SETATTR operation. */
-int
-app_setattr (APP app, const char *name,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const unsigned char *value, size_t valuelen)
-{
- if (!app || !name || !*name || !value)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.setattr)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- return app->fnc.setattr (app, name, pincb, pincb_arg, value, valuelen);
-}
-
-/* Create the signature and return the allocated result in OUTDATA.
- If a PIN is required the PINCB will be used to ask for the PIN; it
- should return the PIN in an allocated buffer and put it into PIN. */
-int
-app_sign (APP app, const char *keyidstr, int hashalgo,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- int rc;
-
- if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.sign)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = app->fnc.sign (app, keyidstr, hashalgo,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- if (opt.verbose)
- log_info ("operation sign result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-/* Create the signature using the INTERNAL AUTHENTICATE command and
- return the allocated result in OUTDATA. If a PIN is required the
- PINCB will be used to ask for the PIN; it should return the PIN in
- an allocated buffer and put it into PIN. */
-int
-app_auth (APP app, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- int rc;
-
- if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.auth)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = app->fnc.auth (app, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- if (opt.verbose)
- log_info ("operation auth result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-
-/* Decrypt the data in INDATA and return the allocated result in OUTDATA.
- If a PIN is required the PINCB will be used to ask for the PIN; it
- should return the PIN in an allocated buffer and put it into PIN. */
-int
-app_decipher (APP app, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- int rc;
-
- if (!app || !indata || !indatalen || !outdata || !outdatalen || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.decipher)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = app->fnc.decipher (app, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- if (opt.verbose)
- log_info ("operation decipher result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-
-/* Perform a SETATTR operation. */
-int
-app_genkey (APP app, CTRL ctrl, const char *keynostr, unsigned int flags,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- int rc;
-
- if (!app || !keynostr || !*keynostr || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.genkey)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = app->fnc.genkey (app, ctrl, keynostr, flags, pincb, pincb_arg);
- if (opt.verbose)
- log_info ("operation genkey result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-
-/* Perform a GET CHALLENGE operation. This fucntion is special as it
- directly accesses the card without any application specific
- wrapper. */
-int
-app_get_challenge (APP app, size_t nbytes, unsigned char *buffer)
-{
- if (!app || !nbytes || !buffer)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- return iso7816_get_challenge (app->slot, nbytes, buffer);
-}
-
-
-
-/* Perform a CHANGE REFERENCE DATA or RESET RETRY COUNTER operation. */
-int
-app_change_pin (APP app, CTRL ctrl, const char *chvnostr, int reset_mode,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- int rc;
-
- if (!app || !chvnostr || !*chvnostr || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.change_pin)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = app->fnc.change_pin (app, ctrl, chvnostr, reset_mode, pincb, pincb_arg);
- if (opt.verbose)
- log_info ("operation change_pin result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-
-
-
-
-
diff --git a/scd/atr.c b/scd/atr.c
deleted file mode 100644
index 4e15aad50..000000000
--- a/scd/atr.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/* atr.c - ISO 7816 ATR fucntions
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dlfcn.h>
-#include <assert.h>
-
-#include "scdaemon.h"
-#include "apdu.h"
-#include "atr.h"
-
-static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
- -1, 512, 768, 1024, 1536, 2048, -1, -1 };
-static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
- 0, -1, -2, -4, -8, -16, -32, -64};
-
-
-/* Dump the ATR of the card at SLOT in a human readable format to
- stream FP. */
-int
-atr_dump (int slot, FILE *fp)
-{
- unsigned char *atrbuffer, *atr;
- size_t atrlen;
- int have_ta, have_tb, have_tc, have_td;
- int n_historical;
- int idx, val;
- unsigned char chksum;
-
- atr = atrbuffer = apdu_get_atr (slot, &atrlen);
- if (!atr)
- return gpg_error (GPG_ERR_GENERAL);
-
- fprintf (fp, "Info on ATR of length %u at slot %d\n",
- (unsigned int)atrlen, slot);
- if (!atrlen)
- {
- fprintf (fp, "error: empty ATR\n");
- goto bailout;
- }
-
-
- if (*atr == 0x3b)
- fputs ("direct convention\n", fp);
- else if (*atr == 0x3f)
- fputs ("inverse convention\n", fp);
- else
- fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
- if (!--atrlen)
- goto bailout;
- atr++;
-
- chksum = *atr;
- for (idx=1; idx < atrlen-1; idx++)
- chksum ^= atr[idx];
-
- have_ta = !!(*atr & 0x10);
- have_tb = !!(*atr & 0x20);
- have_tc = !!(*atr & 0x40);
- have_td = !!(*atr & 0x80);
- n_historical = (*atr & 0x0f);
- fprintf (fp, "%d historical characters indicated\n", n_historical);
-
- if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
- fputs ("error: ATR shorter than indicated by format character\n", fp);
- if (!--atrlen)
- goto bailout;
- atr++;
-
- if (have_ta)
- {
- fputs ("TA1: F=", fp);
- val = fi_table[(*atr >> 4) & 0x0f];
- if (!val)
- fputs ("internal clock", fp);
- else if (val == -1)
- fputs ("RFU", fp);
- else
- fprintf (fp, "%d", val);
- fputs (" D=", fp);
- val = di_table[*atr & 0x0f];
- if (!val)
- fputs ("[impossible value]\n", fp);
- else if (val == -1)
- fputs ("RFU\n", fp);
- else if (val < 0 )
- fprintf (fp, "1/%d\n", val);
- else
- fprintf (fp, "%d\n", val);
-
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_tb)
- {
- fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
- (*atr & 0x80)? " [high bit not cleared]":"");
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_tc)
- {
- if (*atr == 255)
- fputs ("TC1: guard time shortened to 1 etu\n", fp);
- else
- fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
-
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_td)
- {
- have_ta = !!(*atr & 0x10);
- have_tb = !!(*atr & 0x20);
- have_tc = !!(*atr & 0x40);
- have_td = !!(*atr & 0x80);
- fprintf (fp, "TD1: protocol T%d supported\n", *atr & 0x0f);
-
- if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
- fputs ("error: ATR shorter than indicated by format character\n", fp);
-
- if (!--atrlen)
- goto bailout;
- atr++;
- }
- else
- have_ta = have_tb = have_tc = have_td = 0;
-
- if (have_ta)
- {
- fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
- (*atr & 0x80)? "no-":"",
- (*atr & 0x10)? "im": "ex",
- (*atr & 0x0f));
- if ((*atr & 0x60))
- fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_tb)
- {
- fprintf (fp, "TB2: PI2=%d\n", *atr);
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_tc)
- {
- fprintf (fp, "TC2: PWI=%d\n", *atr);
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_td)
- {
- have_ta = !!(*atr & 0x10);
- have_tb = !!(*atr & 0x20);
- have_tc = !!(*atr & 0x40);
- have_td = !!(*atr & 0x80);
- fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
-
- if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
- fputs ("error: ATR shorter than indicated by format character\n", fp);
-
- if (!--atrlen)
- goto bailout;
- atr++;
- }
- else
- have_ta = have_tb = have_tc = have_td = 0;
-
- for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
- {
- if (have_ta)
- {
- fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_tb)
- {
- fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
- idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_tc)
- {
- fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
- if (!--atrlen)
- goto bailout;
- atr++;
- }
-
- if (have_td)
- {
- have_ta = !!(*atr & 0x10);
- have_tb = !!(*atr & 0x20);
- have_tc = !!(*atr & 0x40);
- have_td = !!(*atr & 0x80);
- fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
-
- if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
- fputs ("error: ATR shorter than indicated by format character\n",
- fp);
-
- if (!--atrlen)
- goto bailout;
- atr++;
- }
- else
- have_ta = have_tb = have_tc = have_td = 0;
- }
-
- if (n_historical + 1 > atrlen)
- fputs ("error: ATR shorter than required for historical bytes "
- "and checksum\n", fp);
-
- if (n_historical)
- {
- fputs ("Historical:", fp);
- for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
- fprintf (fp, " %02X", *atr);
- putchar ('\n');
- }
-
- if (!atrlen)
- fputs ("error: checksum missing\n", fp);
- else if (*atr == chksum)
- fprintf (fp, "TCK: %02X (good)\n", *atr);
- else
- fprintf (fp, "TCK: %02X (bad; calculated %02X)\n", *atr, chksum);
-
- atrlen--;
- if (atrlen)
- fprintf (fp, "error: %u bytes garbage at end of ATR\n",
- (unsigned int)atrlen );
-
- bailout:
- xfree (atrbuffer);
-
- return 0;
-}
-
-
-
-
-
-
-
-
-
diff --git a/scd/atr.h b/scd/atr.h
deleted file mode 100644
index 5fdd57457..000000000
--- a/scd/atr.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* atr.h - ISO 7816 ATR functions
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef ATR_H
-#define ATR_H
-
-int atr_dump (int slot, FILE *fp);
-
-
-
-#endif /*ATR_H*/
diff --git a/scd/card-common.h b/scd/card-common.h
deleted file mode 100644
index 31f0dfe8f..000000000
--- a/scd/card-common.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* card-common.h - Common declarations for all card types
- * Copyright (C) 2001, 2002 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef CARD_COMMON_H
-#define CARD_COMMON_H
-
-/* Declaration of private data structure used by card-p15.c */
-struct p15private_s;
-
-
-struct card_ctx_s {
- int reader; /* used reader */
- struct sc_context *ctx;
- struct sc_card *scard;
- struct sc_pkcs15_card *p15card; /* only if there is a pkcs15 application */
- struct p15private_s *p15priv; /* private data used by card-p15.c */
-
- struct {
- int initialized; /* the card has been initialied and the function
- pointers may be used. However for
- unsupported operations the particular
- function pointer is set to NULL */
-
- int (*enum_keypairs) (CARD card, int idx,
- unsigned char *keygrip, char **keyid);
- int (*enum_certs) (CARD card, int idx, char **certid, int *certtype);
- int (*read_cert) (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert);
- int (*sign) (CARD card,
- const char *keyidstr, int hashalgo,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen );
- int (*decipher) (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen);
- } fnc;
-
-};
-
-/*-- card.c --*/
-gpg_error_t map_sc_err (int rc);
-int card_help_get_keygrip (KsbaCert cert, unsigned char *array);
-
-/*-- card-15.c --*/
-void p15_release_private_data (CARD card);
-
-/* constructors */
-void card_p15_bind (CARD card);
-void card_dinsig_bind (CARD card);
-
-
-#endif /*CARD_COMMON_H*/
diff --git a/scd/card-dinsig.c b/scd/card-dinsig.c
deleted file mode 100644
index 391a51da8..000000000
--- a/scd/card-dinsig.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/* card-dinsig.c - German signature law (DINSIG) functions
- * Copyright (C) 2002 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-/* The German signature law and its bylaw (SigG and SigV) is currently
- used with an interface specification described in DIN V 66291-1.
- The AID to be used is: 'D27600006601'.
-
- The file IDs for certificates utilize the generic format:
- Cxyz
- C being the hex digit 'C' (12).
- x being the service indicator:
- '0' := SigG conform digital signature.
- '1' := entity authentication.
- '2' := key encipherment.
- '3' := data encipherment.
- '4' := key agreement.
- other values are reserved for future use.
- y being the security environment number using '0' for cards
- not supporting a SE number.
- z being the certificate type:
- '0' := C.CH (base certificate of ard holder) or C.ICC.
- '1' .. '7' := C.CH (business or professional certificate
- of card holder.
- '8' .. 'D' := C.CA (certificate of a CA issue by the Root-CA).
- 'E' := C.RCA (self certified certificate of the Root-CA).
- 'F' := reserved.
-
- The file IDs used by default are:
- '1F00' EF.SSD (security service descriptor). [o,o]
- '2F02' EF.GDO (global data objects) [m,m]
- 'A000' EF.PROT (signature log). Cyclic file with 20 records of 53 byte.
- Read and update after user authentication. [o,o]
- 'B000' EF.PK.RCA.DS (public keys of Root-CA). Size is 512b or size
- of keys. [m (unless a 'C00E' is present),m]
- 'B001' EF.PK.CA.DS (public keys of CAs). Size is 512b or size
- of keys. [o,o]
- 'C00n' EF.C.CH.DS (digital signature certificate of card holder)
- with n := 0 .. 7. Size is 2k or size of cert. Read and
- update allowed after user authentication. [m,m]
- 'C00m' EF.C.CA.DS (digital signature certificate of CA)
- with m := 8 .. E. Size is 1k or size of cert. Read always
- allowed, update after uder authentication. [o,o]
- 'C100' EF.C.ICC.AUT (AUT certificate of ICC) [o,m]
- 'C108' EF.C.CA.AUT (AUT certificate of CA) [o,m]
- 'D000' EF.DM (display message) [-,m]
-
- The letters in brackets indicate optional or mandatory files: The
- first for card terminals under full control and the second for
- "business" card terminals.
-
- FIXME: Needs a lot more explanation.
-
-*/
-
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifdef HAVE_OPENSC
-#include <opensc/pkcs15.h>
-#include <ksba.h>
-
-#include "scdaemon.h"
-#include "card-common.h"
-
-static int dinsig_read_cert (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert);
-
-
-
-/* See card.c for interface description. Frankly we don't do any real
- enumeration but just check whether the well know files are
- available. */
-static int
-dinsig_enum_keypairs (CARD card, int idx,
- unsigned char *keygrip, char **keyid)
-{
- int rc;
- unsigned char *buf;
- size_t buflen;
- KsbaError krc;
- KsbaCert cert;
-
- /* fixme: We should locate the application via the EF(DIR) and not
- assume a Netkey card */
- if (!idx)
- rc = dinsig_read_cert (card, "DINSIG-DF01.C000", &buf, &buflen);
- else if (idx == 1)
- rc = dinsig_read_cert (card, "DINSIG-DF01.C200", &buf, &buflen);
- else
- rc = -1;
- if (rc)
- return rc;
-
- cert = ksba_cert_new ();
- if (!cert)
- {
- gpg_error_t tmperr = out_of_core ();
- xfree (buf);
- return tmperr;
- }
-
- krc = ksba_cert_init_from_mem (cert, buf, buflen);
- xfree (buf);
- if (krc)
- {
- log_error ("failed to parse the certificate at idx %d: %s\n",
- idx, ksba_strerror (krc));
- ksba_cert_release (cert);
- return gpg_error (GPG_ERR_CARD);
- }
- if (card_help_get_keygrip (cert, keygrip))
- {
- log_error ("failed to calculate the keygrip at index %d\n", idx);
- ksba_cert_release (cert);
- return gpg_error (GPG_ERR_CARD);
- }
- ksba_cert_release (cert);
-
- /* return the iD */
- if (keyid)
- {
- *keyid = xtrymalloc (17);
- if (!*keyid)
- return out_of_core ();
- if (!idx)
- strcpy (*keyid, "DINSIG-DF01.C000");
- else
- strcpy (*keyid, "DINSIG-DF01.C200");
- }
-
- return 0;
-}
-
-
-
-/* See card.c for interface description */
-static int
-dinsig_read_cert (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert)
-{
- int rc;
- struct sc_path path;
- struct sc_file *file;
- unsigned char *buf;
- int buflen;
-
- if (!strcmp (certidstr, "DINSIG-DF01.C000"))
- sc_format_path ("3F00DF01C000", &path);
- else if (!strcmp (certidstr, "DINSIG-DF01.C200"))
- sc_format_path ("3F00DF01C200", &path);
- else
- return gpg_error (GPG_ERR_INV_ID);
-
- rc = sc_select_file (card->scard, &path, &file);
- if (rc)
- {
- log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
- return map_sc_err (rc);
- }
- if (file->type != SC_FILE_TYPE_WORKING_EF
- || file->ef_structure != SC_FILE_EF_TRANSPARENT)
- {
- log_error ("wrong type or structure of certificate EF\n");
- sc_file_free (file);
- return gpg_error (GPG_ERR_CARD);
- }
- if (file->size < 20) /* check against a somewhat arbitrary length */
- {
- log_error ("certificate EF too short\n");
- sc_file_free (file);
- return gpg_error (GPG_ERR_CARD);
- }
- buf = xtrymalloc (file->size);
- if (!buf)
- {
- gpg_error_t tmperr = out_of_core ();
- sc_file_free (file);
- return tmperr;
- }
-
- rc = sc_read_binary (card->scard, 0, buf, file->size, 0);
- if (rc >= 0 && rc != file->size)
- {
- log_error ("short read on certificate EF\n");
- sc_file_free (file);
- xfree (buf);
- return gpg_error (GPG_ERR_CARD);
- }
- sc_file_free (file);
- if (rc < 0)
- {
- log_error ("error reading certificate EF: %s\n", sc_strerror (rc));
- xfree (buf);
- return map_sc_err (rc);
- }
- buflen = rc;
-
- /* The object is not a plain certificate but wrapped into id-at
- userCertificate - fixme: we should check the specs and decided
- whether libksba should support it */
- if (buflen > 9 && buf[0] == 0x30 && buf[4] == 6 && buf[5] == 3
- && buf[6] == 0x55 && buf[7] == 4 && buf[8] == 0x24)
- {
- /* We have to strip the padding. Although this is a good idea
- anyway, we have to do it due to a KSBA problem; KSBA does not
- work correct when the buffer is larger than the ASN.1
- structure and the certificates here are padded with FF. So
- as a workaround we look at the outer structure to get the
- size of the entire thing and adjust the buflen. We can only
- do this when there is a 2 byte length field */
- size_t seqlen;
- if (buf[1] == 0x82)
- {
- seqlen = ((buf[2] << 8) | buf[3]) + 4;
- if (seqlen < buflen)
- buflen = seqlen;
- }
- memmove (buf, buf+9, buflen-9);
- buflen -= 9;
- }
-
- *cert = buf;
- *ncert = buflen;
- return 0;
-}
-
-
-
-
-/* Bind our operations to the card */
-void
-card_dinsig_bind (CARD card)
-{
- card->fnc.enum_keypairs = dinsig_enum_keypairs;
- card->fnc.read_cert = dinsig_read_cert;
-
-}
-#endif /*HAVE_OPENSC*/
diff --git a/scd/card-p15.c b/scd/card-p15.c
deleted file mode 100644
index 3cf4ba519..000000000
--- a/scd/card-p15.c
+++ /dev/null
@@ -1,502 +0,0 @@
-/* card-p15.c - PKCS-15 based card access
- * Copyright (C) 2002 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifdef HAVE_OPENSC
-#include <opensc/pkcs15.h>
-#include <ksba.h>
-
-#include "scdaemon.h"
-#include "card-common.h"
-
-
-struct p15private_s {
- int n_prkey_rsa_objs;
- struct sc_pkcs15_object *prkey_rsa_objs[32];
- int n_cert_objs;
- struct sc_pkcs15_object *cert_objs[32];
-};
-
-
-/* Allocate private data. */
-static int
-init_private_data (CARD card)
-{
- struct p15private_s *priv;
- int rc;
-
- if (card->p15priv)
- return 0; /* already done. */
-
- priv = xtrycalloc (1, sizeof *priv);
- if (!priv)
- return out_of_core ();
-
- /* 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
- which eventually leads to the fact that every call to this
- fucntion returns one more macthing object. The old code in
- p15_enum_keypairs assume that it would alwyas return the same
- numer of objects and used this to figure out what the last object
- enumerated is. We now do an enum_objects just once and keep it
- in the private data. */
- rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_PRKEY_RSA,
- priv->prkey_rsa_objs,
- DIM (priv->prkey_rsa_objs));
- if (rc < 0)
- {
- log_error ("private keys enumeration failed: %s\n", sc_strerror (rc));
- xfree (priv);
- return gpg_error (GPG_ERR_CARD);
- }
- priv->n_prkey_rsa_objs = rc;
-
- /* Read all certificate objects. */
- rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_CERT_X509,
- priv->cert_objs,
- DIM (priv->cert_objs));
- if (rc < 0)
- {
- log_error ("private keys enumeration failed: %s\n", sc_strerror (rc));
- xfree (priv);
- return gpg_error (GPG_ERR_CARD);
- }
- priv->n_cert_objs = rc;
-
- card->p15priv = priv;
- return 0;
-}
-
-
-/* Release private data used in this module. */
-void
-p15_release_private_data (CARD card)
-{
- if (!card->p15priv)
- return;
- xfree (card->p15priv);
- card->p15priv = NULL;
-}
-
-
-
-/* See card.c for interface description */
-static int
-p15_enum_keypairs (CARD card, int idx,
- unsigned char *keygrip, char **keyid)
-{
- int rc;
- KsbaError krc;
- struct p15private_s *priv;
- struct sc_pkcs15_object *tmpobj;
- int nobjs;
- struct sc_pkcs15_prkey_info *pinfo;
- struct sc_pkcs15_cert_info *certinfo;
- struct sc_pkcs15_cert *certder;
- KsbaCert cert;
-
- rc = init_private_data (card);
- if (rc)
- return rc;
- priv = card->p15priv;
- nobjs = priv->n_prkey_rsa_objs;
- rc = 0;
- if (idx >= nobjs)
- return -1;
- pinfo = priv->prkey_rsa_objs[idx]->data;
-
- /* now we need to read the certificate so that we can calculate the
- keygrip */
- rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &tmpobj);
- if (rc)
- {
- log_info ("certificate for private key %d not found: %s\n",
- idx, sc_strerror (rc));
- /* note, that we return the ID anyway */
- rc = gpg_error (GPG_ERR_MISSING_CERTIFICATE);
- goto return_keyid;
- }
- certinfo = tmpobj->data;
- rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
- if (rc)
- {
- log_info ("failed to read certificate for private key %d: %s\n",
- idx, sc_strerror (rc));
- return gpg_error (GPG_ERR_CARD);
- }
-
- cert = ksba_cert_new ();
- if (!cert)
- {
- gpg_error_t tmperr = out_of_core ();
- sc_pkcs15_free_certificate (certder);
- return tmperr;
- }
- krc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len);
- sc_pkcs15_free_certificate (certder);
- if (krc)
- {
- log_error ("failed to parse the certificate for private key %d: %s\n",
- idx, ksba_strerror (krc));
- ksba_cert_release (cert);
- return gpg_error (GPG_ERR_CARD);
- }
- if (card_help_get_keygrip (cert, keygrip))
- {
- log_error ("failed to calculate the keygrip of private key %d\n", idx);
- ksba_cert_release (cert);
- return gpg_error (GPG_ERR_CARD);
- }
- ksba_cert_release (cert);
-
- rc = 0;
- return_keyid:
- if (keyid)
- {
- char *p;
- int i;
-
- *keyid = p = xtrymalloc (9+pinfo->id.len*2+1);
- if (!*keyid)
- return out_of_core ();
- p = stpcpy (p, "P15-5015.");
- for (i=0; i < pinfo->id.len; i++, p += 2)
- sprintf (p, "%02X", pinfo->id.value[i]);
- *p = 0;
- }
-
- return rc;
-}
-
-/* See card.c for interface description */
-static int
-p15_enum_certs (CARD card, int idx, char **certid, int *type)
-{
- int rc;
- struct p15private_s *priv;
- struct sc_pkcs15_object *obj;
- struct sc_pkcs15_cert_info *cinfo;
- int nobjs;
-
- rc = init_private_data (card);
- if (rc)
- return rc;
- priv = card->p15priv;
- nobjs = priv->n_cert_objs;
- rc = 0;
- if (idx >= nobjs)
- return -1;
- obj = priv->cert_objs[idx];
- cinfo = obj->data;
-
- if (certid)
- {
- char *p;
- int i;
-
- *certid = p = xtrymalloc (9+cinfo->id.len*2+1);
- if (!*certid)
- return out_of_core ();
- p = stpcpy (p, "P15-5015.");
- for (i=0; i < cinfo->id.len; i++, p += 2)
- sprintf (p, "%02X", cinfo->id.value[i]);
- *p = 0;
- }
- if (type)
- {
- if (!obj->df)
- *type = 0; /* unknown */
- else if (obj->df->type == SC_PKCS15_CDF)
- *type = 100;
- else if (obj->df->type == SC_PKCS15_CDF_TRUSTED)
- *type = 101;
- else if (obj->df->type == SC_PKCS15_CDF_USEFUL)
- *type = 102;
- else
- *type = 0; /* error -> unknown */
- }
-
- return rc;
-}
-
-
-
-static int
-idstr_to_id (const char *idstr, struct sc_pkcs15_id *id)
-{
- const char *s;
- int n;
-
- /* For now we only support the standard DF */
- if (strncmp (idstr, "P15-5015.", 9) )
- return gpg_error (GPG_ERR_INV_ID);
- for (s=idstr+9, n=0; hexdigitp (s); s++, n++)
- ;
- if (*s || (n&1))
- return gpg_error (GPG_ERR_INV_ID); /*invalid or odd number of digits*/
- n /= 2;
- if (!n || n > SC_PKCS15_MAX_ID_SIZE)
- return gpg_error (GPG_ERR_INV_ID); /* empty or too large */
- for (s=idstr+9, n=0; *s; s += 2, n++)
- id->value[n] = xtoi_2 (s);
- id->len = n;
- return 0;
-}
-
-
-/* See card.c for interface description */
-static int
-p15_read_cert (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert)
-{
- struct sc_pkcs15_object *tmpobj;
- struct sc_pkcs15_id certid;
- struct sc_pkcs15_cert_info *certinfo;
- struct sc_pkcs15_cert *certder;
- int rc;
-
- if (!card || !certidstr || !cert || !ncert)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!card->p15card)
- return gpg_error (GPG_ERR_NO_PKCS15_APP);
-
- rc = idstr_to_id (certidstr, &certid);
- if (rc)
- return rc;
-
- rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &tmpobj);
- if (rc)
- {
- log_info ("certificate '%s' not found: %s\n",
- certidstr, sc_strerror (rc));
- return -1;
- }
- certinfo = tmpobj->data;
- rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
- if (rc)
- {
- log_info ("failed to read certificate '%s': %s\n",
- certidstr, sc_strerror (rc));
- return gpg_error (GPG_ERR_CARD);
- }
-
- *cert = xtrymalloc (certder->data_len);
- if (!*cert)
- {
- gpg_error_t tmperr = out_of_core ();
- sc_pkcs15_free_certificate (certder);
- return tmperr;
- }
- memcpy (*cert, certder->data, certder->data_len);
- *ncert = certder->data_len;
- sc_pkcs15_free_certificate (certder);
- return 0;
-}
-
-
-
-
-
-static int
-p15_prepare_key (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg, struct sc_pkcs15_object **r_keyobj)
-{
- struct sc_pkcs15_id keyid;
- struct sc_pkcs15_pin_info *pin;
- struct sc_pkcs15_object *keyobj, *pinobj;
- char *pinvalue;
- int rc;
-
- rc = idstr_to_id (keyidstr, &keyid);
- if (rc)
- return rc;
-
- rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &keyobj);
- if (rc < 0)
- {
- log_error ("private key not found: %s\n", sc_strerror(rc));
- return gpg_error (GPG_ERR_NO_SECRET_KEY);
- }
-
- rc = sc_pkcs15_find_pin_by_auth_id (card->p15card,
- &keyobj->auth_id, &pinobj);
- if (rc)
- {
- log_error ("failed to find PIN by auth ID: %s\n", sc_strerror (rc));
- return gpg_error (GPG_ERR_BAD_PIN_METHOD);
- }
- pin = pinobj->data;
-
- /* Fixme: pack this into a verification loop */
- /* Fixme: we might want to pass pin->min_length and
- pin->stored_length */
- rc = pincb (pincb_arg, pinobj->label, &pinvalue);
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gnupg_strerror (rc));
- return rc;
- }
-
- rc = sc_pkcs15_verify_pin (card->p15card, pin,
- pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_info ("PIN verification failed: %s\n", sc_strerror (rc));
- return gpg_error (GPG_ERR_BAD_PIN);
- }
-
- /* fixme: check wheter we need to release KEYOBJ in case of an error */
- *r_keyobj = keyobj;
- return 0;
-}
-
-
-/* See card.c for interface description */
-static int
-p15_sign (CARD card, const char *keyidstr, int hashalgo,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- unsigned int cryptflags;
- struct sc_pkcs15_object *keyobj;
- int rc;
- unsigned char *outbuf = NULL;
- size_t outbuflen;
-
- if (hashalgo != GCRY_MD_SHA1)
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
-
- rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj);
- if (rc)
- return rc;
-
- cryptflags = SC_ALGORITHM_RSA_PAD_PKCS1;
-
- outbuflen = 1024;
- outbuf = xtrymalloc (outbuflen);
- if (!outbuf)
- return out_of_core ();
-
- rc = sc_pkcs15_compute_signature (card->p15card, keyobj,
- cryptflags,
- indata, indatalen,
- outbuf, outbuflen );
- if (rc < 0)
- {
- log_error ("failed to create signature: %s\n", sc_strerror (rc));
- rc = gpg_error (GPG_ERR_CARD);
- }
- else
- {
- *outdatalen = rc;
- *outdata = outbuf;
- outbuf = NULL;
- rc = 0;
- }
-
- xfree (outbuf);
- return rc;
-}
-
-
-/* See card.c for description */
-static int
-p15_decipher (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- struct sc_pkcs15_object *keyobj;
- int rc;
- unsigned char *outbuf = NULL;
- size_t outbuflen;
-
- rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj);
- if (rc)
- return rc;
-
- if (card && card->scard && card->scard->driver
- && !strcasecmp (card->scard->driver->short_name, "tcos"))
- {
- /* very ugly hack to force the use of a local key. We need this
- until we have fixed the initialization code for TCOS cards */
- struct sc_pkcs15_prkey_info *prkey = keyobj->data;
- if ( !(prkey->key_reference & 0x80))
- {
- prkey->key_reference |= 0x80;
- log_debug ("using TCOS hack to force the use of local keys\n");
- }
- if (*keyidstr && keyidstr[strlen(keyidstr)-1] == '6')
- {
- prkey->key_reference |= 1;
- log_debug ("warning: using even more TCOS hacks\n");
- }
- }
-
- outbuflen = indatalen < 256? 256 : indatalen;
- outbuf = xtrymalloc (outbuflen);
- if (!outbuf)
- return out_of_core ();
-
- rc = sc_pkcs15_decipher (card->p15card, keyobj,
- 0,
- indata, indatalen,
- outbuf, outbuflen);
- if (rc < 0)
- {
- log_error ("failed to decipher the data: %s\n", sc_strerror (rc));
- rc = gpg_error (GPG_ERR_CARD);
- }
- else
- {
- *outdatalen = rc;
- *outdata = outbuf;
- outbuf = NULL;
- rc = 0;
- }
-
- xfree (outbuf);
- return rc;
-}
-
-
-
-/* Bind our operations to the card */
-void
-card_p15_bind (CARD card)
-{
- card->fnc.enum_keypairs = p15_enum_keypairs;
- card->fnc.enum_certs = p15_enum_certs;
- card->fnc.read_cert = p15_read_cert;
- card->fnc.sign = p15_sign;
- card->fnc.decipher = p15_decipher;
-}
-#endif /*HAVE_OPENSC*/
diff --git a/scd/card.c b/scd/card.c
deleted file mode 100644
index 02b7bfdbf..000000000
--- a/scd/card.c
+++ /dev/null
@@ -1,564 +0,0 @@
-/* card.c - SCdaemon card functions
- * Copyright (C) 2002 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifdef HAVE_OPENSC
-#include <opensc/pkcs15.h>
-#endif
-#include <ksba.h>
-
-#include "scdaemon.h"
-#include "card-common.h"
-
-/* Map the SC error codes to the GNUPG ones */
-gpg_error_t
-map_sc_err (int rc)
-{
- gpg_err_code_t e;
-
- switch (rc)
- {
- case 0: e = 0; break;
-#ifdef HAVE_OPENSC
- case SC_ERROR_NOT_SUPPORTED: e = GPG_ERR_NOT_SUPPORTED; break;
- case SC_ERROR_PKCS15_APP_NOT_FOUND: e = GPG_ERR_NO_PKCS15_APP; break;
- case SC_ERROR_OUT_OF_MEMORY: e = GPG_ERR_ENOMEM; break;
- case SC_ERROR_CARD_NOT_PRESENT: e = GPG_ERR_CARD_NOT_PRESENT; break;
- case SC_ERROR_CARD_REMOVED: e = GPG_ERR_CARD_REMOVED; break;
- case SC_ERROR_INVALID_CARD: e = GPG_ERR_INV_CARD; break;
-#endif
- default: e = GPG_ERR_CARD; break;
- }
- return gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, e);
-}
-
-/* Get the keygrip from CERT, return 0 on success */
-int
-card_help_get_keygrip (KsbaCert cert, unsigned char *array)
-{
- gcry_sexp_t s_pkey;
- int rc;
- KsbaSexp p;
- size_t n;
-
- p = ksba_cert_get_public_key (cert);
- if (!p)
- return -1; /* oops */
- n = gcry_sexp_canon_len (p, 0, NULL, NULL);
- if (!n)
- return -1; /* libksba did not return a proper S-expression */
- rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
- xfree (p);
- if (rc)
- return -1; /* can't parse that S-expression */
- array = gcry_pk_get_keygrip (s_pkey, array);
- gcry_sexp_release (s_pkey);
- if (!array)
- return -1; /* failed to calculate the keygrip */
- return 0;
-}
-
-
-
-
-
-
-
-/* Create a new context for the card and figures out some basic
- information of the card. Detects whgether a PKCS_15 application is
- stored.
-
- Common errors: GPG_ERR_CARD_NOT_PRESENT */
-int
-card_open (CARD *rcard)
-{
-#ifdef HAVE_OPENSC
- CARD card;
- int rc;
-
- card = xtrycalloc (1, sizeof *card);
- if (!card)
- return out_of_core ();
- card->reader = 0;
-
- rc = sc_establish_context (&card->ctx, "scdaemon");
- if (rc)
- {
- log_error ("failed to establish SC context: %s\n", sc_strerror (rc));
- rc = map_sc_err (rc);
- goto leave;
- }
- if (card->reader >= card->ctx->reader_count)
- {
- log_error ("no card reader available\n");
- rc = gpg_error (GPG_ERR_CARD);
- goto leave;
- }
- card->ctx->error_file = log_get_stream ();
- card->ctx->debug = opt.debug_sc;
- card->ctx->debug_file = log_get_stream ();
-
- if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1)
- {
- rc = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
- goto leave;
- }
-
- rc = sc_connect_card (card->ctx->reader[card->reader], 0, &card->scard);
- if (rc)
- {
- log_error ("failed to connect card in reader %d: %s\n",
- card->reader, sc_strerror (rc));
- rc = map_sc_err (rc);
- goto leave;
- }
- if (opt.verbose)
- log_info ("connected to card in reader %d using driver `%s'\n",
- card->reader, card->scard->driver->name);
-
- rc = sc_lock (card->scard);
- if (rc)
- {
- log_error ("can't lock card in reader %d: %s\n",
- card->reader, sc_strerror (rc));
- rc = map_sc_err (rc);
- goto leave;
- }
-
-
- leave:
- if (rc)
- card_close (card);
- else
- *rcard = card;
-
- return rc;
-#else
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
-#endif
-}
-
-
-/* Close a card and release all resources */
-void
-card_close (CARD card)
-{
- if (card)
- {
-#ifdef HAVE_OPENSC
- if (card->p15card)
- {
- sc_pkcs15_unbind (card->p15card);
- card->p15card = NULL;
- }
- if (card->p15priv)
- p15_release_private_data (card);
- if (card->scard)
- {
- sc_unlock (card->scard);
- sc_disconnect_card (card->scard, 0);
- card->scard = NULL;
- }
- if (card->ctx)
- {
- sc_release_context (card->ctx);
- card->ctx = NULL;
- }
-#endif
- xfree (card);
- }
-}
-
-/* Locate a simple TLV encoded data object in BUFFER of LENGTH and
- return a pointer to value as well as its length in NBYTES. Return
- NULL if it was not found. Note, that the function does not check
- whether the value fits into the provided buffer. */
-#ifdef HAVE_OPENSC
-static const char *
-find_simple_tlv (const unsigned char *buffer, size_t length,
- int tag, size_t *nbytes)
-{
- const char *s = buffer;
- size_t n = length;
- size_t len;
-
- for (;;)
- {
- buffer = s;
- if (n < 2)
- return NULL; /* buffer too short for tag and length. */
- len = s[1];
- s += 2; n -= 2;
- if (len == 255)
- {
- if (n < 2)
- return NULL; /* we expected 2 more bytes with the length. */
- len = (s[0] << 8) | s[1];
- s += 2; n -= 2;
- }
- if (*buffer == tag)
- {
- *nbytes = len;
- return s;
- }
- if (len > n)
- return NULL; /* buffer too short to skip to the next tag. */
- s += len; n -= len;
- }
-}
-#endif /*HAVE_OPENSC*/
-
-/* Find the ICC Serial Number within the provided BUFFER of LENGTH
- (which should contain the GDO file) and return it as a hex encoded
- string and allocated string in SERIAL. Return an error code when
- the ICCSN was not found. */
-#ifdef HAVE_OPENSC
-static int
-find_iccsn (const unsigned char *buffer, size_t length, char **serial)
-{
- size_t n;
- const unsigned char *s;
- char *p;
-
- s = find_simple_tlv (buffer, length, 0x5A, &n);
- if (!s)
- return gpg_error (GPG_ERR_CARD);
- length -= s - buffer;
- if (n > length)
- {
- /* Oops, it does not fit into the buffer. This is an invalid
- encoding (or the buffer is too short. However, I have some
- test cards with such an invalid encoding and therefore I use
- this ugly workaround to return something I can further
- experiment with. */
- if (n == 0x0D && length+1 == n)
- {
- log_debug ("enabling BMI testcard workaround\n");
- n--;
- }
- else
- return gpg_error (GPG_ERR_CARD); /* Bad encoding; does
- not fit into buffer. */
- }
- if (!n)
- return gpg_error (GPG_ERR_CARD); /* Well, that is too short. */
-
- *serial = p = xtrymalloc (2*n+1);
- if (!*serial)
- return out_of_core ();
- for (; n; n--, p += 2, s++)
- sprintf (p, "%02X", *s);
- *p = 0;
- return 0;
-}
-#endif /*HAVE_OPENSC*/
-
-/* Retrieve the serial number and the time of the last update of the
- card. The serial number is returned as a malloced string (hex
- encoded) in SERIAL and the time of update is returned in STAMP.
- If no update time is available the returned value is 0. The serial
- is mandatory for a PKCS_15 application and an error will be
- returned if this value is not availbale. For non-PKCS-15 cards a
- serial number is constructed by other means. Caller must free
- SERIAL unless the function returns an error. */
-int
-card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
-{
-#ifdef HAVE_OPENSC
- int rc;
- struct sc_path path;
- struct sc_file *file;
- unsigned char buf[256];
- int buflen;
-#endif
-
- if (!card || !serial || !stamp)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- *serial = NULL;
- *stamp = 0; /* not available */
-
-#ifdef HAVE_OPENSC
- if (!card->fnc.initialized)
- {
- card->fnc.initialized = 1;
- /* The first use of this card tries to figure out the type of the card
- and sets up the function pointers. */
- rc = sc_pkcs15_bind (card->scard, &card->p15card);
- if (rc)
- {
- if (rc != SC_ERROR_PKCS15_APP_NOT_FOUND)
- log_error ("binding of existing PKCS-15 failed in reader %d: %s\n",
- card->reader, sc_strerror (rc));
- card->p15card = NULL;
- rc = 0;
- }
- if (card->p15card)
- card_p15_bind (card);
- else
- card_dinsig_bind (card);
- card->fnc.initialized = 1;
- }
-
-
- /* We should lookup the iso 7812-1 and 8583-3 - argh ISO
- practice is suppressing innovation - IETF rules! So we
- always get the serialnumber from the 2F02 GDO file. */
- /* FIXME: in case we can't parse the 2F02 EF and we have a P15 card,
- we should get the serial number from the respective P15 file */
- sc_format_path ("3F002F02", &path);
- rc = sc_select_file (card->scard, &path, &file);
- if (rc)
- {
- log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
- return gpg_error (GPG_ERR_CARD);
- }
- if (file->type != SC_FILE_TYPE_WORKING_EF
- || file->ef_structure != SC_FILE_EF_TRANSPARENT)
- {
- log_error ("wrong type or structure of GDO file\n");
- sc_file_free (file);
- return gpg_error (GPG_ERR_CARD);
- }
-
- if (!file->size || file->size >= DIM(buf) )
- { /* FIXME: Use a real parser */
- log_error ("unsupported size of GDO file (%d)\n", file->size);
- sc_file_free (file);
- return gpg_error (GPG_ERR_CARD);
- }
- buflen = file->size;
-
- rc = sc_read_binary (card->scard, 0, buf, buflen, 0);
- sc_file_free (file);
- if (rc < 0)
- {
- log_error ("error reading GDO file: %s\n", sc_strerror (rc));
- return gpg_error (GPG_ERR_CARD);
- }
- if (rc != buflen)
- {
- log_error ("short read on GDO file\n");
- return gpg_error (GPG_ERR_CARD);
- }
-
- rc = find_iccsn (buf, buflen, serial);
- if (gpg_err_code (rc) == GPG_ERR_CARD)
- log_error ("invalid structure of GDO file\n");
- if (!rc && card->p15card && !strcmp (*serial, "D27600000000000000000000"))
- { /* This is a German card with a silly serial number. Try to get
- the serial number from the EF(TokenInfo). We indicate such a
- serial number by the using the prefix: "FF0100". */
- const char *efser = card->p15card->serial_number;
- char *p;
-
- if (!efser)
- efser = "";
-
- xfree (*serial);
- *serial = NULL;
- p = xtrymalloc (strlen (efser) + 7);
- if (!p)
- rc = out_of_core ();
- else
- {
- strcpy (p, "FF0100");
- strcpy (p+6, efser);
- *serial = p;
- }
- }
- else if (!rc && **serial == 'F' && (*serial)[1] == 'F')
- { /* The serial number starts with our special prefix. This
- requires that we put our default prefix "FF0000" in front. */
- char *p = xtrymalloc (strlen (*serial) + 7);
- if (!p)
- {
- xfree (*serial);
- *serial = NULL;
- rc = out_of_core ();
- }
- else
- {
- strcpy (p, "FF0000");
- strcpy (p+6, *serial);
- xfree (*serial);
- *serial = p;
- }
- }
- return rc;
-#else
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
-#endif
-}
-
-
-/* Enumerate all keypairs on the card and return the Keygrip as well
- as the internal identification of the key. KEYGRIP must be a
- caller provided buffer with a size of 20 bytes which will receive
- the KEYGRIP of the keypair. If KEYID is not NULL, it returns the
- ID field of the key in allocated memory; this is a string without
- spaces. The function returns -1 when all keys have been
- enumerated. Note that the error GPG_ERR_MISSING_CERTIFICATE may be
- returned if there is just the private key but no public key (ie.e a
- certificate) available. Applications might want to continue
- enumerating after this error.*/
-int
-card_enum_keypairs (CARD card, int idx,
- unsigned char *keygrip,
- char **keyid)
-{
- int rc;
-
- if (keyid)
- *keyid = NULL;
-
- if (!card || !keygrip)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (idx < 0)
- return gpg_error (GPG_ERR_INV_INDEX);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.enum_keypairs)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.enum_keypairs (card, idx, keygrip, keyid);
- if (opt.verbose)
- log_info ("card operation enum_keypairs result: %s\n",
- gpg_strerror (rc));
- return rc;
-}
-
-
-/* Enumerate all trusted certificates available on the card, return
- their ID in CERT and the type in CERTTYPE. Types of certificates
- are:
- 0 := Unknown
- 100 := Regular X.509 cert
- 101 := Trusted X.509 cert
- 102 := Useful X.509 cert
- */
-int
-card_enum_certs (CARD card, int idx, char **certid, int *certtype)
-{
- int rc;
-
- if (certid)
- *certid = NULL;
-
- if (!card)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (idx < 0)
- return gpg_error (GPG_ERR_INV_INDEX);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.enum_certs)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.enum_certs (card, idx, certid, certtype);
- if (opt.verbose)
- log_info ("card operation enum_certs result: %s\n",
- gpg_strerror (rc));
- return rc;
-}
-
-
-
-/* Read the certificate identified by CERTIDSTR which is the
- hexadecimal encoded ID of the certificate, prefixed with the string
- "3F005015.". The certificate is return in DER encoded form in CERT
- and NCERT. */
-int
-card_read_cert (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert)
-{
- int rc;
-
- if (!card || !certidstr || !cert || !ncert)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.read_cert)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.read_cert (card, certidstr, cert, ncert);
- if (opt.verbose)
- log_info ("card operation read_cert result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-
-/* Create the signature and return the allocated result in OUTDATA.
- If a PIN is required the PINCB will be used to ask for the PIN; it
- should return the PIN in an allocated buffer and put it into PIN. */
-int
-card_sign (CARD card, const char *keyidstr, int hashalgo,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- int rc;
-
- if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.sign)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.sign (card, keyidstr, hashalgo,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- if (opt.verbose)
- log_info ("card operation sign result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
-
-/* Create the signature and return the allocated result in OUTDATA.
- If a PIN is required the PINCB will be used to ask for the PIN; it
- should return the PIN in an allocated buffer and put it into PIN. */
-int
-card_decipher (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen )
-{
- int rc;
-
- if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!card->fnc.initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!card->fnc.decipher)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = card->fnc.decipher (card, keyidstr,
- pincb, pincb_arg,
- indata, indatalen,
- outdata, outdatalen);
- if (opt.verbose)
- log_info ("card operation decipher result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
diff --git a/scd/command.c b/scd/command.c
deleted file mode 100644
index c53af84f9..000000000
--- a/scd/command.c
+++ /dev/null
@@ -1,1034 +0,0 @@
-/* command.c - SCdaemon command handler
- * Copyright (C) 2001, 2002, 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <ksba.h>
-
-#include <assuan.h>
-
-#include "scdaemon.h"
-#include "app-common.h"
-
-/* maximum length aloowed as a PIN; used for INQUIRE NEEDPIN */
-#define MAXLEN_PIN 100
-
-#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
-
-/* Data used to associate an Assuan context with local server data */
-struct server_local_s {
- ASSUAN_CONTEXT assuan_ctx;
-};
-
-
-/* Check whether the option NAME appears in LINE */
-static int
-has_option (const char *line, const char *name)
-{
- const char *s;
- int n = strlen (name);
-
- s = strstr (line, name);
- return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
-}
-
-
-
-
-/* Note, that this reset_notify is also used for cleanup purposes. */
-static void
-reset_notify (ASSUAN_CONTEXT ctx)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
-
- if (ctrl->card_ctx)
- {
- card_close (ctrl->card_ctx);
- ctrl->card_ctx = NULL;
- xfree (ctrl->in_data.value);
- ctrl->in_data.value = NULL;
- }
- if (ctrl->app_ctx)
- {
- /* FIXME: close the application. */
- xfree (ctrl->app_ctx);
- ctrl->app_ctx = NULL;
- }
-}
-
-
-static int
-option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
-{
- return 0;
-}
-
-
-/* If the card has not yet been opened, do it. Note that this
- function returns an Assuan error, so don't map the error a second
- time */
-static AssuanError
-open_card (CTRL ctrl)
-{
- if (ctrl->app_ctx)
- return 0; /* Already initialized for one specific application. */
- if (ctrl->card_ctx)
- return 0; /* Already initialized using a card context. */
-
- ctrl->app_ctx = select_application ();
- if (!ctrl->app_ctx)
- { /* No application found - fall back to old mode. */
- int rc = card_open (&ctrl->card_ctx);
- if (rc)
- return map_to_assuan_status (rc);
- }
- return 0;
-}
-
-
-/* Do the percent and plus/space unescaping in place and return tghe
- length of the valid buffer. */
-static size_t
-percent_plus_unescape (unsigned char *string)
-{
- unsigned char *p = string;
- size_t n = 0;
-
- while (*string)
- {
- if (*string == '%' && string[1] && string[2])
- {
- string++;
- *p++ = xtoi_2 (string);
- n++;
- string+= 2;
- }
- else if (*string == '+')
- {
- *p++ = ' ';
- n++;
- string++;
- }
- else
- {
- *p++ = *string++;
- n++;
- }
- }
-
- return n;
-}
-
-
-
-/* SERIALNO
-
- Return the serial number of the card using a status reponse. This
- functon should be used to check for the presence of a card.
-
- This function is special in that it can be used to reset the card.
- Most other functions will return an error when a card change has
- been detected and the use of this function is therefore required.
-
- Background: We want to keep the client clear of handling card
- changes between operations; i.e. the client can assume that all
- operations are done on the same card unless he calls this function.
- */
-static int
-cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc = 0;
- char *serial_and_stamp;
- char *serial;
- time_t stamp;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- if (ctrl->app_ctx)
- rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
- else
- rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
- if (rc)
- return map_to_assuan_status (rc);
- rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
- xfree (serial);
- if (rc < 0)
- return ASSUAN_Out_Of_Core;
- rc = 0;
- assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
- free (serial_and_stamp);
- return 0;
-}
-
-
-
-
-/* LEARN [--force]
-
- Learn all useful information of the currently inserted card. When
- used without the force options, the command might do an INQUIRE
- like this:
-
- INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
-
- The client should just send an "END" if the processing should go on
- or a "CANCEL" to force the function to terminate with a Cancel
- error message. The response of this command is a list of status
- lines formatted as this:
-
- S APPTYPE <apptype>
-
- This returns the type of the application, currently the strings:
-
- P15 = PKCS-15 structure used
- DINSIG = DIN SIG
- OPENPGP = OpenPGP card
-
- are implemented. These strings are aliases for the AID
-
- S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
-
- If there is no certificate yet stored on the card a single "X" is
- returned as the keygrip. In addition to the keypair info, information
- about all certificates stored on the card is also returned:
-
- S CERTINFO <certtype> <hexstring_with_id>
-
- Where CERTTYPE is a number indicating the type of certificate:
- 0 := Unknown
- 100 := Regular X.509 cert
- 101 := Trusted X.509 cert
- 102 := Useful X.509 cert
-
- For certain cards, more information will be returned:
-
- S KEY-FPR <no> <hexstring>
-
- For OpenPGP cards this returns the stored fingerprints of the
- keys. This can be used check whether a key is available on the
- card. NO may be 1, 2 or 3.
-
- S CA-FPR <no> <hexstring>
-
- Similar to above, these are the fingerprints of keys assumed to be
- ultimately trusted.
-
- S DISP-NAME <name_of_card_holder>
-
- The name of the card holder as stored on the card; percent
- aescaping takes place, spaces are encoded as '+'
-
- S PUBKEY-URL <url>
-
- The URL to be used for locating the entire public key.
-
-*/
-static int
-cmd_learn (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc = 0;
- int idx;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- /* Unless the force option is used we try a shortcut by identifying
- the card using a serial number and inquiring the client with
- that. The client may choose to cancel the operation if he already
- knows about this card */
- {
- char *serial_and_stamp;
- char *serial;
- time_t stamp;
-
- if (ctrl->app_ctx)
- rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
- else
- rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
- if (rc)
- return map_to_assuan_status (rc);
- rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
- xfree (serial);
- if (rc < 0)
- return ASSUAN_Out_Of_Core;
- rc = 0;
- assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
-
- if (!has_option (line, "--force"))
- {
- char *command;
-
- rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
- if (rc < 0)
- {
- free (serial_and_stamp);
- return ASSUAN_Out_Of_Core;
- }
- rc = 0;
- rc = assuan_inquire (ctx, command, NULL, NULL, 0);
- free (command); /* (must use standard free here) */
- if (rc)
- {
- if (rc != ASSUAN_Canceled)
- log_error ("inquire KNOWNCARDP failed: %s\n",
- assuan_strerror (rc));
- free (serial_and_stamp);
- return rc;
- }
- /* not canceled, so we have to proceeed */
- }
- free (serial_and_stamp);
- }
-
- /* Return information about the certificates. */
- if (ctrl->app_ctx)
- rc = -1; /* This information is not yet available for applications. */
- for (idx=0; !rc; idx++)
- {
- char *certid;
- int certtype;
-
- rc = card_enum_certs (ctrl->card_ctx, idx, &certid, &certtype);
- if (!rc)
- {
- char *buf;
-
- buf = xtrymalloc (40 + 1 + strlen (certid) + 1);
- if (!buf)
- rc = out_of_core ();
- else
- {
- sprintf (buf, "%d %s", certtype, certid);
- assuan_write_status (ctx, "CERTINFO", buf);
- xfree (buf);
- }
- }
- xfree (certid);
- }
- if (rc == -1)
- rc = 0;
-
-
- /* Return information about the keys. */
- if (ctrl->app_ctx)
- rc = -1; /* This information is not yet available for applications. */
- for (idx=0; !rc; idx++)
- {
- unsigned char keygrip[20];
- char *keyid;
- int no_cert = 0;
-
- rc = card_enum_keypairs (ctrl->card_ctx, idx, keygrip, &keyid);
- if (gpg_err_code (rc) == GPG_ERR_MISSING_CERT && keyid)
- {
- /* this does happen with an incomplete personalized
- card; i.e. during the time we have stored the key on the
- card but not stored the certificate; probably becuase it
- has not yet been received back from the CA. Note that we
- must release KEYID in this case. */
- rc = 0;
- no_cert = 1;
- }
- if (!rc)
- {
- char *buf, *p;
-
- buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1);
- if (!buf)
- rc = out_of_core ();
- else
- {
- int i;
-
- if (no_cert)
- *p++ = 'X';
- else
- {
- for (i=0; i < 20; i++, p += 2)
- sprintf (p, "%02X", keygrip[i]);
- }
- *p++ = ' ';
- strcpy (p, keyid);
- assuan_write_status (ctx, "KEYPAIRINFO", buf);
- xfree (buf);
- }
- }
- xfree (keyid);
- }
- if (rc == -1)
- rc = 0;
-
- if (!rc && ctrl->app_ctx)
- rc = app_write_learn_status (ctrl->app_ctx, ctrl);
-
-
- return map_to_assuan_status (rc);
-}
-
-
-
-/* READCERT <hexified_certid>
-
- */
-static int
-cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- unsigned char *cert;
- size_t ncert;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- if (ctrl->app_ctx)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
- if (rc)
- {
- log_error ("card_read_cert failed: %s\n", gpg_strerror (rc));
- }
- if (!rc)
- {
- rc = assuan_send_data (ctx, cert, ncert);
- xfree (cert);
- if (rc)
- return rc;
- }
-
- return map_to_assuan_status (rc);
-}
-
-
-/* READKEY <hexified_certid>
-
- Return the public key for the given cert or key ID as an standard
- S-Expression. */
-static int
-cmd_readkey (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- unsigned char *cert = NULL;
- size_t ncert, n;
- KsbaCert kc = NULL;
- KsbaSexp p;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- if (ctrl->app_ctx)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
- if (rc)
- {
- log_error ("card_read_cert failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- kc = ksba_cert_new ();
- if (!kc)
- {
- rc = out_of_core ();
- xfree (cert);
- goto leave;
- }
- rc = ksba_cert_init_from_mem (kc, cert, ncert);
- if (rc)
- {
- log_error ("failed to parse the certificate: %s\n", ksba_strerror (rc));
- rc = map_ksba_err (rc);
- goto leave;
- }
-
- p = ksba_cert_get_public_key (kc);
- if (!p)
- {
- rc = gpg_error (GPG_ERR_NO_PUBKEY);
- goto leave;
- }
-
- n = gcry_sexp_canon_len (p, 0, NULL, NULL);
- rc = assuan_send_data (ctx, p, n);
- rc = map_assuan_err (rc);
- xfree (p);
-
-
- leave:
- ksba_cert_release (kc);
- xfree (cert);
- return map_to_assuan_status (rc);
-}
-
-
-
-
-/* SETDATA <hexstring>
-
- The client should use this command to tell us the data he want to
- sign. */
-static int
-cmd_setdata (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int n;
- char *p;
- unsigned char *buf;
-
- /* parse the hexstring */
- for (p=line,n=0; hexdigitp (p); p++, n++)
- ;
- if (*p)
- return set_error (Parameter_Error, "invalid hexstring");
- if (!n)
- return set_error (Parameter_Error, "no data given");
- if ((n&1))
- return set_error (Parameter_Error, "odd number of digits");
- n /= 2;
- buf = xtrymalloc (n);
- if (!buf)
- return ASSUAN_Out_Of_Core;
-
- ctrl->in_data.value = buf;
- ctrl->in_data.valuelen = n;
- for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
- buf[n] = xtoi_2 (p);
- return 0;
-}
-
-
-
-static int
-pin_cb (void *opaque, const char *info, char **retstr)
-{
- ASSUAN_CONTEXT ctx = opaque;
- char *command;
- int rc;
- char *value;
- size_t valuelen;
-
- *retstr = NULL;
- log_debug ("asking for PIN '%s'\n", info);
-
- rc = asprintf (&command, "NEEDPIN %s", info);
- if (rc < 0)
- return out_of_core ();
-
- /* FIXME: Write an inquire function which returns the result in
- secure memory */
- rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN);
- free (command);
- if (rc)
- return map_assuan_err (rc);
-
- if (!valuelen || value[valuelen-1])
- {
- /* We require that the returned value is an UTF-8 string */
- xfree (value);
- return gpg_error (GPG_ERR_INV_RESPONSE);
- }
- *retstr = value;
- return 0;
-}
-
-
-/* PKSIGN <hexified_id>
-
- */
-static int
-cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- unsigned char *outdata;
- size_t outdatalen;
- char *keyidstr;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- /* We have to use a copy of the key ID because the function may use
- the pin_cb which in turn uses the assuan line buffer and thus
- overwriting the original line with the keyid */
- keyidstr = strdup (line);
- if (!keyidstr)
- return ASSUAN_Out_Of_Core;
-
- if (ctrl->app_ctx)
- rc = app_sign (ctrl->app_ctx,
- keyidstr, GCRY_MD_SHA1,
- pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
- else
- rc = card_sign (ctrl->card_ctx,
- keyidstr, GCRY_MD_SHA1,
- pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
- free (keyidstr);
- if (rc)
- {
- log_error ("card_sign failed: %s\n", gpg_strerror (rc));
- }
- else
- {
- rc = assuan_send_data (ctx, outdata, outdatalen);
- xfree (outdata);
- if (rc)
- return rc; /* that is already an assuan error code */
- }
-
- return map_to_assuan_status (rc);
-}
-
-/* PKAUTH <hexified_id>
-
- */
-static int
-cmd_pkauth (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- unsigned char *outdata;
- size_t outdatalen;
- char *keyidstr;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- if (!ctrl->app_ctx)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- /* We have to use a copy of the key ID because the function may use
- the pin_cb which in turn uses the assuan line buffer and thus
- overwriting the original line with the keyid */
- keyidstr = strdup (line);
- if (!keyidstr)
- return ASSUAN_Out_Of_Core;
-
- rc = app_auth (ctrl->app_ctx,
- keyidstr,
- pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
- free (keyidstr);
- if (rc)
- {
- log_error ("app_auth_sign failed: %s\n", gpg_strerror (rc));
- }
- else
- {
- rc = assuan_send_data (ctx, outdata, outdatalen);
- xfree (outdata);
- if (rc)
- return rc; /* that is already an assuan error code */
- }
-
- return map_to_assuan_status (rc);
-}
-
-/* PKDECRYPT <hexified_id>
-
- */
-static int
-cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- unsigned char *outdata;
- size_t outdatalen;
- char *keyidstr;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- keyidstr = strdup (line);
- if (!keyidstr)
- return ASSUAN_Out_Of_Core;
- if (ctrl->app_ctx)
- rc = app_decipher (ctrl->app_ctx,
- keyidstr,
- pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
- else
- rc = card_decipher (ctrl->card_ctx,
- keyidstr,
- pin_cb, ctx,
- ctrl->in_data.value, ctrl->in_data.valuelen,
- &outdata, &outdatalen);
- free (keyidstr);
- if (rc)
- {
- log_error ("card_create_signature failed: %s\n", gpg_strerror (rc));
- }
- else
- {
- rc = assuan_send_data (ctx, outdata, outdatalen);
- xfree (outdata);
- if (rc)
- return rc; /* that is already an assuan error code */
- }
-
- return map_to_assuan_status (rc);
-}
-
-
-/* SETATTR <name> <value>
-
- This command is used to store data on a a smartcard. The allowed
- names and values are depend on the currently selected smartcard
- application. NAME and VALUE must be percent and '+' escaped.
-
- However, the curent implementation assumes that Name is not escaped;
- this works as long as noone uses arbitrary escaping.
-
- A PIN will be requested for most NAMEs. See the corresponding
- setattr function of the actually used application (app-*.c) for
- details. */
-static int
-cmd_setattr (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- char *keyword;
- int keywordlen;
- size_t nbytes;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- keyword = line;
- for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
- ;
- if (*line)
- *line++ = 0;
- while (spacep (line))
- line++;
- nbytes = percent_plus_unescape (line);
-
- rc = app_setattr (ctrl->app_ctx, keyword, pin_cb, ctx, line, nbytes);
-
- return map_to_assuan_status (rc);
-}
-
-/* GENKEY [--force] <no>
-
- Generate a key on-card identified by NO, which is application
- specific. Return values are application specific. For OpenPGP
- cards 2 status lines are returned:
-
- S KEY-FPR <hexstring>
- S KEY-CREATED-AT <seconds_since_epoch>
- S KEY-DATA [p|n] <hexdata>
-
-
- --force is required to overwriet an already existing key. The
- KEY-CREATED-AT is required for further processing because it is
- part of the hashed key material for the fingerprint.
-
- The public part of the key can also later be retrieved using the
- READKEY command.
-
- */
-static int
-cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- char *keyno;
- int force = has_option (line, "--force");
-
- /* Skip over options. */
- while ( *line == '-' && line[1] == '-' )
- {
- while (!spacep (line))
- line++;
- while (spacep (line))
- line++;
- }
- if (!*line)
- return set_error (Parameter_Error, "no key number given");
- keyno = line;
- while (!spacep (line))
- line++;
- *line = 0;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- if (!ctrl->app_ctx)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx);
-
- return map_to_assuan_status (rc);
-}
-
-
-/* RANDOM <nbytes>
-
- Get NBYTES of random from the card and send them back as data.
-*/
-static int
-cmd_random (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- size_t nbytes;
- unsigned char *buffer;
-
- if (!*line)
- return set_error (Parameter_Error, "number of requested bytes missing");
- nbytes = strtoul (line, NULL, 0);
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- if (!ctrl->app_ctx)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- buffer = xtrymalloc (nbytes);
- if (!buffer)
- return ASSUAN_Out_Of_Core;
-
- rc = app_get_challenge (ctrl->app_ctx, nbytes, buffer);
- if (!rc)
- {
- rc = assuan_send_data (ctx, buffer, nbytes);
- xfree (buffer);
- return rc; /* that is already an assuan error code */
- }
- xfree (buffer);
-
- return map_to_assuan_status (rc);
-}
-
-
-/* PASSWD [--reset] <chvno>
-
- Change the PIN or reset thye retry counter of the card holder
- verfication vector CHVNO. */
-static int
-cmd_passwd (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- char *chvnostr;
- int reset_mode = has_option (line, "--reset");
-
- /* Skip over options. */
- while (*line == '-' && line[1] == '-')
- {
- while (!spacep (line))
- line++;
- while (spacep (line))
- line++;
- }
- if (!*line)
- return set_error (Parameter_Error, "no CHV number given");
- chvnostr = line;
- while (!spacep (line))
- line++;
- *line = 0;
-
- if ((rc = open_card (ctrl)))
- return rc;
-
- if (!ctrl->app_ctx)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- rc = app_change_pin (ctrl->app_ctx, ctrl, chvnostr, reset_mode, pin_cb, ctx
-);
- if (rc)
- log_error ("command passwd failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-
-
-
-/* Tell the assuan library about our commands */
-static int
-register_commands (ASSUAN_CONTEXT ctx)
-{
- static struct {
- const char *name;
- int (*handler)(ASSUAN_CONTEXT, char *line);
- } table[] = {
- { "SERIALNO", cmd_serialno },
- { "LEARN", cmd_learn },
- { "READCERT", cmd_readcert },
- { "READKEY", cmd_readkey },
- { "SETDATA", cmd_setdata },
- { "PKSIGN", cmd_pksign },
- { "PKAUTH", cmd_pkauth },
- { "PKDECRYPT", cmd_pkdecrypt },
- { "INPUT", NULL },
- { "OUTPUT", NULL },
- { "SETATTR", cmd_setattr },
- { "GENKEY", cmd_genkey },
- { "RANDOM", cmd_random },
- { "PASSWD", cmd_passwd },
- { NULL }
- };
- int i, rc;
-
- for (i=0; table[i].name; i++)
- {
- rc = assuan_register_command (ctx, table[i].name, table[i].handler);
- if (rc)
- return rc;
- }
- assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
-
- assuan_register_reset_notify (ctx, reset_notify);
- assuan_register_option_handler (ctx, option_handler);
- return 0;
-}
-
-
-/* Startup the server. If LISTEN_FD is given as -1, this is simple
- piper server, otherwise it is a regular server */
-void
-scd_command_handler (int listen_fd)
-{
- int rc;
- ASSUAN_CONTEXT ctx;
- struct server_control_s ctrl;
-
- memset (&ctrl, 0, sizeof ctrl);
- scd_init_default_ctrl (&ctrl);
-
- if (listen_fd == -1)
- {
- int filedes[2];
-
- filedes[0] = 0;
- filedes[1] = 1;
- rc = assuan_init_pipe_server (&ctx, filedes);
- }
- else
- {
- rc = assuan_init_socket_server (&ctx, listen_fd);
- }
- if (rc)
- {
- log_error ("failed to initialize the server: %s\n",
- assuan_strerror(rc));
- scd_exit (2);
- }
- rc = register_commands (ctx);
- if (rc)
- {
- log_error ("failed to register commands with Assuan: %s\n",
- assuan_strerror(rc));
- scd_exit (2);
- }
- assuan_set_pointer (ctx, &ctrl);
- ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
- ctrl.server_local->assuan_ctx = ctx;
-
- if (DBG_ASSUAN)
- assuan_set_log_stream (ctx, log_get_stream ());
-
- for (;;)
- {
- rc = assuan_accept (ctx);
- if (rc == -1)
- {
- break;
- }
- else if (rc)
- {
- log_info ("Assuan accept problem: %s\n", assuan_strerror (rc));
- break;
- }
-
- rc = assuan_process (ctx);
- if (rc)
- {
- log_info ("Assuan processing failed: %s\n", assuan_strerror (rc));
- continue;
- }
- }
- reset_notify (ctx); /* used for cleanup */
-
- assuan_deinit_server (ctx);
-}
-
-
-/* Send a line with status information via assuan and escape all given
- buffers. The variable elements are pairs of (char *, size_t),
- terminated with a (NULL, 0). */
-void
-send_status_info (CTRL ctrl, const char *keyword, ...)
-{
- va_list arg_ptr;
- const unsigned char *value;
- size_t valuelen;
- char buf[950], *p;
- size_t n;
- ASSUAN_CONTEXT ctx = ctrl->server_local->assuan_ctx;
-
- va_start (arg_ptr, keyword);
-
- p = buf;
- n = 0;
- while ( (value = va_arg (arg_ptr, const unsigned char *)) )
- {
- valuelen = va_arg (arg_ptr, size_t);
- if (!valuelen)
- continue; /* empty buffer */
- if (n)
- {
- *p++ = ' ';
- n++;
- }
- for ( ; valuelen && n < DIM (buf)-2; n++, valuelen--, value++)
- {
- if (*value < ' ' || *value == '+')
- {
- sprintf (p, "%%%02X", *value);
- p += 3;
- }
- else if (*value == ' ')
- *p++ = '+';
- else
- *p++ = *value;
- }
- }
- *p = 0;
- assuan_write_status (ctx, keyword, buf);
-
- va_end (arg_ptr);
-}
-
diff --git a/scd/iso7816.c b/scd/iso7816.c
deleted file mode 100644
index 8903d8a5c..000000000
--- a/scd/iso7816.c
+++ /dev/null
@@ -1,371 +0,0 @@
-/* iso7816.c - ISO 7816 commands
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dlfcn.h>
-
-#include "scdaemon.h"
-#include "iso7816.h"
-#include "apdu.h"
-
-#define CMD_SELECT_FILE 0xA4
-#define CMD_VERIFY 0x20
-#define CMD_CHANGE_REFERENCE_DATA 0x24
-#define CMD_RESET_RETRY_COUNTER 0x2C
-#define CMD_GET_DATA 0xCA
-#define CMD_PUT_DATA 0xDA
-#define CMD_PSO 0x2A
-#define CMD_INTERNAL_AUTHENTICATE 0x88
-#define CMD_GENERATE_KEYPAIR 0x47
-#define CMD_GET_CHALLENGE 0x84
-
-static gpg_error_t
-map_sw (int sw)
-{
- gpg_err_code_t ec;
-
- switch (sw)
- {
- case SW_EEPROM_FAILURE: ec = GPG_ERR_HARDWARE; break;
- case SW_WRONG_LENGTH: ec = GPG_ERR_INV_VALUE; break;
- case SW_CHV_WRONG: ec = GPG_ERR_BAD_PIN; break;
- case SW_CHV_BLOCKED: ec = GPG_ERR_PIN_BLOCKED; break;
- case SW_USE_CONDITIONS: ec = GPG_ERR_USE_CONDITIONS; break;
- case SW_NOT_SUPPORTED: ec = GPG_ERR_NOT_SUPPORTED; break;
- case SW_BAD_PARAMETER: ec = GPG_ERR_INV_VALUE; break;
- case SW_REF_NOT_FOUND: ec = GPG_ERR_NO_OBJ; break;
- case SW_BAD_P0_P1: ec = GPG_ERR_INV_VALUE; break;
- case SW_INS_NOT_SUP: ec = GPG_ERR_CARD; break;
- case SW_CLA_NOT_SUP: ec = GPG_ERR_CARD; break;
- case SW_SUCCESS: ec = 0; break;
-
- case SW_HOST_OUT_OF_CORE: ec = GPG_ERR_ENOMEM; break;
- case SW_HOST_INV_VALUE: ec = GPG_ERR_INV_VALUE; break;
- case SW_HOST_INCOMPLETE_CARD_RESPONSE: ec = GPG_ERR_CARD; break;
- default:
- if ((sw & 0x010000))
- ec = GPG_ERR_GENERAL; /* Should not happen. */
- else if ((sw & 0xff00) == SW_MORE_DATA)
- ec = 0; /* This should actually never been seen here. */
- else
- ec = GPG_ERR_CARD;
- }
- return gpg_error (ec);
-}
-
-/* This function is specialized version of the SELECT FILE command.
- SLOT is the card and reader as created for example by
- apdu_open_reader (), AID is a buffer of size AIDLEN holding the
- requested application ID. The function can't be used to enumerate
- AIDs and won't return the AID on success. The return value is 0
- for okay or GNUPG error code. Note that ISO error codes are
- internally mapped. */
-gpg_error_t
-iso7816_select_application (int slot, const char *aid, size_t aidlen)
-{
- int sw;
-
- sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
- return map_sw (sw);
-}
-
-
-/* Perform a VERIFY command on SLOT using the card holder verification
- vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */
-gpg_error_t
-iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
-{
- int sw;
-
- sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
- return map_sw (sw);
-}
-
-/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
- verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
- 0), a "change reference data" is done, otherwise an "exchange
- reference data". The new reference data is expected in NEWCHV of
- length NEWCHVLEN. */
-gpg_error_t
-iso7816_change_reference_data (int slot, int chvno,
- const char *oldchv, size_t oldchvlen,
- const char *newchv, size_t newchvlen)
-{
- int sw;
- char *buf;
-
- if ((!oldchv && oldchvlen)
- || (oldchv && !oldchvlen)
- || !newchv || !newchvlen )
- return gpg_error (GPG_ERR_INV_VALUE);
-
- buf = xtrymalloc (oldchvlen + newchvlen);
- if (!buf)
- return out_of_core ();
- if (oldchvlen)
- memcpy (buf, oldchv, oldchvlen);
- memcpy (buf+oldchvlen, newchv, newchvlen);
-
- sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
- oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
- xfree (buf);
- return map_sw (sw);
-
-}
-
-gpg_error_t
-iso7816_reset_retry_counter (int slot, int chvno,
- const char *newchv, size_t newchvlen)
-{
- int sw;
-
- if (!newchv || !newchvlen )
- return gpg_error (GPG_ERR_INV_VALUE);
-
- sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
- 2, chvno, newchvlen, newchv);
- return map_sw (sw);
-}
-
-
-/* Perform a GET DATA command requesting TAG and storing the result in
- a newly allocated buffer at the address passed by RESULT. Return
- the length of this data at the address of RESULTLEN. */
-gpg_error_t
-iso7816_get_data (int slot, int tag,
- unsigned char **result, size_t *resultlen)
-{
- int sw;
-
- if (!result || !resultlen)
- return gpg_error (GPG_ERR_INV_VALUE);
- *result = NULL;
- *resultlen = 0;
-
- sw = apdu_send (slot, 0x00, CMD_GET_DATA,
- ((tag >> 8) & 0xff), (tag & 0xff), -1, NULL,
- result, resultlen);
- if (sw != SW_SUCCESS)
- {
- /* Make sure that pending buffers are released. */
- xfree (*result);
- *result = NULL;
- *resultlen = 0;
- return map_sw (sw);
- }
-
- return 0;
-}
-
-
-/* Perform a PUT DATA command on card in SLOT. Write DATA of length
- DATALEN to TAG. */
-gpg_error_t
-iso7816_put_data (int slot, int tag,
- const unsigned char *data, size_t datalen)
-{
- int sw;
-
- sw = apdu_send_simple (slot, 0x00, CMD_PUT_DATA,
- ((tag >> 8) & 0xff), (tag & 0xff),
- datalen, data);
- return map_sw (sw);
-}
-
-
-/* Perform the security operation COMPUTE DIGITAL SIGANTURE. On
- success 0 is returned and the data is availavle in a newly
- allocated buffer stored at RESULT with its length stored at
- RESULTLEN. */
-gpg_error_t
-iso7816_compute_ds (int slot, const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen)
-{
- int sw;
-
- if (!data || !datalen || !result || !resultlen)
- return gpg_error (GPG_ERR_INV_VALUE);
- *result = NULL;
- *resultlen = 0;
-
- sw = apdu_send (slot, 0x00, CMD_PSO, 0x9E, 0x9A, datalen, data,
- result, resultlen);
- if (sw != SW_SUCCESS)
- {
- /* Make sure that pending buffers are released. */
- xfree (*result);
- *result = NULL;
- *resultlen = 0;
- return map_sw (sw);
- }
-
- return 0;
-}
-
-
-/* Perform the security operation DECIPHER. On
- success 0 is returned and the plaintext is available in a newly
- allocated buffer stored at RESULT with its length stored at
- RESULTLEN. */
-gpg_error_t
-iso7816_decipher (int slot, const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen)
-{
- int sw;
- unsigned char *buf;
-
- if (!data || !datalen || !result || !resultlen)
- return gpg_error (GPG_ERR_INV_VALUE);
- *result = NULL;
- *resultlen = 0;
-
- /* We need to prepend the padding indicator. */
- buf = xtrymalloc (datalen + 1);
- if (!buf)
- return out_of_core ();
- *buf = 0; /* Padding indicator. */
- memcpy (buf+1, data, datalen);
- sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf,
- result, resultlen);
- xfree (buf);
- if (sw != SW_SUCCESS)
- {
- /* Make sure that pending buffers are released. */
- xfree (*result);
- *result = NULL;
- *resultlen = 0;
- return map_sw (sw);
- }
-
- return 0;
-}
-
-
-gpg_error_t
-iso7816_internal_authenticate (int slot,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen)
-{
- int sw;
-
- if (!data || !datalen || !result || !resultlen)
- return gpg_error (GPG_ERR_INV_VALUE);
- *result = NULL;
- *resultlen = 0;
-
- sw = apdu_send (slot, 0x00, CMD_INTERNAL_AUTHENTICATE, 0, 0,
- datalen, data, result, resultlen);
- if (sw != SW_SUCCESS)
- {
- /* Make sure that pending buffers are released. */
- xfree (*result);
- *result = NULL;
- *resultlen = 0;
- return map_sw (sw);
- }
-
- return 0;
-}
-
-
-static gpg_error_t
-generate_keypair (int slot, int readonly,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen)
-{
- int sw;
-
- if (!data || !datalen || !result || !resultlen)
- return gpg_error (GPG_ERR_INV_VALUE);
- *result = NULL;
- *resultlen = 0;
-
- sw = apdu_send (slot, 0x00, CMD_GENERATE_KEYPAIR, readonly? 0x81:0x80, 0,
- datalen, data, result, resultlen);
- if (sw != SW_SUCCESS)
- {
- /* Make sure that pending buffers are released. */
- xfree (*result);
- *result = NULL;
- *resultlen = 0;
- return map_sw (sw);
- }
-
- return 0;
-}
-
-
-gpg_error_t
-iso7816_generate_keypair (int slot,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen)
-{
- return generate_keypair (slot, 0, data, datalen, result, resultlen);
-}
-
-
-gpg_error_t
-iso7816_read_public_key (int slot,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen)
-{
- return generate_keypair (slot, 1, data, datalen, result, resultlen);
-}
-
-
-
-gpg_error_t
-iso7816_get_challenge (int slot, int length, unsigned char *buffer)
-{
- int sw;
- unsigned char *result;
- size_t resultlen, n;
-
- if (!buffer || length < 1)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- do
- {
- result = NULL;
- n = length > 254? 254 : length;
- sw = apdu_send_le (slot, 0x00, CMD_GET_CHALLENGE, 0, 0, -1, NULL,
- n,
- &result, &resultlen);
- if (sw != SW_SUCCESS)
- {
- /* Make sure that pending buffers are released. */
- xfree (result);
- return map_sw (sw);
- }
- if (resultlen > n)
- resultlen = n;
- memcpy (buffer, result, resultlen);
- buffer += resultlen;
- length -= resultlen;
- xfree (result);
- }
- while (length > 0);
-
- return 0;
-}
diff --git a/scd/iso7816.h b/scd/iso7816.h
deleted file mode 100644
index d7e77a101..000000000
--- a/scd/iso7816.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/* iso7816.h - ISO 7816 commands
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef ISO7816_H
-#define ISO7816_H
-
-gpg_error_t iso7816_select_application (int slot,
- const char *aid, size_t aidlen);
-gpg_error_t iso7816_verify (int slot,
- int chvno, const char *chv, size_t chvlen);
-gpg_error_t iso7816_change_reference_data (int slot, int chvno,
- const char *oldchv, size_t oldchvlen,
- const char *newchv, size_t newchvlen);
-gpg_error_t iso7816_reset_retry_counter (int slot, int chvno,
- const char *newchv, size_t newchvlen);
-gpg_error_t iso7816_get_data (int slot, int tag,
- unsigned char **result, size_t *resultlen);
-gpg_error_t iso7816_put_data (int slot, int tag,
- const unsigned char *data, size_t datalen);
-gpg_error_t iso7816_compute_ds (int slot,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen);
-gpg_error_t iso7816_decipher (int slot,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen);
-gpg_error_t iso7816_internal_authenticate (int slot,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen);
-gpg_error_t iso7816_generate_keypair (int slot,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen);
-gpg_error_t iso7816_read_public_key (int slot,
- const unsigned char *data, size_t datalen,
- unsigned char **result, size_t *resultlen);
-gpg_error_t iso7816_get_challenge (int slot,
- int length, unsigned char *buffer);
-
-
-#endif /*ISO7816_H*/
diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c
deleted file mode 100644
index 9caf39a8a..000000000
--- a/scd/sc-copykeys.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/* sc-copykeys.c - A tool to store keys on a smartcard.
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#define JNLIB_NEED_LOG_LOGV
-#include "scdaemon.h"
-#include <gcrypt.h>
-
-#include "../common/ttyio.h"
-#include "../common/simple-pwquery.h"
-#include "apdu.h" /* for open_reader */
-#include "atr.h"
-#include "app-common.h"
-
-#define _(a) (a)
-
-
-enum cmd_and_opt_values
-{ oVerbose = 'v',
- oReaderPort = 500,
- oDebug,
- oDebugAll,
-
-aTest };
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 301, NULL, 0, "@Options:\n " },
-
- { oVerbose, "verbose", 0, "verbose" },
- { oReaderPort, "reader-port", 1, "|N|connect to reader at port N"},
- { oDebug, "debug" ,4|16, "set debugging flags"},
- { oDebugAll, "debug-all" ,0, "enable full debugging"},
- {0}
-};
-
-
-static void copykeys (APP app, const char *fname);
-
-
-static const char *
-my_strusage (int level)
-{
- const char *p;
- switch (level)
- {
- case 11: p = "sc-copykeys (GnuPG)";
- break;
- case 13: p = VERSION; break;
- case 17: p = PRINTABLE_OS_NAME; break;
- case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
- break;
- case 1:
- case 40: p = _("Usage: sc-copykeys [options] (-h for help)\n");
- break;
- case 41: p = _("Syntax: sc-copykeys [options] "
- "file-with-key\n"
- "Copy keys to a smartcards\n");
- break;
-
- default: p = NULL;
- }
- return p;
-}
-
-/* Used by gcry for logging */
-static void
-my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
-{
- /* translate the log levels */
- switch (level)
- {
- case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
- case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
- case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
- case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
- case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
- case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
- case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
- default: level = JNLIB_LOG_ERROR; break;
- }
- log_logv (level, fmt, arg_ptr);
-}
-
-
-int
-main (int argc, char **argv )
-{
- ARGPARSE_ARGS pargs;
- int slot, rc;
- int reader_port = 32768; /* First USB reader. */
- struct app_ctx_s appbuf;
-
- memset (&appbuf, 0, sizeof appbuf);
-
- set_strusage (my_strusage);
- gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
- log_set_prefix ("sc-copykeys", 1);
-
- /* check that the libraries are suitable. Do it here because
- the option parsing may need services of the library */
- if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
- {
- log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
- NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
- }
-
- gcry_set_log_handler (my_gcry_logger, NULL);
- gcry_control (GCRYCTL_DISABLE_SECMEM, 0); /* FIXME - we want to use it */
- /* FIXME? gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);*/
-
- pargs.argc = &argc;
- pargs.argv = &argv;
- pargs.flags= 1; /* do not remove the args */
- while (arg_parse (&pargs, opts) )
- {
- switch (pargs.r_opt)
- {
- case oVerbose: opt.verbose++; break;
- case oDebug: opt.debug |= pargs.r.ret_ulong; break;
- case oDebugAll: opt.debug = ~0; break;
- default : pargs.err = 2; break;
- }
- }
- if (log_get_errorcount(0))
- exit(2);
-
- if (argc != 1)
- usage (1);
-
- slot = apdu_open_reader (reader_port);
- if (slot == -1)
- exit (1);
-
- /* FIXME: Use select_application. */
- appbuf.slot = slot;
- rc = app_select_openpgp (&appbuf, &appbuf.serialno, &appbuf.serialnolen);
- if (rc)
- {
- log_error ("selecting openpgp failed: %s\n", gpg_strerror (rc));
- exit (1);
- }
- appbuf.initialized = 1;
- log_info ("openpgp application selected\n");
-
- copykeys (&appbuf, *argv);
-
-
- return 0;
-}
-
-
-
-void
-send_status_info (CTRL ctrl, const char *keyword, ...)
-{
- /* DUMMY */
-}
-
-
-
-static char *
-read_file (const char *fname, size_t *r_length)
-{
- FILE *fp;
- struct stat st;
- char *buf;
- size_t buflen;
-
- fp = fname? fopen (fname, "rb") : stdin;
- if (!fp)
- {
- log_error ("can't open `%s': %s\n",
- fname? fname: "[stdin]", strerror (errno));
- return NULL;
- }
-
- if (fstat (fileno(fp), &st))
- {
- log_error ("can't stat `%s': %s\n",
- fname? fname: "[stdin]", strerror (errno));
- if (fname)
- fclose (fp);
- return NULL;
- }
-
- buflen = st.st_size;
- buf = xmalloc (buflen+1);
- if (fread (buf, buflen, 1, fp) != 1)
- {
- log_error ("error reading `%s': %s\n",
- fname? fname: "[stdin]", strerror (errno));
- if (fname)
- fclose (fp);
- xfree (buf);
- return NULL;
- }
- if (fname)
- fclose (fp);
-
- *r_length = buflen;
- return buf;
-}
-
-
-static gcry_sexp_t
-read_key (const char *fname)
-{
- char *buf;
- size_t buflen;
- gcry_sexp_t private;
- int rc;
-
- buf = read_file (fname, &buflen);
- if (!buf)
- return NULL;
-
- rc = gcry_sexp_new (&private, buf, buflen, 1);
- if (rc)
- {
- log_error ("gcry_sexp_new failed: %s\n", gpg_strerror (rc));
- return NULL;
- }
- xfree (buf);
-
- return private;
-}
-
-
-
-static gcry_mpi_t *
-sexp_to_kparms (gcry_sexp_t sexp, unsigned long *created)
-{
- gcry_sexp_t list, l2;
- const char *name;
- const char *s;
- size_t n;
- int i, idx;
- const char *elems;
- gcry_mpi_t *array;
-
- *created = 0;
- list = gcry_sexp_find_token (sexp, "private-key", 0 );
- if(!list)
- return NULL;
-
- /* quick hack to get the creation time. */
- l2 = gcry_sexp_find_token (list, "created", 0);
- if (l2 && (name = gcry_sexp_nth_data (l2, 1, &n)))
- {
- char *tmp = xmalloc (n+1);
- memcpy (tmp, name, n);
- tmp[n] = 0;
- *created = strtoul (tmp, NULL, 10);
- xfree (tmp);
- }
- gcry_sexp_release (l2);
- l2 = gcry_sexp_cadr (list);
- gcry_sexp_release (list);
- list = l2;
- name = gcry_sexp_nth_data (list, 0, &n);
- if(!name || n != 3 || memcmp (name, "rsa", 3))
- {
- gcry_sexp_release (list);
- return NULL;
- }
-
- /* Parameter names used with RSA. */
- elems = "nedpqu";
- array = xcalloc (strlen(elems) + 1, sizeof *array);
- for (idx=0, s=elems; *s; s++, idx++ )
- {
- l2 = gcry_sexp_find_token (list, s, 1);
- if (!l2)
- {
- for (i=0; i<idx; i++)
- gcry_mpi_release (array[i]);
- xfree (array);
- gcry_sexp_release (list);
- return NULL; /* required parameter not found */
- }
- array[idx] = gcry_sexp_nth_mpi (l2, 1, GCRYMPI_FMT_USG);
- gcry_sexp_release (l2);
- if (!array[idx])
- {
- for (i=0; i<idx; i++)
- gcry_mpi_release (array[i]);
- xfree (array);
- gcry_sexp_release (list);
- return NULL; /* required parameter is invalid */
- }
- }
-
- gcry_sexp_release (list);
- return array;
-}
-
-
-/* Return true if the SHA1 fingerprint FPR consists only of zeroes. */
-static int
-fpr_is_zero (const char *fpr)
-{
- int i;
-
- for (i=0; i < 20 && !fpr[i]; i++)
- ;
- return (i == 20);
-}
-
-
-static void
-show_sha1_fpr (const unsigned char *fpr)
-{
- int i;
-
- if (fpr)
- {
- for (i=0; i < 20 ; i+=2, fpr += 2 )
- {
- if (i == 10 )
- tty_printf (" ");
- tty_printf (" %02X%02X", *fpr, fpr[1]);
- }
- }
- else
- tty_printf (" [none]");
- tty_printf ("\n");
-}
-
-/* Query the card, show a list of already stored keys and ask the user
- where to store the key. Returns the key number or 0 for cancel
- operation. */
-static int
-query_card (APP app)
-{
- int keyno = 0;
- char *serialno, *disp_name, *pubkey_url;
- unsigned char *fpr1, *fpr2, *fpr3;
-
-
- if (app_openpgp_cardinfo (app,
- &serialno,
- &disp_name,
- &pubkey_url,
- &fpr1, &fpr2, &fpr3))
- return 0;
-
-
- for (;;)
- {
- char *answer;
-
- tty_printf ("\n");
-
- tty_printf ("Serial number ....: %s\n",
- serialno? serialno : "[none]");
- tty_printf ("Name of cardholder: %s\n",
- disp_name && *disp_name? disp_name : "[not set]");
- tty_printf ("URL of public key : %s\n",
- pubkey_url && *pubkey_url? pubkey_url : "[not set]");
- tty_printf ("Signature key ....:");
- show_sha1_fpr (fpr1);
- tty_printf ("Encryption key....:");
- show_sha1_fpr (fpr2);
- tty_printf ("Authentication key:");
- show_sha1_fpr (fpr3);
-
- tty_printf ("\n"
- "1 - store as signature key and reset usage counter\n"
- "2 - store as encryption key\n"
- "3 - store as authentication key\n"
- "Q - quit\n"
- "\n");
-
- answer = tty_get("Your selection? ");
- tty_kill_prompt();
- if (strlen (answer) != 1)
- ;
- else if ( *answer == '1' )
- {
- if ( (fpr1 && !fpr_is_zero (fpr1)) )
- {
- tty_printf ("\n");
- log_error ("WARNING: signature key does already exists!\n");
- tty_printf ("\n");
- if ( tty_get_answer_is_yes ("Replace existing key? ") )
- {
- keyno = 1;
- break;
- }
- }
- else
- {
- keyno = 1;
- break;
- }
- }
- else if ( *answer == '2' )
- {
- if ( (fpr2 && !fpr_is_zero (fpr2)) )
- {
- tty_printf ("\n");
- log_error ("WARNING: encryption key does already exists!\n");
- tty_printf ("\n");
- if ( tty_get_answer_is_yes ("Replace existing key? ") )
- {
- keyno = 2;
- break;
- }
- }
- else
- {
- keyno = 2;
- break;
- }
- }
- else if ( *answer == '3' )
- {
- if ( (fpr3 && !fpr_is_zero (fpr3)) )
- {
- tty_printf ("\n");
- log_error ("WARNING: authentication key does already exists!\n");
- tty_printf ("\n");
- if ( tty_get_answer_is_yes ("Replace existing key? ") )
- {
- keyno = 3;
- break;
- }
- }
- else
- {
- keyno = 3;
- break;
- }
- }
- else if ( *answer == 'q' || *answer == 'Q')
- {
- keyno = 0;
- break;
- }
- }
-
- xfree (serialno);
- xfree (disp_name);
- xfree (pubkey_url);
- xfree (fpr1);
- xfree (fpr2);
- xfree (fpr3);
-
- return keyno;
-}
-
-
-/* Callback function to ask for a PIN. */
-static int
-pincb (void *arg, const char *prompt, char **pinvalue)
-{
- char *pin = xstrdup ("12345678");
-
-/* pin = simple_pwquery (NULL, NULL, prompt, */
-/* "We need the admin's PIN to store the key on the card", */
-/* NULL); */
-/* if (!pin) */
-/* return gpg_error (GPG_ERR_CANCELED); */
-
-
-
- *pinvalue = pin;
- return 0;
-}
-
-
-/* This function expects a file (or NULL for stdin) with the secret
- and public key parameters. This file should consist of an
- S-expression as used by gpg-agent. Only the unprotected format is
- supported. Example:
-
- (private-key
- (rsa
- (n #00e0ce9..[some bytes not shown]..51#)
- (e #010001#)
- (d #046129F..[some bytes not shown]..81#)
- (p #00e861b..[some bytes not shown]..f1#)
- (q #00f7a7c..[some bytes not shown]..61#)
- (u #304559a..[some bytes not shown]..9b#))
- (uri http://foo.bar x-foo:whatever_you_want))
-
-*/
-static void
-copykeys (APP app, const char *fname)
-{
- int rc;
- gcry_sexp_t private;
- gcry_mpi_t *mpis, rsa_n, rsa_e, rsa_p, rsa_q;
- unsigned int nbits;
- size_t n;
- unsigned char *template, *tp;
- unsigned char m[128], e[4];
- size_t mlen, elen;
- unsigned long creation_date;
- time_t created_at;
- int keyno;
-
- if (!strcmp (fname, "-"))
- fname = NULL;
-
- private = read_key (fname);
- if (!private)
- exit (1);
-
- mpis = sexp_to_kparms (private, &creation_date);
- if (!creation_date)
- {
- log_info ("no creation date found - assuming current date\n");
- created_at = time (NULL);
- }
- else
- created_at = creation_date;
- gcry_sexp_release (private);
- if (!mpis)
- {
- log_error ("invalid structure of key file or not RSA\n");
- exit (1);
- }
- /* MPIS is now an array with the key parameters as defined by OpenPGP. */
- rsa_n = mpis[0];
- rsa_e = mpis[1];
- gcry_mpi_release (mpis[2]);
- rsa_p = mpis[3];
- rsa_q = mpis[4];
- gcry_mpi_release (mpis[5]);
- xfree (mpis);
-
- nbits = gcry_mpi_get_nbits (rsa_e);
- if (nbits < 2 || nbits > 32)
- {
- log_error ("public exponent too large (more than 32 bits)\n");
- goto failure;
- }
- nbits = gcry_mpi_get_nbits (rsa_p);
- if (nbits != 512)
- {
- log_error ("length of first RSA prime is not 512\n");
- goto failure;
- }
- nbits = gcry_mpi_get_nbits (rsa_q);
- if (nbits != 512)
- {
- log_error ("length of second RSA prime is not 512\n");
- goto failure;
- }
-
- nbits = gcry_mpi_get_nbits (rsa_n);
- if (nbits != 1024)
- {
- log_error ("length of RSA modulus is not 1024\n");
- goto failure;
- }
-
- keyno = query_card (app);
- if (!keyno)
- goto failure;
-
- /* Build the private key template as described in section 4.3.3.6 of
- the specs.
- 0xC0 <length> public exponent
- 0xC1 <length> prime p
- 0xC2 <length> prime q */
- template = tp = xmalloc (1+2 + 1+1+4 + 1+1+64 + 1+1+64);
- *tp++ = 0xC0;
- *tp++ = 4;
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, tp, 4, &n, rsa_e);
- if (rc)
- {
- log_error ("mpi_print failed: %s\n", gpg_strerror (rc));
- goto failure;
- }
- assert (n <= 4);
- memcpy (e, tp, n);
- elen = n;
- if (n != 4)
- {
- memmove (tp+4-n, tp, 4-n);
- memset (tp, 0, 4-n);
- }
- tp += 4;
-
- *tp++ = 0xC1;
- *tp++ = 64;
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, tp, 64, &n, rsa_p);
- if (rc)
- {
- log_error ("mpi_print failed: %s\n", gpg_strerror (rc));
- goto failure;
- }
- assert (n == 64);
- tp += 64;
-
- *tp++ = 0xC2;
- *tp++ = 64;
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, tp, 64, &n, rsa_q);
- if (rc)
- {
- log_error ("mpi_print failed: %s\n", gpg_strerror (rc));
- goto failure;
- }
- assert (n == 64);
- tp += 64;
- assert (tp - template == 138);
-
- /* (we need the modulus to calculate the fingerprint) */
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, m, 128, &n, rsa_n);
- if (rc)
- {
- log_error ("mpi_print failed: %s\n", gpg_strerror (rc));
- goto failure;
- }
- assert (n == 128);
- mlen = 128;
-
-
- rc = app_openpgp_storekey (app, keyno,
- template, tp - template,
- created_at,
- m, mlen,
- e, elen,
- pincb, NULL);
-
- if (rc)
- {
- log_error ("error storing key: %s\n", gpg_strerror (rc));
- goto failure;
- }
- log_info ("key successfully stored\n");
- {
- unsigned char *mm, *ee;
- size_t mmlen, eelen;
- int i;
-
- rc = app_openpgp_readkey (app, keyno, &mm, &mmlen, &ee, &eelen);
- if (rc)
- {
- log_error ("error reading key back: %s\n", gpg_strerror (rc));
- goto failure;
- }
-
- /* Strip leading zeroes. */
- for (i=0; i < mmlen && !mm[i]; i++)
- ;
- mmlen -= i;
- memmove (mm, mm+i, mmlen);
- for (i=0; i < eelen && !ee[i]; i++)
- ;
- eelen -= i;
- memmove (ee, ee+i, eelen);
-
- if (eelen != elen || mmlen != mlen)
- {
- log_error ("key parameter length mismatch (n=%u/%u, e=%u/%u)\n",
- (unsigned int)mlen, (unsigned int)mmlen,
- (unsigned int)elen, (unsigned int)eelen);
- xfree (mm);
- xfree (ee);
- goto failure;
- }
-
- if (memcmp (m, mm, mlen))
- {
- log_error ("key parameter n mismatch\n");
- log_printhex ("original n: ", m, mlen);
- log_printhex (" copied n: ", mm, mlen);
- xfree (mm);
- xfree (ee);
- goto failure;
- }
- if (memcmp (e, ee, elen))
- {
- log_error ("key parameter e mismatch\n");
- log_printhex ("original e: ", e, elen);
- log_printhex (" copied e: ", ee, elen);
- xfree (mm);
- xfree (ee);
- goto failure;
- }
- xfree (mm);
- xfree (ee);
- }
-
-
- gcry_mpi_release (rsa_e);
- gcry_mpi_release (rsa_p);
- gcry_mpi_release (rsa_q);
- gcry_mpi_release (rsa_n);
- return;
-
- failure:
- gcry_mpi_release (rsa_e);
- gcry_mpi_release (rsa_p);
- gcry_mpi_release (rsa_q);
- gcry_mpi_release (rsa_n);
- exit (1);
-}
-
-
diff --git a/scd/sc-investigate.c b/scd/sc-investigate.c
deleted file mode 100644
index e8f0eb83c..000000000
--- a/scd/sc-investigate.c
+++ /dev/null
@@ -1,209 +0,0 @@
-/* sc-investigate.c - A tool to look around on smartcards.
- * Copyright (C) 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#define JNLIB_NEED_LOG_LOGV
-#include "scdaemon.h"
-#include <gcrypt.h>
-
-#include "apdu.h" /* for open_reader */
-#include "atr.h"
-#include "app-common.h"
-
-#define _(a) (a)
-
-
-enum cmd_and_opt_values
-{ oVerbose = 'v',
- oReaderPort = 500,
- oDebug,
- oDebugAll,
-
- oGenRandom,
-
-aTest };
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 301, NULL, 0, "@Options:\n " },
-
- { oVerbose, "verbose", 0, "verbose" },
- { oReaderPort, "reader-port", 1, "|N|connect to reader at port N"},
- { oDebug, "debug" ,4|16, "set debugging flags"},
- { oDebugAll, "debug-all" ,0, "enable full debugging"},
- { oGenRandom, "gen-random", 4, "|N|generate N bytes of random"},
- {0}
-};
-
-static const char *
-my_strusage (int level)
-{
- const char *p;
- switch (level)
- {
- case 11: p = "sc-investigate (GnuPG)";
- break;
- case 13: p = VERSION; break;
- case 17: p = PRINTABLE_OS_NAME; break;
- case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
- break;
- case 1:
- case 40: p = _("Usage: sc-investigate [options] (-h for help)\n");
- break;
- case 41: p = _("Syntax: sc-investigate [options] [args]]\n"
- "Have a look at smartcards\n");
- break;
-
- default: p = NULL;
- }
- return p;
-}
-
-/* Used by gcry for logging */
-static void
-my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
-{
- /* translate the log levels */
- switch (level)
- {
- case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
- case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
- case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
- case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
- case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
- case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
- case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
- default: level = JNLIB_LOG_ERROR; break;
- }
- log_logv (level, fmt, arg_ptr);
-}
-
-
-int
-main (int argc, char **argv )
-{
- ARGPARSE_ARGS pargs;
- int slot, rc;
- int reader_port = 32768; /* First USB reader. */
- struct app_ctx_s appbuf;
- unsigned long gen_random = 0;
-
- memset (&appbuf, 0, sizeof appbuf);
-
- set_strusage (my_strusage);
- gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
- log_set_prefix ("sc-investigate", 1);
-
- /* check that the libraries are suitable. Do it here because
- the option parsing may need services of the library */
- if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
- {
- log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
- NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
- }
-
- gcry_set_log_handler (my_gcry_logger, NULL);
- /* FIXME? gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);*/
-
- pargs.argc = &argc;
- pargs.argv = &argv;
- pargs.flags= 1; /* do not remove the args */
- while (arg_parse (&pargs, opts) )
- {
- switch (pargs.r_opt)
- {
- case oVerbose: opt.verbose++; break;
- case oDebug: opt.debug |= pargs.r.ret_ulong; break;
- case oDebugAll: opt.debug = ~0; break;
- case oGenRandom: gen_random = pargs.r.ret_ulong; break;
- default : pargs.err = 2; break;
- }
- }
- if (log_get_errorcount(0))
- exit(2);
-
- if (opt.verbose < 2)
- opt.verbose = 2; /* hack to let select_openpgp print some info. */
-
- if (argc)
- usage (1);
-
- slot = apdu_open_reader (reader_port);
- if (slot == -1)
- exit (1);
-
- if (!gen_random)
- {
- rc = atr_dump (slot, stdout);
- if (rc)
- log_error ("can't dump ATR: %s\n", gpg_strerror (rc));
- }
-
- appbuf.slot = slot;
- rc = app_select_openpgp (&appbuf, NULL, NULL);
- if (rc)
- log_error ("selecting openpgp failed: %s\n", gpg_strerror (rc));
- else
- {
- appbuf.initialized = 1;
- log_info ("openpgp application selected\n");
-
- if (gen_random)
- {
- size_t nbytes;
- unsigned char *buffer;
-
- buffer = xmalloc (4096);
- do
- {
- nbytes = gen_random > 4096? 4096 : gen_random;
- rc = app_get_challenge (&appbuf, nbytes, buffer);
- if (rc)
- log_error ("app_get_challenge failed: %s\n",gpg_strerror (rc));
- else
- {
- if (fwrite (buffer, nbytes, 1, stdout) != 1)
- log_error ("writing to stdout failed: %s\n",
- strerror (errno));
- gen_random -= nbytes;
- }
- }
- while (gen_random && !log_get_errorcount (0));
- xfree (buffer);
- }
- }
-
- return log_get_errorcount (0)? 2:0;
-}
-
-
-
-void
-send_status_info (CTRL ctrl, const char *keyword, ...)
-{
- /* DUMMY */
-}
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
deleted file mode 100644
index 8e0ef37c9..000000000
--- a/scd/scdaemon.c
+++ /dev/null
@@ -1,638 +0,0 @@
-/* scdaemon.c - The GnuPG Smartcard Daemon
- * Copyright (C) 2001, 2002 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdarg.h>
-#include <string.h>
-#include <errno.h>
-#include <assert.h>
-#include <time.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <signal.h>
-
-#define JNLIB_NEED_LOG_LOGV
-#include "scdaemon.h"
-#include <ksba.h>
-#include <gcrypt.h>
-
-#include <assuan.h> /* malloc hooks */
-
-#include "i18n.h"
-#include "sysutils.h"
-
-
-
-enum cmd_and_opt_values
-{ aNull = 0,
- oCsh = 'c',
- oQuiet = 'q',
- oSh = 's',
- oVerbose = 'v',
-
- oNoVerbose = 500,
- oOptions,
- oDebug,
- oDebugAll,
- oDebugWait,
- oDebugSC,
- oNoGreeting,
- oNoOptions,
- oHomedir,
- oNoDetach,
- oNoGrab,
- oLogFile,
- oServer,
- oDaemon,
- oBatch,
- oReaderPort,
-
-aTest };
-
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 301, NULL, 0, N_("@Options:\n ") },
-
- { oServer, "server", 0, N_("run in server mode (foreground)") },
- { oDaemon, "daemon", 0, N_("run in daemon mode (background)") },
- { oVerbose, "verbose", 0, N_("verbose") },
- { oQuiet, "quiet", 0, N_("be somewhat more quiet") },
- { oSh, "sh", 0, N_("sh-style command output") },
- { oCsh, "csh", 0, N_("csh-style command output") },
- { oOptions, "options" , 2, N_("read options from file")},
- { oDebug, "debug" ,4|16, N_("set debugging flags")},
- { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
- { oDebugWait,"debug-wait",1, "@"},
- { oDebugSC, "debug-sc", 1, N_("|N|set OpenSC debug level to N")},
- { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
- { oLogFile, "log-file" ,2, N_("use a log file for the server")},
- { oReaderPort, "reader-port", 1, N_("|N|connect to reader at port N")},
-
- {0}
-};
-
-
-static volatile int caught_fatal_sig = 0;
-
-/* It is possible that we are currently running under setuid permissions */
-static int maybe_setuid = 1;
-
-/* Name of the communication socket */
-static char socket_name[128];
-
-static const char *
-my_strusage (int level)
-{
- const char *p;
- switch (level)
- {
- case 11: p = "scdaemon (GnuPG)";
- break;
- case 13: p = VERSION; break;
- case 17: p = PRINTABLE_OS_NAME; break;
- case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
- break;
- case 1:
- case 40: p = _("Usage: scdaemon [options] (-h for help)");
- break;
- case 41: p = _("Syntax: scdaemon [options] [command [args]]\n"
- "Smartcard daemon for GnuPG\n");
- break;
-
- default: p = NULL;
- }
- return p;
-}
-
-
-
-static void
-i18n_init (void)
-{
-#ifdef USE_SIMPLE_GETTEXT
- set_gettext_file( PACKAGE );
-#else
-#ifdef ENABLE_NLS
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
-#endif
-#endif
-}
-
-
-
-/* Used by gcry for logging */
-static void
-my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr)
-{
- /* translate the log levels */
- switch (level)
- {
- case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break;
- case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break;
- case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break;
- case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break;
- case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break;
- case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break;
- case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break;
- default: level = JNLIB_LOG_ERROR; break;
- }
- log_logv (level, fmt, arg_ptr);
-}
-
-
-static void
-cleanup (void)
-{
- if (*socket_name)
- {
- char *p;
-
- remove (socket_name);
- p = strrchr (socket_name, '/');
- if (p)
- {
- *p = 0;
- rmdir (socket_name);
- *p = '/';
- }
- *socket_name = 0;
- }
-}
-
-
-static RETSIGTYPE
-cleanup_sh (int sig)
-{
- if (caught_fatal_sig)
- raise (sig);
- caught_fatal_sig = 1;
-
- /* gcry_control( GCRYCTL_TERM_SECMEM );*/
- cleanup ();
-
-#ifndef HAVE_DOSISH_SYSTEM
- { /* reset action to default action and raise signal again */
- struct sigaction nact;
- nact.sa_handler = SIG_DFL;
- sigemptyset( &nact.sa_mask );
- nact.sa_flags = 0;
- sigaction( sig, &nact, NULL);
- }
-#endif
- raise( sig );
-}
-
-int
-main (int argc, char **argv )
-{
- ARGPARSE_ARGS pargs;
- int orig_argc;
- int may_coredump;
- char **orig_argv;
- FILE *configfp = NULL;
- char *configname = NULL;
- const char *shell;
- unsigned configlineno;
- int parse_debug = 0;
- int default_config =1;
- int greeting = 0;
- int nogreeting = 0;
- int pipe_server = 0;
- int is_daemon = 0;
- int nodetach = 0;
- int csh_style = 0;
- char *logfile = NULL;
- int debug_wait = 0;
- int reader_port = 32768; /* First USB reader. */
-
- set_strusage (my_strusage);
- gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
- /* Please note that we may running SUID(ROOT), so be very CAREFUL
- when adding any stuff between here and the call to INIT_SECMEM()
- somewhere after the option parsing */
- log_set_prefix ("scdaemon", 1|4);
- i18n_init ();
-
- /* check that the libraries are suitable. Do it here because
- the option parsing may need services of the library */
- if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
- {
- log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
- NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
- }
-
- ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
- assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
- gcry_set_log_handler (my_gcry_logger, NULL);
- gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
-
- may_coredump = disable_core_dumps ();
-
- shell = getenv ("SHELL");
- if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
- csh_style = 1;
-
- /* FIXME: Using this homedir option does only make sense when not
- running as a system service. We might want to check for this by
- looking at the uid or ebtter use an explict option for this */
- opt.homedir = getenv("GNUPGHOME");
- if (!opt.homedir || !*opt.homedir)
- opt.homedir = GNUPG_DEFAULT_HOMEDIR;
-
- /* check whether we have a config file on the commandline */
- orig_argc = argc;
- orig_argv = argv;
- pargs.argc = &argc;
- pargs.argv = &argv;
- pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */
- while (arg_parse( &pargs, opts))
- {
- if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
- parse_debug++;
- else if (pargs.r_opt == oOptions)
- { /* yes there is one, so we do not try the default one, but
- read the option file when it is encountered at the
- commandline */
- default_config = 0;
- }
- else if (pargs.r_opt == oNoOptions)
- default_config = 0; /* --no-options */
- else if (pargs.r_opt == oHomedir)
- opt.homedir = pargs.r.ret_str;
- }
-
- /* initialize the secure memory. */
- gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
- maybe_setuid = 0;
-
- /*
- Now we are working under our real uid
- */
-
-
- if (default_config)
- configname = make_filename (opt.homedir, "scdaemon.conf", NULL );
-
- argc = orig_argc;
- argv = orig_argv;
- pargs.argc = &argc;
- pargs.argv = &argv;
- pargs.flags= 1; /* do not remove the args */
- next_pass:
- if (configname)
- {
- configlineno = 0;
- configfp = fopen (configname, "r");
- if (!configfp)
- {
- if (default_config)
- {
- if( parse_debug )
- log_info (_("NOTE: no default option file `%s'\n"),
- configname );
- }
- else
- {
- log_error (_("option file `%s': %s\n"),
- configname, strerror(errno) );
- exit(2);
- }
- xfree (configname);
- configname = NULL;
- }
- if (parse_debug && configname )
- log_info (_("reading options from `%s'\n"), configname );
- default_config = 0;
- }
-
- while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
- {
- switch (pargs.r_opt)
- {
- case oQuiet: opt.quiet = 1; break;
- case oVerbose: opt.verbose++; break;
- case oBatch: opt.batch=1; break;
-
- case oDebug: opt.debug |= pargs.r.ret_ulong; break;
- case oDebugAll: opt.debug = ~0; break;
- case oDebugWait: debug_wait = pargs.r.ret_int; break;
- case oDebugSC: opt.debug_sc = pargs.r.ret_int; break;
-
- case oOptions:
- /* config files may not be nested (silently ignore them) */
- if (!configfp)
- {
- xfree(configname);
- configname = xstrdup(pargs.r.ret_str);
- goto next_pass;
- }
- break;
- case oNoGreeting: nogreeting = 1; break;
- case oNoVerbose: opt.verbose = 0; break;
- case oNoOptions: break; /* no-options */
- case oHomedir: opt.homedir = pargs.r.ret_str; break;
- case oNoDetach: nodetach = 1; break;
- case oLogFile: logfile = pargs.r.ret_str; break;
- case oCsh: csh_style = 1; break;
- case oSh: csh_style = 0; break;
- case oServer: pipe_server = 1; break;
- case oDaemon: is_daemon = 1; break;
-
- case oReaderPort: reader_port = pargs.r.ret_int; break;
-
- default : pargs.err = configfp? 1:2; break;
- }
- }
- if (configfp)
- {
- fclose( configfp );
- configfp = NULL;
- xfree(configname);
- configname = NULL;
- goto next_pass;
- }
- xfree (configname);
- configname = NULL;
- if (log_get_errorcount(0))
- exit(2);
- if (nogreeting )
- greeting = 0;
-
- if (greeting)
- {
- fprintf (stderr, "%s %s; %s\n",
- strusage(11), strusage(13), strusage(14) );
- fprintf (stderr, "%s\n", strusage(15) );
- }
-#ifdef IS_DEVELOPMENT_VERSION
- log_info ("NOTE: this is a development version!\n");
-#endif
-
-
- if (atexit (cleanup))
- {
- log_error ("atexit failed\n");
- cleanup ();
- exit (1);
- }
-
-
- if (debug_wait && pipe_server)
- {
- log_debug ("waiting for debugger - my pid is %u .....\n",
- (unsigned int)getpid());
- sleep (debug_wait);
- log_debug ("... okay\n");
- }
-
- /* now start with logging to a file if this is desired */
- if (logfile)
- {
- log_set_file (logfile);
- log_set_prefix (NULL, 1|2|4);
- }
-
-
- if (pipe_server)
- { /* this is the simple pipe based server */
- scd_command_handler (-1);
- }
- else if (!is_daemon)
- {
- log_info (_("please use the option `--daemon'"
- " to run the program in the background\n"));
- }
- else
- { /* regular server mode */
- int fd;
- pid_t pid;
- int i;
- int len;
- struct sockaddr_un serv_addr;
- char *p;
-
- /* fixme: if there is already a running gpg-agent we should
- share the same directory - and vice versa */
- *socket_name = 0;
- snprintf (socket_name, DIM(socket_name)-1,
- "/tmp/gpg-XXXXXX/S.scdaemon");
- socket_name[DIM(socket_name)-1] = 0;
- p = strrchr (socket_name, '/');
- if (!p)
- BUG ();
- *p = 0;;
- if (!mkdtemp(socket_name))
- {
- log_error ("can't create directory `%s': %s\n",
- socket_name, strerror(errno) );
- exit (1);
- }
- *p = '/';
-
- if (strchr (socket_name, ':') )
- {
- log_error ("colons are not allowed in the socket name\n");
- exit (1);
- }
- if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
- {
- log_error ("name of socket to long\n");
- exit (1);
- }
-
-
- fd = socket (AF_UNIX, SOCK_STREAM, 0);
- if (fd == -1)
- {
- log_error ("can't create socket: %s\n", strerror(errno) );
- exit (1);
- }
-
- memset (&serv_addr, 0, sizeof serv_addr);
- serv_addr.sun_family = AF_UNIX;
- strcpy (serv_addr.sun_path, socket_name);
- len = (offsetof (struct sockaddr_un, sun_path)
- + strlen(serv_addr.sun_path) + 1);
-
- if (bind (fd, (struct sockaddr*)&serv_addr, len) == -1)
- {
- log_error ("error binding socket to `%s': %s\n",
- serv_addr.sun_path, strerror (errno) );
- close (fd);
- exit (1);
- }
-
- if (listen (fd, 5 ) == -1)
- {
- log_error ("listen() failed: %s\n", strerror (errno));
- close (fd);
- exit (1);
- }
-
- if (opt.verbose)
- log_info ("listening on socket `%s'\n", socket_name );
-
-
- fflush (NULL);
- pid = fork ();
- if (pid == (pid_t)-1)
- {
- log_fatal ("fork failed: %s\n", strerror (errno) );
- exit (1);
- }
- else if (pid)
- { /* we are the parent */
- char *infostr;
-
- close (fd);
-
- /* create the info string: <name>:<pid>:<protocol_version> */
- if (asprintf (&infostr, "SCDAEMON_INFO=%s:%lu:1",
- socket_name, (ulong)pid ) < 0)
- {
- log_error ("out of core\n");
- kill (pid, SIGTERM);
- exit (1);
- }
- *socket_name = 0; /* don't let cleanup() remove the socket -
- the child should do this from now on */
- if (argc)
- { /* run the program given on the commandline */
- if (putenv (infostr))
- {
- log_error ("failed to set environment: %s\n",
- strerror (errno) );
- kill (pid, SIGTERM );
- exit (1);
- }
- execvp (argv[0], argv);
- log_error ("failed to run the command: %s\n", strerror (errno));
- kill (pid, SIGTERM);
- exit (1);
- }
- else
- {
- /* print the environment string, so that the caller can use
- shell's eval to set it */
- if (csh_style)
- {
- *strchr (infostr, '=') = ' ';
- printf ( "setenv %s\n", infostr);
- }
- else
- {
- printf ( "%s; export SCDAEMON_INFO;\n", infostr);
- }
- free (infostr);
- exit (0);
- }
- /* NOTREACHED */
- } /* end parent */
-
- /* this is the child */
-
- /* detach from tty and put process into a new session */
- if (!nodetach )
- { /* close stdin, stdout and stderr unless it is the log stream */
- for (i=0; i <= 2; i++)
- {
- if ( log_get_fd () != i)
- close (i);
- }
- if (setsid() == -1)
- {
- log_error ("setsid() failed: %s\n", strerror(errno) );
- cleanup ();
- exit (1);
- }
- }
-
- /* setup signals */
- {
- struct sigaction oact, nact;
-
- nact.sa_handler = cleanup_sh;
- sigemptyset (&nact.sa_mask);
- nact.sa_flags = 0;
-
- sigaction (SIGHUP, NULL, &oact);
- if (oact.sa_handler != SIG_IGN)
- sigaction (SIGHUP, &nact, NULL);
- sigaction( SIGTERM, NULL, &oact );
- if (oact.sa_handler != SIG_IGN)
- sigaction (SIGTERM, &nact, NULL);
- nact.sa_handler = SIG_IGN;
- sigaction (SIGPIPE, &nact, NULL);
- sigaction (SIGINT, &nact, NULL);
- }
-
- if (chdir("/"))
- {
- log_error ("chdir to / failed: %s\n", strerror (errno));
- exit (1);
- }
-
- scd_command_handler (fd);
-
- close (fd);
- }
-
- return 0;
-}
-
-void
-scd_exit (int rc)
-{
- #if 0
-#warning no update_random_seed_file
- update_random_seed_file();
- #endif
-#if 0
- /* at this time a bit annoying */
- if (opt.debug & DBG_MEMSTAT_VALUE)
- {
- gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
- gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
- }
- if (opt.debug)
- gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
-#endif
- gcry_control (GCRYCTL_TERM_SECMEM );
- rc = rc? rc : log_get_errorcount(0)? 2 : 0;
- exit (rc);
-}
-
-
-void
-scd_init_default_ctrl (CTRL ctrl)
-{
-
-}
-
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
deleted file mode 100644
index b21e19f8c..000000000
--- a/scd/scdaemon.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/* scdaemon.h - Global definitions for the SCdaemon
- * Copyright (C) 2001, 2002, 2003 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 2 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, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
- */
-
-#ifndef SCDAEMON_H
-#define SCDAEMON_H
-
-#ifdef GPG_ERR_SOURCE_DEFAULT
-#error GPG_ERR_SOURCE_DEFAULT already defined
-#endif
-#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_SCD
-#include <gpg-error.h>
-#include <errno.h>
-
-#include <time.h>
-#include <gcrypt.h>
-#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
-
-/* A large struct name "opt" to keep global flags */
-struct {
- unsigned int debug; /* debug flags (DBG_foo_VALUE) */
- int debug_sc; /* OpenSC debug level */
- int verbose; /* verbosity level */
- int quiet; /* be as quiet as possible */
- int dry_run; /* don't change any persistent data */
- int batch; /* batch mode */
- const char *homedir; /* configuration directory name */
-} opt;
-
-
-#define DBG_COMMAND_VALUE 1 /* debug commands i/o */
-#define DBG_MPI_VALUE 2 /* debug mpi details */
-#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
-#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
-#define DBG_CACHE_VALUE 64 /* debug the caching */
-#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
-#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_ASSUAN_VALUE 1024
-#define DBG_CARD_IO_VALUE 2048
-
-#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
-#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
-#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
-#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
-#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
-#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
-#define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE)
-
-struct server_local_s;
-struct card_ctx_s;
-struct app_ctx_s;
-
-struct server_control_s {
- struct server_local_s *server_local;
- struct card_ctx_s *card_ctx;
- struct app_ctx_s *app_ctx;
- struct {
- unsigned char *value;
- int valuelen;
- } in_data; /* helper to store the value we are going to sign */
-
-};
-
-typedef struct server_control_s *CTRL;
-typedef struct card_ctx_s *CARD;
-typedef struct app_ctx_s *APP;
-
-/*-- scdaemon.c --*/
-void scd_exit (int rc);
-void scd_init_default_ctrl (CTRL ctrl);
-
-/*-- command.c --*/
-void scd_command_handler (int);
-void send_status_info (CTRL ctrl, const char *keyword, ...);
-
-/*-- card.c --*/
-int card_open (CARD *rcard);
-void card_close (CARD card);
-int card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp);
-int card_enum_keypairs (CARD card, int idx,
- unsigned char *keygrip,
- char **keyid);
-int card_enum_certs (CARD card, int idx, char **certid, int *certtype);
-int card_read_cert (CARD card, const char *certidstr,
- unsigned char **cert, size_t *ncert);
-int card_sign (CARD card,
- const char *keyidstr, int hashalgo,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen );
-int card_decipher (CARD card, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg,
- const void *indata, size_t indatalen,
- unsigned char **outdata, size_t *outdatalen);
-
-
-#endif /*SCDAEMON_H*/