* configure.ac: Changed tests for libusb to also suuport the

stable version 0.1.x.

* scdaemon.texi (Card applications): New section.

* scdaemon.c (main): New option --disable-application.
* app.c (is_app_allowed): New.
(select_application): Use it to check for disabled applications.

* ccid-driver.h (CCID_DRIVER_ERR_ABORTED): New.
* ccid-driver.c (ccid_open_reader): Support the stable 0.1 version
of libusb.
(ccid_get_atr): Handle short messages.

* apdu.c (my_rapdu_get_status): Implemented.
This commit is contained in:
Werner Koch 2004-08-05 09:24:36 +00:00
parent 587222f48d
commit 818e9bad58
16 changed files with 282 additions and 31 deletions

View File

@ -1,3 +1,8 @@
2004-08-05 Werner Koch <wk@g10code.de>
* configure.ac: Changed tests for libusb to also suuport the
stable version 0.1.x.
2004-07-22 Werner Koch <wk@g10code.de>
Released 1.9.10.

22
TODO
View File

@ -79,3 +79,25 @@ might want to have an agent context for each service request
* doc/
** Explain how to setup a root CA key as trusted
** Explain how trustlist.txt might be managed.
* Requirements by the BSI
** Support authorityKeyIdentifier.keyIdentifier
This needs support in libksba/src/cert.c as well as in sm/*.c.
Need test certs as well. Same goes for CRL authorityKeyIdentifier.
** For pkcs#10 request header.
We use "NEW CERTIFICATE REQUEST" the specs say "CERTIFICATE
REQUEST" should be used. However it seems that their CA software
is also able to use our header. Binary pkcs#10 request are not
allowed.
** Dirmngr: name subordination (nameRelativeToCRLIssuer)
is not yet supported by Dirmngr.
** Dirmngr: CRL DP URI
The CRL DP shall use an URI for LDAP without a host name. The host
name shall be looked by using the DN in the URI. We don't implement
this yet. Solution is to have a mapping DN->host in our ldapservers
configuration file.

View File

@ -451,15 +451,13 @@ 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,
AC_CHECK_LIB(usb, usb_bulk_write,
[ LIBUSB_LIBS="$LIBUSB_LIBS -lusb"
AC_DEFINE(HAVE_LIBUSB,1,
[defined if libusb is available])
])
AC_SUBST(LIBUSB_LIBS)
AC_CHECK_FUNCS(usb_create_match)
#
# Check wether it is necessary to link against libdl.

View File

@ -1,3 +1,7 @@
2004-08-05 Werner Koch <wk@g10code.de>
* scdaemon.texi (Card applications): New section.
2004-06-22 Werner Koch <wk@g10code.com>
* glossary.texi: New.

View File

@ -10,7 +10,7 @@
@c man begin DESCRIPTION
The @sc{scdaeon} is a daemon to manage smartcards. It is usually
The @sc{scdaemon} is a daemon to manage smartcards. It is usually
invoked by gpg-agent and in general not used directly.
@c man end
@ -20,6 +20,7 @@ invoked by gpg-agent and in general not used directly.
@menu
* Scdaemon Commands:: List of all commands.
* Scdaemon Options:: List of all options.
* Card applications:: Description of card applications.
* Scdaemon Examples:: Some usage examples.
* Scdaemon Protocol:: The protocol the daemon uses.
@end menu
@ -176,18 +177,70 @@ is @code{libtowitoko.so}.
@itemx --deny-admin
@opindex allow-admin
@opindex deny-admin
This enables the use of Admin class commands for card application
This enables the use of Admin class commands for card applications
where this is supported. Currently we support it for the OpenPGP
card. Deny is the default. This commands is useful to inhibit
accidental access to admin class command which could ultimately lock
the card through worng PIN numbers.
@item --disable-application @var{name}
@opindex disable-application
This option disables the use of the card application named
@var{name}. This is mainly useful for debugging or if a application
with lower priority should be used by default.
@end table
All the long options may also be given in the configuration file after
stripping off the two leading dashes.
@c man begin CARD APPLICATIONS
@node Card applications
@section Description of card applications
@sc{scdaemon} supports the card applications as described below.
@menu
* OpenPGP Card:: The OpenPGP card application
* NKS Card:: The Telesec NetKey card application
* DINSIG Card:: The DINSIG card application
* PKCS#15 Card:: The PKCS#15 card application
@end menu
@node OpenPGP Card
@subsection The OpenPGP card application ``openpgp''
This application is currently only used by @sc{gpg} but may in
future also be useful with @sc{gpgsm}.
The specification for such a card is available at
@uref{http://g10code.com/docs/openpgp-card-1.0.pdf}.
@node NKS Card
@subsection The Telesec NetKey card ``nks''
This is the main application of the Telesec cards as available in
Germany. It is a superset of the German DINSIG card. The card is
used by @sc{gpgsm}.
@node DINSIG Card
@subsection The DINSIG card application ``dinsig''
This is an application as described in the German draft standard
@emph{DIN V 66291-1}. It is intended to be used by cards supporteing
the German signature law and its bylaws (SigG and SigV).
@node PKCS#15 Card
@subsection The PKCS#15 card application ``p15''
This is common fraqmework for smart card applications; support is only
available if compiled with support for the OpenSC library. It is used
by @sc{gpgsm}.
@c
@c Examples
@c

View File

@ -1,3 +1,16 @@
2004-08-05 Werner Koch <wk@g10code.de>
* scdaemon.c (main): New option --disable-application.
* app.c (is_app_allowed): New.
(select_application): Use it to check for disabled applications.
* ccid-driver.h (CCID_DRIVER_ERR_ABORTED): New.
* ccid-driver.c (ccid_open_reader): Support the stable 0.1 version
of libusb.
(ccid_get_atr): Handle short messages.
* apdu.c (my_rapdu_get_status): Implemented.
2004-07-27 Moritz Schulte <moritz@g10code.com>
* apdu.c: Include <signal.h>.

View File

@ -19,7 +19,6 @@
*/
#include <config.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
@ -296,6 +295,7 @@ host_sw_string (long err)
case SW_HOST_CARD_IO_ERROR: return "card I/O error";
case SW_HOST_GENERAL_ERROR: return "general error";
case SW_HOST_NO_READER: return "no reader";
case SW_HOST_ABORTED: return "aborted";
default: return "unknown host status error";
}
}
@ -1633,7 +1633,42 @@ reset_rapdu_reader (int slot)
static int
my_rapdu_get_status (int slot, unsigned int *status)
{
return SW_HOST_NOT_SUPPORTED;
int err;
reader_table_t slotp;
rapdu_msg_t msg = NULL;
int oldslot;
slotp = reader_table + slot;
oldslot = rapdu_set_reader (slotp->rapdu.handle, slot);
err = rapdu_send_cmd (slotp->rapdu.handle, RAPDU_CMD_GET_STATUS);
rapdu_set_reader (slotp->rapdu.handle, oldslot);
if (err)
{
log_error ("sending rapdu command GET_STATUS failed: %s\n",
err < 0 ? strerror (errno): rapdu_strerror (err));
return rapdu_status_to_sw (err);
}
err = rapdu_read_msg (slotp->rapdu.handle, &msg);
if (err)
{
log_error ("receiving rapdu message failed: %s\n",
err < 0 ? strerror (errno): rapdu_strerror (err));
rapdu_msg_release (msg);
return rapdu_status_to_sw (err);
}
if (msg->cmd != RAPDU_STATUS_SUCCESS || !msg->datalen)
{
int sw = rapdu_status_to_sw (msg->cmd);
log_error ("rapdu command GET_STATUS failed: %s\n",
rapdu_strerror (msg->cmd));
rapdu_msg_release (msg);
return sw;
}
*status = msg->data[0];
rapdu_msg_release (msg);
return 0;
}

View File

@ -58,7 +58,8 @@ enum {
SW_HOST_CARD_INACTIVE = 0x10009,
SW_HOST_CARD_IO_ERROR = 0x1000a,
SW_HOST_GENERAL_ERROR = 0x1000b,
SW_HOST_NO_READER = 0x1000c
SW_HOST_NO_READER = 0x1000c,
SW_HOST_ABORTED = 0x1000d
};

View File

@ -32,6 +32,19 @@
#include "tlv.h"
/* Check wether the application NAME is allowed. This does not mean
we have support for it though. */
static int
is_app_allowed (const char *name)
{
strlist_t l;
for (l=opt.disabled_applications; l; l = l->next)
if (!strcmp (l->d, name))
return 0; /* no */
return 1; /* yes */
}
/* If called with NAME as NULL, select the best fitting application
and return a context; otherwise select the application with NAME
and return a context. SLOT identifies the reader device. Returns
@ -84,11 +97,11 @@ select_application (ctrl_t ctrl, int slot, const char *name)
rc = gpg_error (GPG_ERR_NOT_FOUND);
if (!name || !strcmp (name, "openpgp"))
if (rc && is_app_allowed ("openpgp") && (!name || !strcmp (name, "openpgp")))
rc = app_select_openpgp (app);
if (rc && (!name || !strcmp (name, "nks")))
if (rc && is_app_allowed ("nks") && (!name || !strcmp (name, "nks")))
rc = app_select_nks (app);
if (rc && (!name || !strcmp (name, "dinsig")))
if (rc && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
rc = app_select_dinsig (app);
if (rc && name)
rc = gpg_error (GPG_ERR_NOT_SUPPORTED);

View File

@ -412,7 +412,13 @@ read_device_info (ccid_driver_t handle, struct usb_device *dev)
{
int cfg_no;
for (cfg_no=0; cfg_no < dev->descriptor->bNumConfigurations; cfg_no++)
for (cfg_no=0; cfg_no <
#ifdef HAVE_USB_CREATE_MATCH
dev->descriptor->bNumConfigurations
#else
dev->descriptor.bNumConfigurations
#endif
; cfg_no++)
{
struct usb_config_descriptor *config = dev->config + cfg_no;
int ifc_no;
@ -451,8 +457,9 @@ read_device_info (ccid_driver_t handle, struct usb_device *dev)
int
ccid_open_reader (ccid_driver_t *handle, int readerno)
{
#ifdef HAVE_USB_CREATE_MATCH
/* This is the development version of libusb. */
static int initialized;
int rc;
usb_match_handle *match = NULL;
struct usb_device *dev = NULL;
@ -471,7 +478,7 @@ ccid_open_reader (ccid_driver_t *handle, int readerno)
DEBUGOUT_1 ("usb_create_match failed: %d\n", rc);
return CCID_DRIVER_ERR_NO_READER;
}
while (usb_find_device(match, dev, &dev) >= 0)
{
DEBUGOUT_3 ("%-40s %04X/%04X\n", dev->filename,
@ -530,7 +537,6 @@ ccid_open_reader (ccid_driver_t *handle, int readerno)
readerno--;
}
leave:
if (idev)
usb_close (idev);
@ -542,6 +548,96 @@ ccid_open_reader (ccid_driver_t *handle, int readerno)
rc = -1; /* In case we didn't enter the while loop at all. */
return rc;
#else /* Stable 0.1 version of libusb. */
static int initialized;
int rc = 0;
struct usb_bus *busses, *bus;
struct usb_device *dev = NULL;
usb_dev_handle *idev = NULL;
*handle = NULL;
if (!initialized)
{
usb_init ();
initialized = 1;
}
usb_find_busses();
usb_find_devices();
busses = usb_get_busses();
for (bus = busses; bus; bus = bus->next)
{
for (dev = bus->devices; dev; dev = dev->next)
{
DEBUGOUT_3 ("%-40s %04X/%04X\n", dev->filename,
dev->descriptor.idVendor, dev->descriptor.idProduct);
if (!readerno)
{
*handle = calloc (1, sizeof **handle);
if (!*handle)
{
DEBUGOUT ("out of memory\n");
rc = CCID_DRIVER_ERR_OUT_OF_CORE;
free (*handle);
*handle = NULL;
goto leave;
}
rc = read_device_info (*handle, dev);
if (rc)
{
DEBUGOUT ("device not supported\n");
free (*handle);
*handle = NULL;
continue;
}
idev = usb_open (dev);
if (!idev)
{
DEBUGOUT_1 ("usb_open failed: %s\n", strerror (errno));
free (*handle);
*handle = NULL;
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
goto leave;
}
/* fixme: Do we need to claim and set the interface as
determined by read_device_info ()? */
rc = usb_claim_interface (idev, 0);
if (rc)
{
DEBUGOUT_1 ("usb_claim_interface failed: %d\n", rc);
free (*handle);
*handle = NULL;
rc = CCID_DRIVER_ERR_CARD_IO_ERROR;
goto leave;
}
(*handle)->idev = idev;
idev = NULL;
/* FIXME: Do we need to get the endpoint addresses from the
structure and store them with the handle? */
goto leave; /* ready. */
}
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 ? */
if (!rc && !*handle)
rc = -1; /* In case we didn't enter the while loop at all. */
return rc;
#endif /* Stable version 0.1 of libusb. */
}
@ -894,10 +990,7 @@ ccid_get_atr (ccid_driver_t handle,
tpdulen = msglen - 10;
if (tpdulen < 4)
{
DEBUGOUT ("cannot yet handle short blocks!\n");
return -1;
}
return CCID_DRIVER_ERR_ABORTED;
#ifdef DEBUG_T1
fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
@ -1092,10 +1185,9 @@ ccid_transceive (ccid_driver_t handle,
if (tpdulen < 4)
{
DEBUGOUT ("cannot yet handle short blocks!\n");
return CCID_DRIVER_ERR_NOT_SUPPORTED;
usb_clear_halt (handle->idev, 0x82);
return CCID_DRIVER_ERR_ABORTED;
}
#ifdef DEBUG_T1
fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
((msg[11] & 0xc0) == 0x80)? 'R' :

View File

@ -70,7 +70,7 @@
#define CCID_DRIVER_ERR_CARD_IO_ERROR 0x1000a
#define CCID_DRIVER_ERR_GENERAL_ERROR 0x1000b
#define CCID_DRIVER_ERR_NO_READER 0x1000c
#define CCID_DRIVER_ERR_ABORTED 0x1000d
struct ccid_driver_s;
typedef struct ccid_driver_s *ccid_driver_t;

View File

@ -90,6 +90,7 @@ map_sw (int sw)
case SW_HOST_CARD_IO_ERROR: ec = GPG_ERR_EIO; break;
case SW_HOST_GENERAL_ERROR: ec = GPG_ERR_GENERAL; break;
case SW_HOST_NO_READER: ec = GPG_ERR_ENODEV; break;
case SW_HOST_ABORTED: ec = GPG_ERR_CANCELED; break;
default:
if ((sw & 0x010000))

View File

@ -80,6 +80,7 @@ enum cmd_and_opt_values
oDisableOpenSC,
oAllowAdmin,
oDenyAdmin,
oDisableApplication,
aTest };
@ -124,6 +125,7 @@ static ARGPARSE_OPTS opts[] = {
/* end --disable-opensc */},
{ oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")},
{ oDenyAdmin, "deny-admin", 0, "@" },
{ oDisableApplication, "disable-application", 2, "@"},
{0}
};
@ -493,6 +495,10 @@ main (int argc, char **argv )
case oAllowAdmin: opt.allow_admin = 1; break;
case oDenyAdmin: opt.allow_admin = 0; break;
case oDisableApplication:
add_to_strlist (&opt.disabled_applications, pargs.r.ret_str);
break;
default : pargs.err = configfp? 1:2; break;
}
}

View File

@ -52,6 +52,8 @@ struct {
int disable_ccid; /* Disable the use of the internal CCID driver. */
int allow_admin; /* Allow the use of admin commands for certain
cards. */
strlist_t disabled_applications; /* card applications we do not
want to use. */
} opt;

View File

@ -1,3 +1,8 @@
2004-07-23 Werner Koch <wk@g10code.de>
* certreqgen.c (proc_parameters): Do not allow key length below
1024.
2004-07-22 Werner Koch <wk@g10code.de>
* keylist.c (list_cert_raw): Print the keygrip.

View File

@ -444,7 +444,7 @@ proc_parameters (ctrl_t ctrl,
if (i < 1 || i != GCRY_PK_RSA )
{
r = get_parameter (para, pKEYTYPE);
log_error ("line %d: invalid algorithm\n", r->lnr);
log_error (_("line %d: invalid algorithm\n"), r->lnr);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
@ -453,11 +453,12 @@ proc_parameters (ctrl_t ctrl,
nbits = 1024;
else
nbits = get_parameter_uint (para, pKEYLENGTH);
if (nbits < 512 || nbits > 4096)
if (nbits < 1024 || nbits > 4096)
{
/* The BSI specs dated 2002-11-25 don't allow lengths below 1024. */
r = get_parameter (para, pKEYTYPE);
log_error ("line %d: invalid key length %u (valid are 512 to 4096)\n",
r->lnr, nbits);
log_error (_("line %d: invalid key length %u (valid are %d to %d)\n"),
r->lnr, nbits, 1024, 4096);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
@ -470,7 +471,7 @@ proc_parameters (ctrl_t ctrl,
if (!(s=get_parameter_value (para, pNAMEDN)))
{
r = get_parameter (para, pKEYTYPE);
log_error ("line %d: no subject name given\n", r->lnr);
log_error (_("line %d: no subject name given\n"), r->lnr);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
/* fixme check s */
@ -485,7 +486,7 @@ proc_parameters (ctrl_t ctrl,
|| strstr(s, ".."))
{
r = get_parameter (para, pKEYTYPE);
log_error ("line %d: not a valid email address\n", r->lnr);
log_error (_("line %d: not a valid email address\n"), r->lnr);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
}
@ -497,7 +498,7 @@ proc_parameters (ctrl_t ctrl,
if (rc)
{
r = get_parameter (para, pKEYTYPE);
log_error ("line %d: key generation failed: %s\n",
log_error (_("line %d: key generation failed: %s\n"),
r->lnr, gpg_strerror (rc));
return rc;
}