1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

* configure.ac (HAVE_LIBUSB): Added a simple test for libusb.

* scdaemon.c, scdaemon.h: New option --pcsc-ccid.
* ccid-driver.c, ccid-driver.h: New but far from being useful.
* Makefile.am: Add above.
* apdu.c: Add support for that ccid driver.
This commit is contained in:
Werner Koch 2003-09-02 19:06:34 +00:00
parent 93c76df907
commit 936250aac9
13 changed files with 827 additions and 7 deletions

View File

@ -1,3 +1,7 @@
2003-09-02 Werner Koch <wk@gnupg.org>
* configure.ac (HAVE_LIBUSB): Added a simple test for libusb.
2003-08-19 Marcus Brinkmann <marcus@g10code.de> 2003-08-19 Marcus Brinkmann <marcus@g10code.de>
* configure.ac (AM_PATH_GPG_ERROR): Add missing comma in * configure.ac (AM_PATH_GPG_ERROR): Add missing comma in

3
TODO
View File

@ -20,6 +20,9 @@ might want to have an agent context for each service request
** When a certificate chain was sucessfully verified, make ephemeral certs used in this chain permanent. ** When a certificate chain was sucessfully verified, make ephemeral certs used in this chain permanent.
** figure out how to auto retrieve a key by serialno+issuer. ** figure out how to auto retrieve a key by serialno+issuer.
Dirmngr is currently not able to parse more than the CN. Dirmngr is currently not able to parse more than the CN.
** Try all available root certs in case we have several of them in our keybox.
For example TC TrustCenter Class 1 CA certs are ambiguous becuase
user certs don't come with a authorityKeyIdentifier.
* sm/decrypt.c * sm/decrypt.c
** replace leading zero in integer hack by a cleaner solution ** replace leading zero in integer hack by a cleaner solution

View File

@ -39,6 +39,10 @@ do_encode_md (const byte * md, size_t mdlen, int algo, gcry_sexp_t * r_hash)
char * p, tmp[16]; char * p, tmp[16];
int i, rc; int i, rc;
#warning I do do like that stuff - libgcrypt provides easier interfaces. -wk
/* FIXME: Either use the build function or create canonical encoded
S-expressions. */
p = xmalloc (64 + 2 * mdlen); p = xmalloc (64 + 2 * mdlen);
s = gcry_md_algo_name (algo); s = gcry_md_algo_name (algo);
if (s && strlen (s) < 16) if (s && strlen (s) < 16)

View File

@ -376,6 +376,19 @@ AM_PATH_LIBASSUAN("$NEED_LIBASSUAN_VERSION",
# #
AM_PATH_KSBA("$NEED_KSBA_VERSION",have_ksba=yes,have_ksba=no) AM_PATH_KSBA("$NEED_KSBA_VERSION",have_ksba=yes,have_ksba=no)
#
# libusb allows us to use the integrated CCID smartcard reader driver.
# Note, that we need the CVS version. FIXME: libusb should have a
# regular check as the other libraries do.
AC_CHECK_LIB(usb, usb_find_device,
[ LIBUSB_LIBS="$LIBUSB_LIBS -lusb"
AC_DEFINE(HAVE_LIBUSB,1,
[defined if libusb is available])
])
AC_SUBST(LIBUSB_LIBS)
# #
# OpenSC is needed by the SCdaemon - if it is not availbale we can only # OpenSC is needed by the SCdaemon - if it is not availbale we can only

View File

@ -3,6 +3,10 @@
* pkglue.c (mpi_from_sexp): New. Used to factor out * pkglue.c (mpi_from_sexp): New. Used to factor out
some common code. some common code.
2003-08-24 Werner Koch <wk@gnupg.org>
* keygen.c (do_generate_keypair): Print a reminder to use --gen-revoke.
2003-08-18 Timo Schulz <twoaday@freakmail.de> 2003-08-18 Timo Schulz <twoaday@freakmail.de>
* encode.c (encode_sesskey): Checked the code and removed * encode.c (encode_sesskey): Checked the code and removed

View File

@ -2655,6 +2655,15 @@ do_generate_keypair (struct para_data_s *para,
"the command \"--edit-key\" to generate a " "the command \"--edit-key\" to generate a "
"secondary key for this purpose.\n")); "secondary key for this purpose.\n"));
} }
if (!opt.batch && card)
{
tty_printf(_(
"Please create a revocation certificate now, so that you are able\n"
"to revoke the key if it ever happens that you lose your card or\n"
"the card gets damaged. Use the command \"--gen-revoke\".\n"
));
}
} }
} }

View File

@ -1,3 +1,10 @@
2003-09-02 Werner Koch <wk@gnupg.org>
* scdaemon.c, scdaemon.h: New option --pcsc-ccid.
* ccid-driver.c, ccid-driver.h: New but far from being useful.
* Makefile.am: Add above.
* apdu.c: Add support for that ccid driver.
2003-08-26 Timo Schulz <twoaday@freakmail.de> 2003-08-26 Timo Schulz <twoaday@freakmail.de>
* apdu.c (new_reader_slot): Only set 'is_osc' when OpenSC * apdu.c (new_reader_slot): Only set 'is_osc' when OpenSC

View File

@ -32,17 +32,19 @@ scdaemon_SOURCES = \
card-common.h \ card-common.h \
card-p15.c card-dinsig.c \ card-p15.c card-dinsig.c \
apdu.c apdu.h \ apdu.c apdu.h \
ccid-driver.c ccid-driver.h \
iso7816.c iso7816.h \ iso7816.c iso7816.h \
app.c app-common.h \ app.c app-common.h \
app-openpgp.c app-openpgp.c
scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \ scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \ $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(LIBASSUAN_LIBS) \
-lgpg-error @INTLLIBS@ -ldl $(LIBUSB_LIBS) -lgpg-error @INTLLIBS@ -ldl
sc_investigate_SOURCES = \ sc_investigate_SOURCES = \
sc-investigate.c scdaemon.h \ sc-investigate.c scdaemon.h \
apdu.c apdu.h \ apdu.c apdu.h \
ccid-driver.c ccid-driver.h \
iso7816.c iso7816.h \ iso7816.c iso7816.h \
app.c app-common.h \ app.c app-common.h \
app-openpgp.c \ app-openpgp.c \
@ -50,12 +52,14 @@ sc_investigate_SOURCES = \
sc_investigate_LDADD = \ sc_investigate_LDADD = \
../jnlib/libjnlib.a ../common/libcommon.a \ ../jnlib/libjnlib.a ../common/libcommon.a \
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) @INTLLIBS@ -lgpg-error -ldl $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) @INTLLIBS@ \
-lgpg-error -ldl
sc_copykeys_SOURCES = \ sc_copykeys_SOURCES = \
sc-copykeys.c scdaemon.h \ sc-copykeys.c scdaemon.h \
apdu.c apdu.h \ apdu.c apdu.h \
ccid-driver.c ccid-driver.h \
iso7816.c iso7816.h \ iso7816.c iso7816.h \
app.c app-common.h \ app.c app-common.h \
app-openpgp.c \ app-openpgp.c \
@ -64,7 +68,8 @@ sc_copykeys_SOURCES = \
sc_copykeys_LDADD = \ sc_copykeys_LDADD = \
../jnlib/libjnlib.a ../common/libcommon.a \ ../jnlib/libjnlib.a ../common/libcommon.a \
../common/libsimple-pwquery.a \ ../common/libsimple-pwquery.a \
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@ -ldl $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(LIBUSB_LIBS) \
-lgpg-error @INTLLIBS@ -ldl

View File

@ -31,6 +31,7 @@
#include "scdaemon.h" #include "scdaemon.h"
#include "apdu.h" #include "apdu.h"
#include "dynload.h" #include "dynload.h"
#include "ccid-driver.h"
#define MAX_READER 4 /* Number of readers we support concurrently. */ #define MAX_READER 4 /* Number of readers we support concurrently. */
#define CARD_CONNECT_TIMEOUT 1 /* Number of seconds to wait for #define CARD_CONNECT_TIMEOUT 1 /* Number of seconds to wait for
@ -42,6 +43,10 @@
struct reader_table_s { struct reader_table_s {
int used; /* True if slot is used. */ int used; /* True if slot is used. */
unsigned short port; /* Port number: 0 = unused, 1 - dev/tty */ unsigned short port; /* Port number: 0 = unused, 1 - dev/tty */
int is_ccid; /* Uses the internal CCID driver. */
struct {
ccid_driver_t handle;
} ccid;
int is_ctapi; /* This is a ctAPI driver. */ int is_ctapi; /* This is a ctAPI driver. */
struct { struct {
unsigned long context; unsigned long context;
@ -155,6 +160,7 @@ new_reader_slot (void)
return -1; return -1;
} }
reader_table[reader].used = 1; reader_table[reader].used = 1;
reader_table[reader].is_ccid = 0;
reader_table[reader].is_ctapi = 0; reader_table[reader].is_ctapi = 0;
#ifdef HAVE_OPENSC #ifdef HAVE_OPENSC
reader_table[reader].is_osc = 0; reader_table[reader].is_osc = 0;
@ -166,7 +172,9 @@ new_reader_slot (void)
static void static void
dump_reader_status (int reader) dump_reader_status (int reader)
{ {
if (reader_table[reader].is_ctapi) if (reader_table[reader].is_ccid)
log_info ("reader slot %d: using ccid driver\n", reader);
else if (reader_table[reader].is_ctapi)
{ {
log_info ("reader slot %d: %s\n", reader, log_info ("reader slot %d: %s\n", reader,
reader_table[reader].status == 1? "Processor ICC present" : reader_table[reader].status == 1? "Processor ICC present" :
@ -549,7 +557,74 @@ pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
return err? -1:0; /* FIXME: Return appropriate error code. */ return err? -1:0; /* FIXME: Return appropriate error code. */
} }
#ifdef HAVE_LIBUSB
/*
Internal CCID driver interface.
*/
static int
open_ccid_reader (void)
{
int err;
int slot;
reader_table_t slotp;
slot = new_reader_slot ();
if (slot == -1)
return -1;
slotp = reader_table + slot;
err = ccid_open_reader (&slotp->ccid.handle, 0);
if (err)
{
slotp->used = 0;
return -1;
}
err = ccid_get_atr (slotp->ccid.handle,
slotp->atr, sizeof slotp->atr, &slotp->atrlen);
if (err)
{
slotp->used = 0;
return -1;
}
slotp->is_ccid = 1;
dump_reader_status (slot);
return slot;
}
/* Actually send the APDU of length APDULEN to SLOT and return a
maximum of *BUFLEN data in BUFFER, the actual returned size will be
set to BUFLEN. Returns: Internal CCID driver error code. */
static int
send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
unsigned char *buffer, size_t *buflen)
{
long err;
size_t maxbuflen;
if (DBG_CARD_IO)
log_printhex (" APDU_data:", apdu, apdulen);
maxbuflen = *buflen;
err = ccid_transceive (reader_table[slot].ccid.handle,
apdu, apdulen,
buffer, maxbuflen, buflen);
if (err)
log_error ("ccid_transceive failed: (0x%lx)\n",
err);
return err? -1:0; /* FIXME: Return appropriate error code. */
}
#endif /* HAVE_LIBUSB */
#ifdef HAVE_OPENSC #ifdef HAVE_OPENSC
/* /*
OpenSC Interface. OpenSC Interface.
@ -755,6 +830,17 @@ apdu_open_reader (const char *portstr)
{ {
static int pcsc_api_loaded, ct_api_loaded; static int pcsc_api_loaded, ct_api_loaded;
#ifdef HAVE_LIBUSB
if (!opt.disable_ccid)
{
int slot;
slot = open_ccid_reader ();
if (slot != -1)
return slot; /* got one */
}
#endif
#ifdef HAVE_OPENSC #ifdef HAVE_OPENSC
if (!opt.disable_opensc) if (!opt.disable_opensc)
{ {
@ -871,6 +957,10 @@ error_string (int slot, long rc)
return "[invalid slot]"; return "[invalid slot]";
if (reader_table[slot].is_ctapi) if (reader_table[slot].is_ctapi)
return ct_error_string (rc); return ct_error_string (rc);
#ifdef HAVE_LIBUSB
else if (reader_table[slot].is_ccid)
return "no CCID driver error strings yet";
#endif
#ifdef HAVE_OPENSC #ifdef HAVE_OPENSC
else if (reader_table[slot].is_osc) else if (reader_table[slot].is_osc)
return sc_strerror (rc); return sc_strerror (rc);
@ -889,6 +979,10 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
return SW_HOST_NO_DRIVER; return SW_HOST_NO_DRIVER;
if (reader_table[slot].is_ctapi) if (reader_table[slot].is_ctapi)
return ct_send_apdu (slot, apdu, apdulen, buffer, buflen); return ct_send_apdu (slot, apdu, apdulen, buffer, buflen);
#ifdef HAVE_LIBUSB
else if (reader_table[slot].is_ccid)
return send_apdu_ccid (slot, apdu, apdulen, buffer, buflen);
#endif
#ifdef HAVE_OPENSC #ifdef HAVE_OPENSC
else if (reader_table[slot].is_osc) else if (reader_table[slot].is_osc)
return osc_send_apdu (slot, apdu, apdulen, buffer, buflen); return osc_send_apdu (slot, apdu, apdulen, buffer, buflen);

627
scd/ccid-driver.c Normal file
View File

@ -0,0 +1,627 @@
/* ccid-driver.c - USB ChipCardInterfaceDevices driver
* 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
*/
/* CCID (ChipCardInterfaceDevices) is a specification for accessing
smartcard via a reader connected to the USB.
This is a limited driver allowing to use some CCID drivers directly
without any other specila drivers. This is a fallback driver to be
used when nothing else works or the system should be kept minimal
for security reasons. It makes use of the libusb library to gain
portable access to USB.
This driver has been tested with the SCM SCR335 smartcard reader
and requires that reader implements the TPDU level exchange and
does fully automatic initialization.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#if defined(HAVE_LIBUSB) || defined(TEST)
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <usb.h>
#include "ccid-driver.h"
enum {
RDR_to_PC_NotifySlotChange= 0x50,
RDR_to_PC_HardwareError = 0x51,
PC_to_RDR_SetParameters = 0x61,
PC_to_RDR_IccPowerOn = 0x62,
PC_to_RDR_IccPowerOff = 0x63,
PC_to_RDR_GetSlotStatus = 0x65,
PC_to_RDR_Secure = 0x69,
PC_to_RDR_T0APDU = 0x6a,
PC_to_RDR_Escape = 0x6b,
PC_to_RDR_GetParameters = 0x6c,
PC_to_RDR_ResetParameters = 0x6d,
PC_to_RDR_IccClock = 0x6e,
PC_to_RDR_XfrBlock = 0x6f,
PC_to_RDR_Mechanical = 0x71,
PC_to_RDR_Abort = 0x72,
PC_to_RDR_SetDataRate = 0x73,
RDR_to_PC_DataBlock = 0x80,
RDR_to_PC_SlotStatus = 0x81,
RDR_to_PC_Parameters = 0x82,
RDR_to_PC_Escape = 0x83,
RDR_to_PC_DataRate = 0x84
};
/* Store information on the driver's state. A pointer to such a
structure is used as handle for most functions. */
struct ccid_driver_s {
usb_dev_handle *idev;
int seqno;
unsigned char t1_seqno;
};
/* Open the reader with the internal number READERNO and return a a
pointer to be used as handle in HANDLE. Returns 0 on success. */
int
ccid_open_reader (ccid_driver_t *handle, int readerno)
{
static int initialized;
int rc;
usb_match_handle *match = NULL;
struct usb_device *dev = NULL;
usb_dev_handle *idev = NULL;
*handle = NULL;
if (!initialized)
{
usb_init ();
initialized = 1;
}
rc = usb_create_match (&match, -1, -1, 11, -1, -1);
if (rc)
{
fprintf (stderr, "ccid-driver: usb_create_match failed: %d\n", rc);
return -1;
}
while (usb_find_device(match, dev, &dev) >= 0)
{
fprintf(stderr, "ccid-driver: %-40s %04X/%04X\n", dev->filename,
dev->descriptor->idVendor, dev->descriptor->idProduct);
if (!readerno)
{
rc = usb_open (dev, &idev);
if (rc)
{
fprintf (stderr, "ccid-driver: usb_open failed: %d\n", rc);
goto leave;
}
rc = usb_claim_interface (idev, 0);
if (rc)
{
fprintf (stderr, "ccid-driver: usb_claim_interface failed: %d\n",
rc);
goto leave;
}
*handle = calloc (1, sizeof **handle);
if (!*handle)
{
fprintf (stderr, "ccid-driver: out of memory\n");
rc = -1;
goto leave;
}
(*handle)->idev = idev;
idev = NULL;
break;
}
readerno--;
}
leave:
if (idev)
usb_close (idev);
/* fixme: Do we need to release dev or is it supposed to be a
shallow copy of the list created internally by usb_init ? */
usb_free_match (match);
return rc;
}
/* Return False if a card is present and powered. */
int
ccid_check_card_presence (ccid_driver_t handle)
{
return -1;
}
static void
set_msg_len (unsigned char *msg, unsigned int length)
{
msg[1] = length;
msg[2] = length >> 8;
msg[3] = length >> 16;
msg[4] = length >> 24;
}
/* Write a MSG of length MSGLEN to the designated bulk out endpoint.
Returns 0 on success. */
static int
bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen)
{
int rc;
rc = usb_bulk_write (handle->idev,
1, /*endpoint */
msg, msglen,
1000 /* ms timeout */);
if (rc == msglen)
return 0;
if (rc == -1)
fprintf (stderr, "ccid-driver: usb_bulk_write error: %s\n",
strerror (errno));
else
fprintf (stderr, "ccid-driver: usb_bulk_write failed: %d\n", rc);
return -1;
}
/* Read a maximum of LENGTH bytes from the bulk in endpoint into
BUFFER and return the actual read number if bytes in NREAD.
Returns 0 on success. */
static int
bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
size_t *nread)
{
int rc;
rc = usb_bulk_read (handle->idev,
0x82,
buffer, length,
1000 /* ms timeout */ );
if (rc < 0)
{
fprintf (stderr, "ccid-driver: usb_bulk_read error: %s\n",
strerror (errno));
return -1;
}
*nread = rc;
return 0;
}
/* experimental */
int
ccid_poll (ccid_driver_t handle)
{
int rc;
unsigned char msg[10];
size_t msglen;
int i, j;
rc = usb_bulk_read (handle->idev,
0x83,
msg, sizeof msg,
0 /* ms timeout */ );
if (rc < 0 && errno == ETIMEDOUT)
return 0;
if (rc < 0)
{
fprintf (stderr, "ccid-driver: usb_intr_read error: %s\n",
strerror (errno));
return -1;
}
msglen = rc;
rc = 0;
if (msglen < 1)
{
fprintf (stderr, "ccid-driver: intr-in msg too short\n");
return -1;
}
if (msg[0] == RDR_to_PC_NotifySlotChange)
{
fprintf (stderr, "ccid-driver: notify slot change:");
for (i=1; i < msglen; i++)
for (j=0; j < 4; j++)
fprintf (stderr, " %d:%c%c",
(i-1)*4+j,
(msg[i] & (1<<(j*2)))? 'p':'-',
(msg[i] & (2<<(j*2)))? '*':' ');
putc ('\n', stderr);
}
else if (msg[0] == RDR_to_PC_HardwareError)
{
fprintf (stderr, "ccid-driver: hardware error occured\n");
}
else
{
fprintf (stderr, "ccid-driver: unknown intr-in msg of type %02X\n",
msg[0]);
}
return 0;
}
int
ccid_slot_status (ccid_driver_t handle)
{
int rc;
unsigned char msg[100];
size_t msglen;
unsigned char seqno;
msg[0] = PC_to_RDR_GetSlotStatus;
msg[5] = 0; /* slot */
msg[6] = seqno = handle->seqno++;
msg[7] = 0; /* RFU */
msg[8] = 0; /* RFU */
msg[9] = 0; /* RFU */
set_msg_len (msg, 0);
rc = bulk_out (handle, msg, 10);
if (rc)
return rc;
rc = bulk_in (handle, msg, sizeof msg, &msglen);
if (rc)
return rc;
if (msglen < 10)
{
fprintf (stderr, "ccid-driver: bulk-in msg too short (%u)\n",
(unsigned int)msglen);
return -1;
}
if (msg[0] != RDR_to_PC_SlotStatus)
{
fprintf (stderr, "ccid-driver: unexpected bulk-in msg type (%02x)\n",
msg[0]);
return -1;
}
if (msg[5] != 0)
{
fprintf (stderr, "ccid-driver: unexpected bulk-in slot (%d)\n",
msg[5]);
return -1;
}
if (msg[6] != seqno)
{
fprintf (stderr, "ccid-driver: bulk-in seqno does not match (%d/%d)\n",
seqno, msg[6]);
return -1;
}
fprintf (stderr,
"ccid-driver: status: %02X error: %02X clock-status: %02X\n",
msg[7], msg[8], msg[9] );
return 0;
}
int
ccid_get_atr (ccid_driver_t handle,
unsigned char *atr, size_t maxatrlen, size_t *atrlen)
{
int rc;
unsigned char msg[100];
size_t msglen;
unsigned char seqno;
int i;
msg[0] = PC_to_RDR_IccPowerOn;
msg[5] = 0; /* slot */
msg[6] = seqno = handle->seqno++;
msg[7] = 0; /* power select (0=auto, 1=5V, 2=3V, 3=1.8V) */
msg[8] = 0; /* RFU */
msg[9] = 0; /* RFU */
set_msg_len (msg, 0);
msglen = 10;
rc = bulk_out (handle, msg, msglen);
if (rc)
return rc;
rc = bulk_in (handle, msg, sizeof msg, &msglen);
if (rc)
return rc;
if (msglen < 10)
{
fprintf (stderr, "ccid-driver: bulk-in msg too short (%u)\n",
(unsigned int)msglen);
return -1;
}
if (msg[0] != RDR_to_PC_DataBlock)
{
fprintf (stderr, "ccid-driver: unexpected bulk-in msg type (%02x)\n",
msg[0]);
return -1;
}
if (msg[5] != 0)
{
fprintf (stderr, "ccid-driver: unexpected bulk-in slot (%d)\n",
msg[5]);
return -1;
}
if (msg[6] != seqno)
{
fprintf (stderr, "ccid-driver: bulk-in seqno does not match (%d/%d)\n",
seqno, msg[6]);
return -1;
}
fprintf (stderr,
"ccid-driver: status: %02X error: %02X clock-status: %02X\n"
" data:", msg[7], msg[8], msg[9] );
for (i=10; i < msglen; i++)
fprintf (stderr, " %02X", msg[i]);
putc ('\n', stderr);
if (atr)
{
size_t n = msglen - 10;
if (n > maxatrlen)
n = maxatrlen;
memcpy (atr, msg+10, n);
*atrlen = n;
}
return 0;
}
/*
Protocol T=1 overview
Block Structure:
Prologue Field:
1 byte Node Address (NAD)
1 byte Protocol Control Byte (PCB)
1 byte Length (LEN)
Information Field:
0-254 byte APDU or Control Information (INF)
Epilogue Field:
1 byte Error Detection Code (EDC)
NAD:
bit 7 unused
bit 4..6 Destination Node Address (DAD)
bit 3 unused
bit 2..0 Source Node Address (SAD)
If node adresses are not used, SAD and DAD should be set to 0 on
the first block sent to the card. If they are used they should
have different values (0 for one is okay); that first block sets up
the addresses of the node.
PCB:
Information Block (I-Block):
bit 7 0
bit 6 Sequence number (yep, that is modulo 2)
bit 5 Chaining flag
bit 4..0 reserved
Received-Ready Block (R-Block):
bit 7 1
bit 6 0
bit 5 0
bit 4 Sequence number
bit 3..0 0 = no error
1 = EDC or parity error
2 = other error
other values are reserved
Supervisory Block (S-Block):
bit 7 1
bit 6 1
bit 5 clear=request,set=response
bit 4..0 0 = resyncronisation request
1 = information field size request
2 = abort request
3 = extension of BWT request
4 = VPP error
other values are reserved
*/
int
ccid_transceive (ccid_driver_t handle,
const unsigned char *apdu, size_t apdulen,
unsigned char *resp, size_t maxresplen, size_t *nresp)
{
int rc;
unsigned char msg[10+258], *tpdu, *p;
size_t msglen;
unsigned char seqno;
int i;
unsigned char crc;
/* Construct an I-Block. */
if (apdulen > 254)
return -1; /* Invalid length. */
tpdu = msg+10;
tpdu[0] = ((1 << 4) | 0); /* NAD: DAD=1, SAD=0 */
tpdu[1] = ((handle->t1_seqno & 1) << 6); /* I-block */
tpdu[2] = apdulen;
memcpy (tpdu+3, apdu, apdulen);
crc = 0;
for (i=0,p=tpdu; i < apdulen+3; i++)
crc ^= *p++;
tpdu[3+apdulen] = crc;
handle->t1_seqno ^= 1;
msg[0] = PC_to_RDR_XfrBlock;
msg[5] = 0; /* slot */
msg[6] = seqno = handle->seqno++;
msg[7] = 4; /* bBWI */
msg[8] = 0; /* RFU */
msg[9] = 0; /* RFU */
set_msg_len (msg, apdulen+4);
msglen = 10 + apdulen + 4;
fprintf (stderr, "ccid-driver: sending");
for (i=0; i < msglen; i++)
fprintf (stderr, " %02X", msg[i]);
putc ('\n', stderr);
rc = bulk_out (handle, msg, msglen);
if (rc)
return rc;
rc = bulk_in (handle, msg, sizeof msg, &msglen);
if (rc)
return rc;
if (msglen < 10)
{
fprintf (stderr, "ccid-driver: bulk-in msg too short (%u)\n",
(unsigned int)msglen);
return -1;
}
if (msg[0] != RDR_to_PC_DataBlock)
{
fprintf (stderr, "ccid-driver: unexpected bulk-in msg type (%02x)\n",
msg[0]);
return -1;
}
if (msg[5] != 0)
{
fprintf (stderr, "ccid-driver: unexpected bulk-in slot (%d)\n",
msg[5]);
return -1;
}
if (msg[6] != seqno)
{
fprintf (stderr, "ccid-driver: bulk-in seqno does not match (%d/%d)\n",
seqno, msg[6]);
return -1;
}
fprintf (stderr,
"ccid-driver: status: %02X error: %02X clock-status: %02X\n"
" data:", msg[7], msg[8], msg[9] );
for (i=10; i < msglen; i++)
fprintf (stderr, " %02X", msg[i]);
putc ('\n', stderr);
if (resp)
{
size_t n = msglen - 10;
if (n < 4)
n = 0; /* fixme: this is an empty I-block or some other block
- we ignore it for now until we have implemented the
T=1 machinery. */
else
{
p = msg + 10 + 3; /* Skip ccid header and prologue field. */
n -= 3;
n--; /* Strip the epilogue field. */
if (n > maxresplen)
n = maxresplen; /* fixme: return an error instead of truncating. */
memcpy (resp, p, n);
}
*nresp = n;
}
return 0;
}
#ifdef TEST
int
main (int argc, char **argv)
{
int rc;
ccid_driver_t ccid;
rc = ccid_open_reader (&ccid, 0);
if (rc)
return 1;
ccid_poll (ccid);
fputs ("getting ATR ...\n", stderr);
rc = ccid_get_atr (ccid, NULL, 0, NULL);
if (rc)
return 1;
ccid_poll (ccid);
fputs ("getting slot status ...\n", stderr);
rc = ccid_slot_status (ccid);
if (rc)
return 1;
ccid_poll (ccid);
{
static unsigned char apdu[] = {
0, 0xA4, 4, 0, 6, 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01};
rc = ccid_transceive (ccid,
apdu, sizeof apdu,
NULL, 0, NULL);
}
ccid_poll (ccid);
{
static unsigned char apdu[] = {
0, 0xCA, 0, 0x65, 254 };
rc = ccid_transceive (ccid,
apdu, sizeof apdu,
NULL, 0, NULL);
}
ccid_poll (ccid);
return 0;
}
/*
* Local Variables:
* compile-command: "gcc -DTEST -Wall -I/usr/local/include -lusb -g ccid-driver.c"
* End:
*/
#endif /*TEST*/
#endif /*HAVE_LIBUSB*/

40
scd/ccid-driver.h Normal file
View File

@ -0,0 +1,40 @@
/* ccid-driver.c - USB ChipCardInterfaceDevices driver
* 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 CCID_DRIVER_H
#define CCID_DRIVER_H
struct ccid_driver_s;
typedef struct ccid_driver_s *ccid_driver_t;
int ccid_open_reader (ccid_driver_t *handle, int readerno);
int ccid_get_atr (ccid_driver_t handle,
unsigned char *atr, size_t maxatrlen, size_t *atrlen);
int ccid_transceive (ccid_driver_t handle,
const unsigned char *apdu, size_t apdulen,
unsigned char *resp, size_t maxresplen, size_t *nresp);
#endif /*CCID_DRIVER_H*/

View File

@ -71,6 +71,7 @@ enum cmd_and_opt_values
oReaderPort, oReaderPort,
octapiDriver, octapiDriver,
opcscDriver, opcscDriver,
oDisableCCID,
oDisableOpenSC, oDisableOpenSC,
aTest }; aTest };
@ -97,9 +98,16 @@ static ARGPARSE_OPTS opts[] = {
{ oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")}, { oReaderPort, "reader-port", 2, N_("|N|connect to reader at port N")},
{ octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ct-API driver")}, { octapiDriver, "ctapi-driver", 2, N_("NAME|use NAME as ct-API driver")},
{ opcscDriver, "pcsc-driver", 2, N_("NAME|use NAME as PC/SC driver")}, { opcscDriver, "pcsc-driver", 2, N_("NAME|use NAME as PC/SC driver")},
{ oDisableCCID, "disable-ccidc", 0,
#ifdef HAVE_LIBUSB
N_("do not use the internal CCID driver")
#else
"@"
#endif
/* end --disable-ccid */},
{ oDisableOpenSC, "disable-opensc", 0, { oDisableOpenSC, "disable-opensc", 0,
#ifdef HAVE_OPENSC #ifdef HAVE_OPENSC
N_("Do not use the OpenSC layer") N_("do not use the OpenSC layer")
#else #else
"@" "@"
#endif #endif
@ -387,6 +395,7 @@ main (int argc, char **argv )
case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break; case oReaderPort: app_set_default_reader_port (pargs.r.ret_str); break;
case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break; case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break; case opcscDriver: opt.pcsc_driver = pargs.r.ret_str; break;
case oDisableCCID: opt.disable_ccid = 1; break;
case oDisableOpenSC: opt.disable_opensc = 1; break; case oDisableOpenSC: opt.disable_opensc = 1; break;
default : pargs.err = configfp? 1:2; break; default : pargs.err = configfp? 1:2; break;

View File

@ -55,7 +55,8 @@ struct {
const char *homedir; /* configuration directory name */ const char *homedir; /* configuration directory name */
const char *ctapi_driver; /* Library to access the ctAPI. */ const char *ctapi_driver; /* Library to access the ctAPI. */
const char *pcsc_driver; /* Library to access the PC/SC system. */ const char *pcsc_driver; /* Library to access the PC/SC system. */
int disable_opensc; /* Disable the sue of the OpenSC framework. */ int disable_opensc; /* Disable the use of the OpenSC framework. */
int disable_ccid; /* Disable the use of the internal CCID driver. */
} opt; } opt;