From 818e9bad581868f8455a62fb3548b4dcc9d4cbac Mon Sep 17 00:00:00 2001 From: Werner Koch Date: Thu, 5 Aug 2004 09:24:36 +0000 Subject: [PATCH] * 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. --- ChangeLog | 5 ++ TODO | 22 +++++++++ configure.ac | 6 +-- doc/ChangeLog | 4 ++ doc/scdaemon.texi | 57 ++++++++++++++++++++++- scd/ChangeLog | 13 ++++++ scd/apdu.c | 39 +++++++++++++++- scd/apdu.h | 3 +- scd/app.c | 19 ++++++-- scd/ccid-driver.c | 114 +++++++++++++++++++++++++++++++++++++++++----- scd/ccid-driver.h | 2 +- scd/iso7816.c | 1 + scd/scdaemon.c | 6 +++ scd/scdaemon.h | 2 + sm/ChangeLog | 5 ++ sm/certreqgen.c | 15 +++--- 16 files changed, 282 insertions(+), 31 deletions(-) diff --git a/ChangeLog b/ChangeLog index d83d94cde..7b14b7944 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2004-08-05 Werner Koch + + * configure.ac: Changed tests for libusb to also suuport the + stable version 0.1.x. + 2004-07-22 Werner Koch Released 1.9.10. diff --git a/TODO b/TODO index ce835d8ec..6e5c8cfb8 100644 --- a/TODO +++ b/TODO @@ -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. + diff --git a/configure.ac b/configure.ac index ca6eaf14f..f34faf469 100644 --- a/configure.ac +++ b/configure.ac @@ -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. diff --git a/doc/ChangeLog b/doc/ChangeLog index 1760695be..79a8c9532 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,7 @@ +2004-08-05 Werner Koch + + * scdaemon.texi (Card applications): New section. + 2004-06-22 Werner Koch * glossary.texi: New. diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi index 51ec4b34c..3e11a8930 100644 --- a/doc/scdaemon.texi +++ b/doc/scdaemon.texi @@ -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 diff --git a/scd/ChangeLog b/scd/ChangeLog index b0f07dc82..80b244ef1 100644 --- a/scd/ChangeLog +++ b/scd/ChangeLog @@ -1,3 +1,16 @@ +2004-08-05 Werner Koch + + * 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 * apdu.c: Include . diff --git a/scd/apdu.c b/scd/apdu.c index 7898452c4..5f800c983 100644 --- a/scd/apdu.c +++ b/scd/apdu.c @@ -19,7 +19,6 @@ */ #include - #include #include #include @@ -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; } diff --git a/scd/apdu.h b/scd/apdu.h index a2b781266..a0654a242 100644 --- a/scd/apdu.h +++ b/scd/apdu.h @@ -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 }; diff --git a/scd/app.c b/scd/app.c index a9a9243eb..b3a13f19a 100644 --- a/scd/app.c +++ b/scd/app.c @@ -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); diff --git a/scd/ccid-driver.c b/scd/ccid-driver.c index 4751b8cdb..0fc168590 100644 --- a/scd/ccid-driver.c +++ b/scd/ccid-driver.c @@ -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' : diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h index 0b108f16d..0cb52e1c3 100644 --- a/scd/ccid-driver.h +++ b/scd/ccid-driver.h @@ -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; diff --git a/scd/iso7816.c b/scd/iso7816.c index d5db607f8..cbb314eb2 100644 --- a/scd/iso7816.c +++ b/scd/iso7816.c @@ -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)) diff --git a/scd/scdaemon.c b/scd/scdaemon.c index f647aecc2..b54a63816 100644 --- a/scd/scdaemon.c +++ b/scd/scdaemon.c @@ -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; } } diff --git a/scd/scdaemon.h b/scd/scdaemon.h index 1dd32ae90..c8d78c88b 100644 --- a/scd/scdaemon.h +++ b/scd/scdaemon.h @@ -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; diff --git a/sm/ChangeLog b/sm/ChangeLog index b9780cc90..b21a5faff 100644 --- a/sm/ChangeLog +++ b/sm/ChangeLog @@ -1,3 +1,8 @@ +2004-07-23 Werner Koch + + * certreqgen.c (proc_parameters): Do not allow key length below + 1024. + 2004-07-22 Werner Koch * keylist.c (list_cert_raw): Print the keygrip. diff --git a/sm/certreqgen.c b/sm/certreqgen.c index 969ed14b0..ab1f539de 100644 --- a/sm/certreqgen.c +++ b/sm/certreqgen.c @@ -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; }