aboutsummaryrefslogtreecommitdiffstats
path: root/scd
diff options
context:
space:
mode:
Diffstat (limited to 'scd')
-rw-r--r--scd/ChangeLog659
-rw-r--r--scd/Makefile.am85
-rw-r--r--scd/apdu.c1981
-rw-r--r--scd/apdu.h85
-rw-r--r--scd/app-common.h170
-rw-r--r--scd/app-dinsig.c427
-rw-r--r--scd/app-help.c162
-rw-r--r--scd/app-nks.c515
-rw-r--r--scd/app-openpgp.c1640
-rw-r--r--scd/app.c391
-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.c258
-rw-r--r--scd/card-p15.c500
-rw-r--r--scd/card.c570
-rw-r--r--scd/ccid-driver.c1277
-rw-r--r--scd/ccid-driver.h76
-rw-r--r--scd/command.c1268
-rw-r--r--scd/iso7816.c617
-rw-r--r--scd/iso7816.h73
-rw-r--r--scd/pcsc-wrapper.c631
-rw-r--r--scd/sc-copykeys.c735
-rw-r--r--scd/sc-investigate.c770
-rw-r--r--scd/scdaemon.c933
-rw-r--r--scd/scdaemon.h130
-rw-r--r--scd/tlv.c208
-rw-r--r--scd/tlv.h84
28 files changed, 0 insertions, 14633 deletions
diff --git a/scd/ChangeLog b/scd/ChangeLog
deleted file mode 100644
index e04575c75..000000000
--- a/scd/ChangeLog
+++ /dev/null
@@ -1,659 +0,0 @@
-2004-06-16 Werner Koch <[email protected]>
-
- * apdu.c (osc_get_status): Fixed type in function name. Noted by
- Axel Thimm. Yes, I didn't tested it with OpenSC :-(.
-
-2004-04-28 Werner Koch <[email protected]>
-
- * app-openpgp.c (do_setattr): Sync FORCE_CHV1.
-
-2004-04-27 Werner Koch <[email protected]>
-
- * app-common.h: Do not include ksba.h for gnupg 1.
-
-2004-04-26 Werner Koch <[email protected]>
-
- * app-common.h: New members FNC.DEINIT and APP_LOCAL.
- * app.c (release_application): Call new deconstructor.
- * app-openpgp.c (do_deinit): New.
- (get_cached_data, flush_cache_item, flush_cache_after_error)
- (flush_cache): New.
- (get_one_do): Replaced arg SLOT by APP. Make used of cached data.
- (verify_chv2, verify_chv3): Flush some cache item after error.
- (do_change_pin): Ditto.
- (do_sign): Ditto.
- (do_setattr): Flush cache item.
- (do_genkey): Flush the entire cache.
- (compare_fingerprint): Use cached data.
-
- * scdaemon.c (main): Do the last change the usual way. This is so
- that we can easily test for versioned config files above.
-
-2004-04-26 Marcus Brinkmann <[email protected]>
-
- * scdaemon.c (main): For now, always print default filename for
- --gpgconf-list, and never /dev/null.
-
-2004-04-21 Werner Koch <[email protected]>
-
- * command.c (scd_update_reader_status_file): Send a signal back to
- the client.
- (option_handler): Parse the new event-signal option.
-
- * scdaemon.c (handle_signal): Do not use SIGUSR{1,2} anymore for
- changing the verbosity.
-
-2004-04-20 Werner Koch <[email protected]>
-
- * command.c (scd_update_reader_status_file): Write status files.
-
- * app-help.c (app_help_read_length_of_cert): Fixed calculation of
- R_CERTOFF.
-
- * pcsc-wrapper.c: New.
- * Makefile.am (pkglib_PROGRAMS): Install it here.
- * apdu.c (writen, readn): New.
- (open_pcsc_reader, pcsc_send_apdu, close_pcsc_reader): Use the
- pcsc-wrapper if we are using Pth.
- (apdu_send_le): Reinitialize RESULTLEN. Handle SW_EOF_REACHED
- like SW_SUCCESS.
-
-2004-04-19 Werner Koch <[email protected]>
-
- * ccid-driver.c (parse_ccid_descriptor): Store some of the reader
- features away. New arg HANDLE
- (read_device_info): New arg HANDLE. Changed caller.
- (bulk_in): Handle time extension requests.
- (ccid_get_atr): Setup parameters and the IFSD.
- (compute_edc): New. Factored out code.
- (ccid_transceive): Use default NADs when required.
-
-2004-04-14 Werner Koch <[email protected]>
-
- * scdaemon.h (server_control_s): Add member READER_SLOT.
- * scdaemon.c (scd_init_default_ctrl): Initialize READER_SLOT to -1.
- * command.c (open_card): Reuse an open slot.
- (reset_notify): Just reset the slot if supported by the reader.
- (do_reset): Factored code from above out.
- (scd_command_handler): Use it for cleanup.
-
- * apdu.h: New pseudo stati SW_HOST_NOT_SUPPORTED,
- SW_HOST_LOCKING_FAILED and SW_HOST_BUSY.
- * iso7816.c (map_sw): Map it.
-
- * ccid-driver.c (ccid_slot_status): Add arg STATUSBITS.
- * apdu.c (apdu_get_status): New.
- (ct_get_status, pcsc_get_status, ocsc_get_status): New stubs.
- (get_status_ccid): New.
- (apdu_reset): New.
- (reset_ct_reader, reset_pcsc_reader, reset_osc_reader): New stubs.
- (reset_ccid_reader): New.
- (apdu_enum_reader): New.
-
- * apdu.c (lock_slot, trylock_slot, unlock_slot): New helpers.
- (new_reader_slot) [USE_GNU_PTH]: Init mutex.
- (apdu_reset, apdu_get_status, apdu_send_le): Run functions
- in locked mode.
-
- * command.c (scd_update_reader_status_file): New.
- * scdaemon.c (handle_tick): Call it.
-
-2004-04-13 Werner Koch <[email protected]>
-
- * scdaemon.c: Convert to a Pth application.
- (handle_signal, ticker_thread, handle_tick): New.
- (main): Fire up the ticker thread in server mode.
-
-2004-03-23 Werner Koch <[email protected]>
-
- * scdaemon.c (main) <gpgconf_list>: Fixed output for pcsc_driver.
-
-2004-03-17 Werner Koch <[email protected]>
-
- * tlv.c (parse_ber_header): Do not check for tag overflow - it
- does not make sense. Simplified the check for length overflow.
-
- * scdaemon.c (main) <gpgconf>: Fixed default value quoting.
-
-2004-03-16 Werner Koch <[email protected]>
-
- * app-dinsig.c: Implemented. Based on app-nks.c and card-dinsig.c
- * app-nks.c (get_length_of_cert): Removed.
- * app-help.c: New.
- (app_help_read_length_of_cert): New. Code taken from above. New
- optional arg R_CERTOFF.
-
- * card-dinsig.c: Removed.
- * card.c (card_get_serial_and_stamp): Do not bind to the old and
- never finsiged card-dinsig.c.
-
- * iso7816.c (iso7816_read_binary): Allow for an NMAX > 254.
-
-2004-03-11 Werner Koch <[email protected]>
-
- * scdaemon.h (out_of_core): Removed. Replaced callers by standard
- gpg_error function.
-
- * apdu.c, iso7816.c, ccid-driver.c [GNUPG_SCD_MAIN_HEADER]: Allow
- to include a header defined by the compiler. This helps us to
- reuse the source in other software.
-
-2004-03-10 Werner Koch <[email protected]>
-
- * iso7816.c (iso7816_read_record): New arg SHORT_EF. Changed all
- callers.
-
-2004-02-18 Werner Koch <[email protected]>
-
- * sc-investigate.c (main): Setup the used character set.
- * scdaemon.c (main): Ditto.
-
- * scdaemon.c (set_debug): New. Add option --debug-level.
- (main): Add option --gpgconf-list.
-
-2004-02-12 Werner Koch <[email protected]>
-
- * Makefile.am: Include cmacros.am for common flags.
-
-2004-01-29 Werner Koch <[email protected]>
-
- * command.c (reset_notify): Release the application context and
- close the reader.
-
-2004-01-28 Werner Koch <[email protected]>
-
- * iso7816.c (iso7816_manage_security_env): New.
- (iso7816_decipher): Add PADIND argument.
-
-2004-01-27 Werner Koch <[email protected]>
-
- * command.c (cmd_readcert, cmd_readkey): Work on a copy of LINE.
-
- * app-common.h (app_ctx_s): Added readcert field.
- * app.c (app_readcert): New.
- * tlv.c (parse_ber_header): Added; taken from libksba.
-
-2004-01-26 Werner Koch <[email protected]>
-
- * card.c (map_sc_err): Use SCD as the error source.
-
- * command.c (open_card): ADD arg NAME to allow requesting a
- specific application. Changed all callers.
- (cmd_serialno): Allow optional argument to select the desired
- application.
-
- * app-nks.c: New.
-
- * scdaemon.h (opt): Add READER_PORT.
- * scdaemon.c (main): Set it here.
- * app.c (app_set_default_reader_port): Removed.
- (select_application): Add NAME arg and figure out a
- default serial number from the GDO. Add SLOT arg and remove all
- reader management.
- (release_application): New.
- (app_write_learn_status): Output an APPTYPE status line.
- * command.c (open_card): Adapt for select_application change.
- * app-openpgp.c (app_select_openpgp): Removed SN and SNLEN args
- and set it directly. Changed all callers.
-
-2004-01-25 Werner Koch <[email protected]>
-
- * iso7816.c (iso7816_select_application): P1 kludge for OpenPGP
- card.
- * app-openpgp.c (find_tlv): Factor out this function to ..
- * tlv.c, tlv.h: .. new.
-
- * scdaemon.h: Introduced app_t and ctrl_t as the new types for APP
- and CTRL.
-
-2004-01-21 Werner Koch <[email protected]>
-
- * apdu.c (apdu_send_le): Treat SW_EOF_REACHED as a warning.
-
-2004-01-20 Werner Koch <[email protected]>
-
- * iso7816.c (iso7816_read_binary): New.
- (iso7816_select_file): New.
- (iso7816_list_directory): New.
-
- * sc-investigate.c: Add option -i.
- (select_app, read_line, interactive_shell): New.
-
-2004-01-16 Werner Koch <[email protected]>
-
- * apdu.h: Add SW_FILE_NOT_FOUND.
- * iso7816.c (map_sw): Map it to GPG_ERR_ENOENT.
- * iso7816.c (iso7816_select_file): New.
-
- * app-dinsig.c: New file w/o any real code yet.
- * Makefile.am (scdaemon_SOURCES,sc_investigate_SOURCES): Add file.
-
- * sc-investigate.c: Add option --disable-ccid.
-
-2003-12-19 Werner Koch <[email protected]>
-
- * apdu.c (apdu_send_le): Send a get_response with the indicated
- length and not the 64 bytes we used for testing.
-
- * app-openpgp.c (verify_chv2, verify_chv3, do_sign): Check the
- minimum length of the passphrase, so that we don't need to
- decrement the retry counter.
-
-2003-12-17 Werner Koch <[email protected]>
-
- * card-p15.c (p15_enum_keypairs): Replaced KRC by RC.
- * card-dinsig.c (dinsig_enum_keypairs): Ditto.
-
-2003-12-16 Werner Koch <[email protected]>
-
- * scdaemon.c (main): Set the prefixes for assuan logging.
-
-2003-11-17 Werner Koch <[email protected]>
-
- * scdaemon.c, scdaemon.h: New options --allow-admin and --deny-admin.
- * app-openpgp.c (verify_chv3): Check it here.
-
-2003-11-12 Werner Koch <[email protected]>
-
- Adjusted for API changes in Libksba.
-
-2003-10-30 Werner Koch <[email protected]>
-
- * apdu.c (close_ct_reader, close_pcsc_reader): Implemented.
- (get_ccid_error_string): New. Not very useful messages, though.
-
-2003-10-25 Werner Koch <[email protected]>
-
- * ccid-driver.c (ccid_open_reader): Return an error if no USB
- devices are found.
-
- * command.c (cmd_genkey, cmd_passwd): Fixed faulty use of
- !spacep().
-
- * apdu.c (apdu_open_reader): Hacks for PC/SC under Windows.
-
-2003-10-20 Werner Koch <[email protected]>
-
- * command.c (cmd_checkpin): New.
- (register_commands): Add command CHECKPIN.
- * app.c (app_check_pin): New.
- * app-openpgp.c (check_against_given_fingerprint): New. Factored
- out that code elsewhere.
- (do_check_pin): New.
-
-2003-10-10 Werner Koch <[email protected]>
-
- * ccid-driver.c (ccid_close_reader): New.
-
- * apdu.c (close_ccid_reader, close_ct_reader, close_csc_reader)
- (close_osc_reader, apdu_close_reader): New. Not all are properly
- implemented yet.
-
-2003-10-09 Werner Koch <[email protected]>
-
- * ccid-driver.c (ccid_transceive): Add T=1 chaining for sending.
-
-2003-10-08 Werner Koch <[email protected]>
-
- * app-openpgp.c (do_getattr): Support SERIALNO and AID.
-
-2003-10-01 Werner Koch <[email protected]>
-
- * ccid-driver.c: Detect GnuPG 1.3 and include appropriate files.
- * apdu.c: Ditto.
- * app-openpgp.c: Ditto.
- * iso7816.c: Ditto.
- (generate_keypair): Renamed to ..
- (do_generate_keypair): .. this.
- * app-common.h [GNUPG_MAJOR_VERSION]: New.
- * iso7816.h [GNUPG_MAJOR_VERSION]: Include cardglue.h
-
-2003-09-30 Werner Koch <[email protected]>
-
- * command.c (cmd_getattr): New command GETATTR.
- * app.c (app_setattr): New.
- (do_getattr): New.
- (do_learn_status): Reimplemented in terms of do_getattr.
-
- * app-openpgp.c (do_change_pin): Make sure CVH1 and CHV2 are
- always synced.
- (verify_chv2, verify_chv3): New. Factored out common code.
- (do_setattr, do_sign, do_auth, do_decipher): Change the names of
- the prompts to match that we have only 2 different PINs.
- (app_select_openpgp): Check whether the card enforced CHV1.
- (convert_sig_counter_value): New. Factor out code from
- get_sig_counter.
-
-2003-09-28 Werner Koch <[email protected]>
-
- * app-openpgp.c (dump_all_do): Use gpg_err_code and not gpg_error.
-
-2003-09-19 Werner Koch <[email protected]>
-
- * ccid-driver.c (parse_ccid_descriptor): New.
- (read_device_info): New.
- (ccid_open_reader): Check that the device has all required features.
-
-2003-09-06 Werner Koch <[email protected]>
-
- * scdaemon.c (main): --pcsc-driver again defaults to pcsclite.
- David Corcoran was so kind to remove the GPL incompatible
- advertisng clause from pcsclite.
- * apdu.c (apdu_open_reader): Actually make pcsc-driver option work.
-
-2003-09-05 Werner Koch <[email protected]>
-
- * ccid-driver.c: More work, data can now actually be retrieved.
- * ccid-driver.c, ccid-driver.h: Alternativley allow use under BSD
- conditions.
-
-2003-09-02 Werner Koch <[email protected]>
-
- * 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 <[email protected]>
-
- * apdu.c (new_reader_slot): Only set 'is_osc' when OpenSC
- is used.
-
-2003-08-25 Werner Koch <[email protected]>
-
- * command.c (cmd_setattr): Use a copy of LINE.
- (cmd_genkey): Use a copy of KEYNO.
- (cmd_passwd): Use a copy of CHVNOSTR.
- (cmd_pksign, cmd_pkauth, cmd_pkdecrypt): s/strdup/xtrystrdup/.
-
-2003-08-19 Werner Koch <[email protected]>
-
- * scdaemon.c, scdaemon.h: New option --pcsc-driver.
- * apdu.c (apdu_open_reader): Use that option here instead of a
- hardcoded one.
-
-2003-08-18 Werner Koch <[email protected]>
-
- * Makefile.am: Add OPENSC_LIBS to all programs.
-
- * scdaemon.c, scdaemon.h: New option --disable-opensc.
- * card.c (card_open): Implement it.
- * apdu.c (open_osc_reader, osc_send_apdu): New.
- (apdu_open_reader) [HAVE_OPENSC]: Use the opensc driver if not
- disabled.
- (error_string) [HAVE_OPENSC]: Use sc_strerror.
- (send_apdu) [HAVE_OPENSC]: Call osc_apdu_send.
-
- * card-p15.c (p15_enum_keypairs, p15_prepare_key): Adjusted for
- libgpg-error.
-
-2003-08-14 Timo Schulz <[email protected]>
-
- * apdu.c (ct_activate_card): Change the code a little to avoid
- problems with other readers.
- * Always use 'dynload.h' instead of 'dlfcn.h'.
-
-2003-08-05 Werner Koch <[email protected]>
-
- * app-openpgp.c (dump_all_do): Don't analyze constructed DOs after
- an error.
-
-2003-08-04 Werner Koch <[email protected]>
-
- * app.c (app_set_default_reader_port): New.
- (select_application): Use it here.
- * scdaemon.c (main): and here.
- * sc-copykeys.c: --reader-port does now take a string.
- * sc-investigate.c, scdaemon.c: Ditto.
- * apdu.c (apdu_open_reader): Ditto. Load pcsclite if no ctapi
- driver is configured. Always include code for ctapi.
- (new_reader_slot): Don't test for already used ports and remove
- port arg.
- (open_pcsc_reader, pcsc_send_apdu, pcsc_error_string): New.
- (apdu_send_le): Changed RC to long to cope with PC/SC.
-
- * scdaemon.c, scdaemon.h: New option --ctapi-driver.
- * sc-investigate.c, sc-copykeys.c: Ditto.
-
-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 c3c603d28..000000000
--- a/scd/Makefile.am
+++ /dev/null
@@ -1,85 +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
-
-bin_PROGRAMS = scdaemon sc-investigate sc-copykeys
-pkglib_PROGRAMS = pcsc-wrapper
-
-AM_CPPFLAGS = -I$(top_srcdir)/intl -I$(top_srcdir)/common
-
-include $(top_srcdir)/am/cmacros.am
-
-AM_CFLAGS = $(OPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \
- $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
-
-
-card_apps = app-openpgp.c app-nks.c app-dinsig.c
-
-scdaemon_SOURCES = \
- scdaemon.c scdaemon.h \
- command.c card.c \
- card-common.h \
- card-p15.c \
- apdu.c apdu.h \
- ccid-driver.c ccid-driver.h \
- iso7816.c iso7816.h \
- tlv.c tlv.h \
- app.c app-common.h app-help.c $(card_apps)
-
-
-scdaemon_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \
- $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(PTH_LIBS) \
- $(KSBA_LIBS) $(LIBASSUAN_LIBS) \
- $(LIBUSB_LIBS) -lgpg-error @INTLLIBS@ -ldl
-
-sc_investigate_SOURCES = \
- sc-investigate.c scdaemon.h \
- apdu.c apdu.h \
- ccid-driver.c ccid-driver.h \
- iso7816.c iso7816.h \
- tlv.c tlv.h \
- atr.c atr.h \
- app.c app-common.h app-help.c $(card_apps)
-
-sc_investigate_LDADD = \
- ../jnlib/libjnlib.a ../common/libcommon.a \
- $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(PTH_LIBS) \
- $(KSBA_LIBS) $(LIBUSB_LIBS) \
- @INTLLIBS@ -lgpg-error -ldl
-
-
-sc_copykeys_SOURCES = \
- sc-copykeys.c scdaemon.h \
- apdu.c apdu.h \
- ccid-driver.c ccid-driver.h \
- iso7816.c iso7816.h \
- tlv.c tlv.h \
- atr.c atr.h \
- app.c app-common.h app-help.c $(card_apps)
-
-sc_copykeys_LDADD = \
- ../jnlib/libjnlib.a ../common/libcommon.a \
- ../common/libsimple-pwquery.a \
- $(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(PTH_LIBS) \
- $(KSBA_LIBS) $(LIBUSB_LIBS) \
- -lgpg-error @INTLLIBS@ -ldl
-
-pcsc_wrapper_SOURCES = pcsc-wrapper.c
-pcsc_wrapper_LDADD = -ldl
-pcsc_wrapper_CFLAGS = \ No newline at end of file
diff --git a/scd/apdu.c b/scd/apdu.c
deleted file mode 100644
index 9742be760..000000000
--- a/scd/apdu.c
+++ /dev/null
@@ -1,1981 +0,0 @@
-/* apdu.c - ISO 7816 APDU functions and low level I/O
- * Copyright (C) 2003, 2004 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>
-#ifdef USE_GNU_PTH
-# include <pth.h>
-# include <unistd.h>
-# include <fcntl.h>
-#endif
-#ifdef HAVE_OPENSC
-# include <opensc/opensc.h>
-#endif
-
-#if defined(GNUPG_SCD_MAIN_HEADER)
-#include GNUPG_SCD_MAIN_HEADER
-#elif GNUPG_MAJOR_VERSION == 1
-/* This is used with GnuPG version < 1.9. The code has been source
- copied from the current GnuPG >= 1.9 and is maintained over
- there. */
-#include "options.h"
-#include "errors.h"
-#include "memory.h"
-#include "util.h"
-#include "i18n.h"
-#include "cardglue.h"
-#else /* GNUPG_MAJOR_VERSION != 1 */
-#include "scdaemon.h"
-#endif /* GNUPG_MAJOR_VERSION != 1 */
-
-#include "apdu.h"
-#include "dynload.h"
-#include "ccid-driver.h"
-
-#ifdef USE_GNU_PTH
-#define NEED_PCSC_WRAPPER 1
-#endif
-
-
-#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). */
-
-
-#ifdef _WIN32
-#define DLSTDCALL __stdcall
-#else
-#define DLSTDCALL
-#endif
-
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
-
-
-/* A structure to collect information pertaining to one reader
- slot. */
-struct reader_table_s {
- int used; /* True if slot is used. */
- 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. */
- struct {
- unsigned long context;
- unsigned long card;
- unsigned long protocol;
-#ifdef NEED_PCSC_WRAPPER
- int req_fd;
- int rsp_fd;
- pid_t pid;
-#endif /*NEED_PCSC_WRAPPER*/
- } pcsc;
-#ifdef HAVE_OPENSC
- int is_osc; /* We are using the OpenSC driver layer. */
- struct {
- struct sc_context *ctx;
- struct sc_card *scard;
- } osc;
-#endif /*HAVE_OPENSC*/
- int status;
- unsigned char atr[33];
- size_t atrlen;
- unsigned int change_counter;
-#ifdef USE_GNU_PTH
- int lock_initialized;
- pth_mutex_t lock;
-#endif
-};
-typedef struct reader_table_s *reader_table_t;
-
-/* A global table to keep track of active readers. */
-static struct reader_table_s reader_table[MAX_READER];
-
-
-/* ct API function pointer. */
-static char (* DLSTDCALL CT_init) (unsigned short ctn, unsigned short Pn);
-static char (* DLSTDCALL 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 (* DLSTDCALL CT_close) (unsigned short ctn);
-
-/* PC/SC constants and function pointer. */
-#define PCSC_SCOPE_USER 0
-#define PCSC_SCOPE_TERMINAL 1
-#define PCSC_SCOPE_SYSTEM 2
-#define PCSC_SCOPE_GLOBAL 3
-
-#define PCSC_PROTOCOL_T0 1
-#define PCSC_PROTOCOL_T1 2
-#define PCSC_PROTOCOL_RAW 4
-
-#define PCSC_SHARE_EXCLUSIVE 1
-#define PCSC_SHARE_SHARED 2
-#define PCSC_SHARE_DIRECT 3
-
-#define PCSC_LEAVE_CARD 0
-#define PCSC_RESET_CARD 1
-#define PCSC_UNPOWER_CARD 2
-#define PCSC_EJECT_CARD 3
-
-struct pcsc_io_request_s {
- unsigned long protocol;
- unsigned long pci_len;
-};
-
-typedef struct pcsc_io_request_s *pcsc_io_request_t;
-
-long (* DLSTDCALL pcsc_establish_context) (unsigned long scope,
- const void *reserved1,
- const void *reserved2,
- unsigned long *r_context);
-long (* DLSTDCALL pcsc_release_context) (unsigned long context);
-long (* DLSTDCALL pcsc_list_readers) (unsigned long context,
- const char *groups,
- char *readers, unsigned long*readerslen);
-long (* DLSTDCALL pcsc_connect) (unsigned long context,
- const char *reader,
- unsigned long share_mode,
- unsigned long preferred_protocols,
- unsigned long *r_card,
- unsigned long *r_active_protocol);
-long (* DLSTDCALL pcsc_disconnect) (unsigned long card,
- unsigned long disposition);
-long (* DLSTDCALL pcsc_status) (unsigned long card,
- char *reader, unsigned long *readerlen,
- unsigned long *r_state,
- unsigned long *r_protocol,
- unsigned char *atr, unsigned long *atrlen);
-long (* DLSTDCALL pcsc_begin_transaction) (unsigned long card);
-long (* DLSTDCALL pcsc_end_transaction) (unsigned long card);
-long (* DLSTDCALL pcsc_transmit) (unsigned long card,
- const pcsc_io_request_t send_pci,
- const unsigned char *send_buffer,
- unsigned long send_len,
- pcsc_io_request_t recv_pci,
- unsigned char *recv_buffer,
- unsigned long *recv_len);
-long (* DLSTDCALL pcsc_set_timeout) (unsigned long context,
- unsigned long timeout);
-
-
-
-
-
-/*
- Helper
- */
-
-
-/* Find an unused reader slot for PORTSTR and put it into the reader
- table. Return -1 on error or the index into the reader table. */
-static int
-new_reader_slot (void)
-{
- int i, reader = -1;
-
- for (i=0; i < MAX_READER; i++)
- {
- if (!reader_table[i].used && reader == -1)
- reader = i;
- }
- if (reader == -1)
- {
- log_error ("new_reader_slot: out of slots\n");
- return -1;
- }
-#ifdef USE_GNU_PTH
- if (!reader_table[reader].lock_initialized)
- {
- if (!pth_mutex_init (&reader_table[reader].lock))
- {
- log_error ("error initializing mutex: %s\n", strerror (errno));
- return -1;
- }
- reader_table[reader].lock_initialized = 1;
- }
-#endif /*USE_GNU_PTH*/
- reader_table[reader].used = 1;
- reader_table[reader].is_ccid = 0;
- reader_table[reader].is_ctapi = 0;
-#ifdef HAVE_OPENSC
- reader_table[reader].is_osc = 0;
-#endif
-#ifdef NEED_PCSC_WRAPPER
- reader_table[reader].pcsc.req_fd = -1;
- reader_table[reader].pcsc.rsp_fd = -1;
- reader_table[reader].pcsc.pid = (pid_t)(-1);
-#endif
- return reader;
-}
-
-
-static void
-dump_reader_status (int reader)
-{
- 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,
- reader_table[reader].status == 1? "Processor ICC present" :
- reader_table[reader].status == 0? "Memory ICC present" :
- "ICC not present" );
- }
- else
- {
- log_info ("reader slot %d: active protocol:", reader);
- if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_T0))
- log_printf (" T0");
- else if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_T1))
- log_printf (" T1");
- else if ((reader_table[reader].pcsc.protocol & PCSC_PROTOCOL_RAW))
- log_printf (" raw");
- log_printf ("\n");
- }
-
- if (reader_table[reader].status != -1)
- {
- log_info ("reader %d: ATR=", reader);
- log_printhex ("", reader_table[reader].atr,
- reader_table[reader].atrlen);
- }
-}
-
-
-
-/*
- ct API Interface
- */
-
-static const char *
-ct_error_string (long 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)
- ; /* FIXME: we should use a more reliable timer than sleep. */
-
- /* 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;
- }
-
- /* 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));
- if (!rc)
- log_printhex (" received data:", buf, buflen);
- 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;
-
- if (port < 0 || port > 0xffff)
- {
- log_error ("open_ct_reader: invalid port %d requested\n", port);
- return -1;
- }
- reader = new_reader_slot ();
- if (reader == -1)
- return reader;
- reader_table[reader].port = port;
-
- 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;
- }
-
- reader_table[reader].is_ctapi = 1;
- dump_reader_status (reader);
- return reader;
-}
-
-static int
-close_ct_reader (int slot)
-{
- CT_close (slot);
- reader_table[slot].used = 0;
- return 0;
-}
-
-static int
-reset_ct_reader (int slot)
-{
- return SW_HOST_NOT_SUPPORTED;
-}
-
-
-static int
-ct_get_status (int slot, unsigned int *status)
-{
- return SW_HOST_NOT_SUPPORTED;
-}
-
-/* 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;
-}
-
-
-
-#ifdef NEED_PCSC_WRAPPER
-static int
-writen (int fd, const void *buf, size_t nbytes)
-{
- size_t nleft = nbytes;
- int nwritten;
-
-/* log_printhex (" writen:", buf, nbytes); */
-
- while (nleft > 0)
- {
-#ifdef USE_GNU_PTH
- nwritten = pth_write (fd, buf, nleft);
-#else
- nwritten = write (fd, buf, nleft);
-#endif
- if (nwritten < 0 && errno == EINTR)
- continue;
- if (nwritten < 0)
- return -1;
- nleft -= nwritten;
- buf = (const char*)buf + nwritten;
- }
- return 0;
-}
-
-/* Read up to BUFLEN bytes from FD and return the number of bytes
- actually read in NREAD. Returns -1 on error or 0 on success. */
-static int
-readn (int fd, void *buf, size_t buflen, size_t *nread)
-{
- size_t nleft = buflen;
- int n;
-/* void *orig_buf = buf; */
-
- while (nleft > 0)
- {
-#ifdef USE_GNU_PTH
- n = pth_read (fd, buf, nleft);
-#else
- n = read (fd, buf, nleft);
-#endif
- if (n < 0 && errno == EINTR)
- continue;
- if (n < 0)
- return -1; /* read error. */
- if (!n)
- break; /* EOF */
- nleft -= n;
- buf = (char*)buf + n;
- }
- if (nread)
- *nread = buflen - nleft;
-
-/* log_printhex (" readn:", orig_buf, *nread); */
-
- return 0;
-}
-#endif /*NEED_PCSC_WRAPPER*/
-
-static const char *
-pcsc_error_string (long err)
-{
- const char *s;
-
- if (!err)
- return "okay";
- if ((err & 0x80100000) != 0x80100000)
- return "invalid PC/SC error code";
- err &= 0xffff;
- switch (err)
- {
- case 0x0002: s = "cancelled"; break;
- case 0x000e: s = "can't dispose"; break;
- case 0x0008: s = "insufficient buffer"; break;
- case 0x0015: s = "invalid ATR"; break;
- case 0x0003: s = "invalid handle"; break;
- case 0x0004: s = "invalid parameter"; break;
- case 0x0005: s = "invalid target"; break;
- case 0x0011: s = "invalid value"; break;
- case 0x0006: s = "no memory"; break;
- case 0x0013: s = "comm error"; break;
- case 0x0001: s = "internal error"; break;
- case 0x0014: s = "unknown error"; break;
- case 0x0007: s = "waited too long"; break;
- case 0x0009: s = "unknown reader"; break;
- case 0x000a: s = "timeout"; break;
- case 0x000b: s = "sharing violation"; break;
- case 0x000c: s = "no smartcard"; break;
- case 0x000d: s = "unknown card"; break;
- case 0x000f: s = "proto mismatch"; break;
- case 0x0010: s = "not ready"; break;
- case 0x0012: s = "system cancelled"; break;
- case 0x0016: s = "not transacted"; break;
- case 0x0017: s = "reader unavailable"; break;
- case 0x0065: s = "unsupported card"; break;
- case 0x0066: s = "unresponsive card"; break;
- case 0x0067: s = "unpowered card"; break;
- case 0x0068: s = "reset card"; break;
- case 0x0069: s = "removed card"; break;
- case 0x006a: s = "inserted card"; break;
- case 0x001f: s = "unsupported feature"; break;
- case 0x0019: s = "PCI too small"; break;
- case 0x001a: s = "reader unsupported"; break;
- case 0x001b: s = "duplicate reader"; break;
- case 0x001c: s = "card unsupported"; break;
- case 0x001d: s = "no service"; break;
- case 0x001e: s = "service stopped"; break;
- default: s = "unknown PC/SC error code"; break;
- }
- return s;
-}
-
-/*
- PC/SC Interface
- */
-
-static int
-open_pcsc_reader (const char *portstr)
-{
-#ifdef NEED_PCSC_WRAPPER
-/* Open the PC/SC reader using the pcsc_wrapper program. This is
- needed to cope with different thread models and other peculiarities
- of libpcsclite. */
- int slot;
- reader_table_t slotp;
- int fd, rp[2], wp[2];
- int n, i;
- pid_t pid;
- size_t len;
- unsigned char msgbuf[9];
- int err;
-
- slot = new_reader_slot ();
- if (slot == -1)
- return -1;
- slotp = reader_table + slot;
-
- /* Fire up the pcsc wrapper. We don't use any fork/exec code from
- the common directy but implement it direclty so that this file
- may still be source copied. */
-
- if (pipe (rp) == -1)
- {
- log_error ("error creating a pipe: %s\n", strerror (errno));
- slotp->used = 0;
- return -1;
- }
- if (pipe (wp) == -1)
- {
- log_error ("error creating a pipe: %s\n", strerror (errno));
- close (rp[0]);
- close (rp[1]);
- slotp->used = 0;
- return -1;
- }
-
- pid = fork ();
- if (pid == -1)
- {
- log_error ("error forking process: %s\n", strerror (errno));
- close (rp[0]);
- close (rp[1]);
- close (wp[0]);
- close (wp[1]);
- slotp->used = 0;
- return -1;
- }
- slotp->pcsc.pid = pid;
-
- if (!pid)
- { /*
- === Child ===
- */
-
- /* Double fork. */
- pid = fork ();
- if (pid == -1)
- _exit (31);
- if (pid)
- _exit (0); /* Immediate exit this parent, so that the child
- gets cleaned up by the init process. */
-
- /* Connect our pipes. */
- if (wp[0] != 0 && dup2 (wp[0], 0) == -1)
- log_fatal ("dup2 stdin failed: %s\n", strerror (errno));
- if (rp[1] != 1 && dup2 (rp[1], 1) == -1)
- log_fatal ("dup2 stdout failed: %s\n", strerror (errno));
-
- /* Send stderr to the bit bucket. */
- fd = open ("/dev/null", O_WRONLY);
- if (fd == -1)
- log_fatal ("can't open `/dev/null': %s", strerror (errno));
- if (fd != 2 && dup2 (fd, 2) == -1)
- log_fatal ("dup2 stderr failed: %s\n", strerror (errno));
-
- /* Close all other files. */
- n = sysconf (_SC_OPEN_MAX);
- if (n < 0)
- n = MAX_OPEN_FDS;
- for (i=3; i < n; i++)
- close(i);
- errno = 0;
-
- execl (GNUPG_LIBDIR "/pcsc-wrapper",
- "pcsc-wrapper",
- "--",
- "1", /* API version */
- opt.pcsc_driver, /* Name of the PC/SC library. */
- NULL);
- _exit (31);
- }
-
- /*
- === Parent ===
- */
- close (wp[0]);
- close (rp[1]);
- slotp->pcsc.req_fd = wp[1];
- slotp->pcsc.rsp_fd = rp[0];
-
- /* Wait for the intermediate child to terminate. */
- while ( (i=pth_waitpid (pid, NULL, 0)) == -1 && errno == EINTR)
- ;
-
- /* Now send the open request. */
- msgbuf[0] = 0x01; /* OPEN command. */
- len = portstr? strlen (portstr):0;
- msgbuf[1] = (len >> 24);
- msgbuf[2] = (len >> 16);
- msgbuf[3] = (len >> 8);
- msgbuf[4] = (len );
- if ( writen (slotp->pcsc.req_fd, msgbuf, 5)
- || (portstr && writen (slotp->pcsc.req_fd, portstr, len)))
- {
- log_error ("error sending PC/SC OPEN request: %s\n",
- strerror (errno));
- goto command_failed;
- }
- /* Read the response. */
- if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
- {
- log_error ("error receiving PC/SC OPEN response: %s\n",
- i? strerror (errno) : "premature EOF");
- goto command_failed;
- }
- len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
- if (msgbuf[0] != 0x81 || len < 4)
- {
- log_error ("invalid response header from PC/SC received\n");
- goto command_failed;
- }
- len -= 4; /* Already read the error code. */
- if (len > DIM (slotp->atr))
- {
- log_error ("PC/SC returned a too large ATR (len=%x)\n", len);
- goto command_failed;
- }
- err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
- if (err)
- {
- log_error ("PC/SC OPEN failed: %s\n", pcsc_error_string (err));
- goto command_failed;
- }
- n = len;
- if ((i=readn (slotp->pcsc.rsp_fd, slotp->atr, n, &len)) || len != n)
- {
- log_error ("error receiving PC/SC OPEN response: %s\n",
- i? strerror (errno) : "premature EOF");
- goto command_failed;
- }
- slotp->atrlen = len;
-
- dump_reader_status (slot);
- return slot;
-
- command_failed:
- close (slotp->pcsc.req_fd);
- close (slotp->pcsc.rsp_fd);
- slotp->pcsc.req_fd = -1;
- slotp->pcsc.rsp_fd = -1;
- kill (slotp->pcsc.pid, SIGTERM);
- slotp->pcsc.pid = (pid_t)(-1);
- slotp->used = 0;
- return -1;
-#else /*!NEED_PCSC_WRAPPER */
- long err;
- int slot;
- char *list = NULL;
- unsigned long nreader, listlen, atrlen;
- char *p;
- unsigned long card_state, card_protocol;
-
- slot = new_reader_slot ();
- if (slot == -1)
- return -1;
-
- err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL,
- &reader_table[slot].pcsc.context);
- if (err)
- {
- log_error ("pcsc_establish_context failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- reader_table[slot].used = 0;
- return -1;
- }
-
- err = pcsc_list_readers (reader_table[slot].pcsc.context,
- NULL, NULL, &nreader);
- if (!err)
- {
- list = xtrymalloc (nreader+1); /* Better add 1 for safety reasons. */
- if (!list)
- {
- log_error ("error allocating memory for reader list\n");
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- return -1;
- }
- err = pcsc_list_readers (reader_table[slot].pcsc.context,
- NULL, list, &nreader);
- }
- if (err)
- {
- log_error ("pcsc_list_readers failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- xfree (list);
- return -1;
- }
-
- listlen = nreader;
- p = list;
- while (nreader)
- {
- if (!*p && !p[1])
- break;
- log_info ("detected reader `%s'\n", p);
- if (nreader < (strlen (p)+1))
- {
- log_error ("invalid response from pcsc_list_readers\n");
- break;
- }
- nreader -= strlen (p)+1;
- p += strlen (p) + 1;
- }
-
- err = pcsc_connect (reader_table[slot].pcsc.context,
- portstr? portstr : list,
- PCSC_SHARE_EXCLUSIVE,
- PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
- &reader_table[slot].pcsc.card,
- &reader_table[slot].pcsc.protocol);
- if (err)
- {
- log_error ("pcsc_connect failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- xfree (list);
- return -1;
- }
-
- atrlen = 32;
- /* (We need to pass a dummy buffer. We use LIST because it ought to
- be large enough.) */
- err = pcsc_status (reader_table[slot].pcsc.card,
- list, &listlen,
- &card_state, &card_protocol,
- reader_table[slot].atr, &atrlen);
- xfree (list);
- if (err)
- {
- log_error ("pcsc_status failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- return -1;
- }
- if (atrlen >= DIM (reader_table[0].atr))
- log_bug ("ATR returned by pcsc_status is too large\n");
- reader_table[slot].atrlen = atrlen;
-/* log_debug ("state from pcsc_status: 0x%lx\n", card_state); */
-/* log_debug ("protocol from pcsc_status: 0x%lx\n", card_protocol); */
-
- dump_reader_status (slot);
- return slot;
-#endif /*!NEED_PCSC_WRAPPER */
-}
-
-
-static int
-pcsc_get_status (int slot, unsigned int *status)
-{
- return SW_HOST_NOT_SUPPORTED;
-}
-
-/* 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: CT API error code. */
-static int
-pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
- unsigned char *buffer, size_t *buflen)
-{
-#ifdef NEED_PCSC_WRAPPER
- long err;
- reader_table_t slotp;
- size_t len, full_len;
- int i, n;
- unsigned char msgbuf[9];
-
- if (DBG_CARD_IO)
- log_printhex (" PCSC_data:", apdu, apdulen);
-
- slotp = reader_table + slot;
-
- if (slotp->pcsc.req_fd == -1
- || slotp->pcsc.rsp_fd == -1
- || slotp->pcsc.pid == (pid_t)(-1) )
- {
- log_error ("pcsc_send_apdu: pcsc-wrapper not running\n");
- return -1;
- }
-
- msgbuf[0] = 0x03; /* TRANSMIT command. */
- len = apdulen;
- msgbuf[1] = (len >> 24);
- msgbuf[2] = (len >> 16);
- msgbuf[3] = (len >> 8);
- msgbuf[4] = (len );
- if ( writen (slotp->pcsc.req_fd, msgbuf, 5)
- || writen (slotp->pcsc.req_fd, apdu, len))
- {
- log_error ("error sending PC/SC TRANSMIT request: %s\n",
- strerror (errno));
- goto command_failed;
- }
-
- /* Read the response. */
- if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
- {
- log_error ("error receiving PC/SC TRANSMIT response: %s\n",
- i? strerror (errno) : "premature EOF");
- goto command_failed;
- }
- len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
- if (msgbuf[0] != 0x81 || len < 4)
- {
- log_error ("invalid response header from PC/SC received\n");
- goto command_failed;
- }
- len -= 4; /* Already read the error code. */
- err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
- if (err)
- {
- log_error ("pcsc_transmit failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- return -1;
- }
-
- full_len = len;
-
- n = *buflen < len ? *buflen : len;
- if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != n)
- {
- log_error ("error receiving PC/SC TRANSMIT response: %s\n",
- i? strerror (errno) : "premature EOF");
- goto command_failed;
- }
- *buflen = n;
-
- full_len -= len;
- if (full_len)
- {
- log_error ("pcsc_send_apdu: provided buffer too short - truncated\n");
- err = -1;
- }
- /* We need to read any rest of the response, to keep the
- protocol runnng. */
- while (full_len)
- {
- unsigned char dummybuf[128];
-
- n = full_len < DIM (dummybuf) ? full_len : DIM (dummybuf);
- if ((i=readn (slotp->pcsc.rsp_fd, dummybuf, n, &len)) || len != n)
- {
- log_error ("error receiving PC/SC TRANSMIT response: %s\n",
- i? strerror (errno) : "premature EOF");
- goto command_failed;
- }
- full_len -= n;
- }
-
- return err;
-
- command_failed:
- close (slotp->pcsc.req_fd);
- close (slotp->pcsc.rsp_fd);
- slotp->pcsc.req_fd = -1;
- slotp->pcsc.rsp_fd = -1;
- kill (slotp->pcsc.pid, SIGTERM);
- slotp->pcsc.pid = (pid_t)(-1);
- slotp->used = 0;
- return -1;
-
-#else /*!NEED_PCSC_WRAPPER*/
-
- long err;
- struct pcsc_io_request_s send_pci;
- unsigned long recv_len;
-
- if (DBG_CARD_IO)
- log_printhex (" PCSC_data:", apdu, apdulen);
-
- if ((reader_table[slot].pcsc.protocol & PCSC_PROTOCOL_T1))
- send_pci.protocol = PCSC_PROTOCOL_T1;
- else
- send_pci.protocol = PCSC_PROTOCOL_T0;
- send_pci.pci_len = sizeof send_pci;
- recv_len = *buflen;
- err = pcsc_transmit (reader_table[slot].pcsc.card,
- &send_pci, apdu, apdulen,
- NULL, buffer, &recv_len);
- *buflen = recv_len;
- if (err)
- log_error ("pcsc_transmit failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
-
- return err? -1:0; /* FIXME: Return appropriate error code. */
-#endif /*!NEED_PCSC_WRAPPER*/
-}
-
-
-static int
-close_pcsc_reader (int slot)
-{
-#ifdef NEED_PCSC_WRAPPER
- long err;
- reader_table_t slotp;
- size_t len;
- int i;
- unsigned char msgbuf[9];
-
- slotp = reader_table + slot;
-
- if (slotp->pcsc.req_fd == -1
- || slotp->pcsc.rsp_fd == -1
- || slotp->pcsc.pid == (pid_t)(-1) )
- {
- log_error ("close_pcsc_reader: pcsc-wrapper not running\n");
- return 0;
- }
-
- msgbuf[0] = 0x02; /* CLOSE command. */
- len = 0;
- msgbuf[1] = (len >> 24);
- msgbuf[2] = (len >> 16);
- msgbuf[3] = (len >> 8);
- msgbuf[4] = (len );
- if ( writen (slotp->pcsc.req_fd, msgbuf, 5) )
- {
- log_error ("error sending PC/SC CLOSE request: %s\n",
- strerror (errno));
- goto command_failed;
- }
-
- /* Read the response. */
- if ((i=readn (slotp->pcsc.rsp_fd, msgbuf, 9, &len)) || len != 9)
- {
- log_error ("error receiving PC/SC CLOSE response: %s\n",
- i? strerror (errno) : "premature EOF");
- goto command_failed;
- }
- len = (msgbuf[1] << 24) | (msgbuf[2] << 16) | (msgbuf[3] << 8 ) | msgbuf[4];
- if (msgbuf[0] != 0x81 || len < 4)
- {
- log_error ("invalid response header from PC/SC received\n");
- goto command_failed;
- }
- len -= 4; /* Already read the error code. */
- err = (msgbuf[5] << 24) | (msgbuf[6] << 16) | (msgbuf[7] << 8 ) | msgbuf[8];
- if (err)
- log_error ("pcsc_close failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
-
- /* We will the wrapper in any case - errors are merely
- informational. */
-
- command_failed:
- close (slotp->pcsc.req_fd);
- close (slotp->pcsc.rsp_fd);
- slotp->pcsc.req_fd = -1;
- slotp->pcsc.rsp_fd = -1;
- kill (slotp->pcsc.pid, SIGTERM);
- slotp->pcsc.pid = (pid_t)(-1);
- slotp->used = 0;
- return 0;
-
-#else /*!NEED_PCSC_WRAPPER*/
-
- pcsc_release_context (reader_table[slot].pcsc.context);
- reader_table[slot].used = 0;
- return 0;
-#endif /*!NEED_PCSC_WRAPPER*/
-}
-
-static int
-reset_pcsc_reader (int slot)
-{
- return SW_HOST_NOT_SUPPORTED;
-}
-
-
-
-
-
-#ifdef HAVE_LIBUSB
-/*
- Internal CCID driver interface.
- */
-
-static const char *
-get_ccid_error_string (long err)
-{
- if (!err)
- return "okay";
- else
- return "unknown CCID error";
-}
-
-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;
-}
-
-static int
-close_ccid_reader (int slot)
-{
- ccid_close_reader (reader_table[slot].ccid.handle);
- reader_table[slot].used = 0;
- return 0;
-}
-
-
-static int
-reset_ccid_reader (int slot)
-{
- int err;
- reader_table_t slotp = reader_table + slot;
- unsigned char atr[33];
- size_t atrlen;
-
- err = ccid_get_atr (slotp->ccid.handle, atr, sizeof atr, &atrlen);
- if (err)
- return -1;
- /* If the reset was successful, update the ATR. */
- assert (sizeof slotp->atr >= sizeof atr);
- slotp->atrlen = atrlen;
- memcpy (slotp->atr, atr, atrlen);
- dump_reader_status (slot);
- return 0;
-}
-
-
-static int
-get_status_ccid (int slot, unsigned int *status)
-{
- int rc;
- int bits;
-
- rc = ccid_slot_status (reader_table[slot].ccid.handle, &bits);
- if (rc)
- return -1;
-
- if (bits == 0)
- *status = 1|2|4;
- else if (bits == 1)
- *status = 2;
- else
- *status = 0;
-
- return 0;
-}
-
-
-/* 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
-/*
- OpenSC Interface.
-
- This uses the OpenSC primitives to send APDUs. We need this
- because we can't mix OpenSC and native (i.e. ctAPI or PC/SC)
- access to a card for resource conflict reasons.
- */
-
-static int
-open_osc_reader (int portno)
-{
- int err;
- int slot;
- reader_table_t slotp;
-
- slot = new_reader_slot ();
- if (slot == -1)
- return -1;
- slotp = reader_table + slot;
-
- err = sc_establish_context (&slotp->osc.ctx, "scdaemon");
- if (err)
- {
- log_error ("failed to establish SC context: %s\n", sc_strerror (err));
- slotp->used = 0;
- return -1;
- }
- if (portno < 0 || portno >= slotp->osc.ctx->reader_count)
- {
- log_error ("no card reader available\n");
- sc_release_context (slotp->osc.ctx);
- slotp->used = 0;
- return -1;
- }
-
- /* Redirect to our logging facility. */
- slotp->osc.ctx->error_file = log_get_stream ();
- slotp->osc.ctx->debug = opt.debug_sc;
- slotp->osc.ctx->debug_file = log_get_stream ();
-
- if (sc_detect_card_presence (slotp->osc.ctx->reader[portno], 0) != 1)
- {
- log_error ("no card present\n");
- sc_release_context (slotp->osc.ctx);
- slotp->used = 0;
- return -1;
- }
-
- /* We want the standard ISO driver. */
- /*FIXME: OpenSC does not like "iso7816", so we use EMV for now. */
- err = sc_set_card_driver(slotp->osc.ctx, "emv");
- if (err)
- {
- log_error ("failed to select the iso7816 driver: %s\n",
- sc_strerror (err));
- sc_release_context (slotp->osc.ctx);
- slotp->used = 0;
- return -1;
- }
-
- /* Now connect the card and hope that OpenSC won't try to be too
- smart. */
- err = sc_connect_card (slotp->osc.ctx->reader[portno], 0,
- &slotp->osc.scard);
- if (err)
- {
- log_error ("failed to connect card in reader %d: %s\n",
- portno, sc_strerror (err));
- sc_release_context (slotp->osc.ctx);
- slotp->used = 0;
- return -1;
- }
- if (opt.verbose)
- log_info ("connected to card in opensc reader %d using driver `%s'\n",
- portno, slotp->osc.scard->driver->name);
-
- err = sc_lock (slotp->osc.scard);
- if (err)
- {
- log_error ("can't lock card in reader %d: %s\n",
- portno, sc_strerror (err));
- sc_disconnect_card (slotp->osc.scard, 0);
- sc_release_context (slotp->osc.ctx);
- slotp->used = 0;
- return -1;
- }
-
- if (slotp->osc.scard->atr_len >= DIM (slotp->atr))
- log_bug ("ATR returned by opensc is too large\n");
- slotp->atrlen = slotp->osc.scard->atr_len;
- memcpy (slotp->atr, slotp->osc.scard->atr, slotp->atrlen);
-
- slotp->is_osc = 1;
-
- dump_reader_status (slot);
- return slot;
-}
-
-
-static int
-close_osc_reader (int slot)
-{
- /* FIXME: Implement. */
- reader_table[slot].used = 0;
- return 0;
-}
-
-static int
-reset_osc_reader (int slot)
-{
- return SW_HOST_NOT_SUPPORTED;
-}
-
-
-static int
-osc_get_status (int slot, unsigned int *status)
-{
- return SW_HOST_NOT_SUPPORTED;
-}
-
-
-/* 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: OpenSC error code. */
-static int
-osc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
- unsigned char *buffer, size_t *buflen)
-{
- long err;
- struct sc_apdu a;
- unsigned char data[SC_MAX_APDU_BUFFER_SIZE];
- unsigned char result[SC_MAX_APDU_BUFFER_SIZE];
-
- if (DBG_CARD_IO)
- log_printhex (" APDU_data:", apdu, apdulen);
-
- if (apdulen < 4)
- {
- log_error ("osc_send_apdu: APDU is too short\n");
- return SC_ERROR_CMD_TOO_SHORT;
- }
-
- memset(&a, 0, sizeof a);
- a.cla = *apdu++;
- a.ins = *apdu++;
- a.p1 = *apdu++;
- a.p2 = *apdu++;
- apdulen -= 4;
-
- if (!apdulen)
- a.cse = SC_APDU_CASE_1;
- else if (apdulen == 1)
- {
- a.le = *apdu? *apdu : 256;
- apdu++; apdulen--;
- a.cse = SC_APDU_CASE_2_SHORT;
- }
- else
- {
- a.lc = *apdu++; apdulen--;
- if (apdulen < a.lc)
- {
- log_error ("osc_send_apdu: APDU shorter than specified in Lc\n");
- return SC_ERROR_CMD_TOO_SHORT;
-
- }
- memcpy(data, apdu, a.lc);
- apdu += a.lc; apdulen -= a.lc;
-
- a.data = data;
- a.datalen = a.lc;
-
- if (!apdulen)
- a.cse = SC_APDU_CASE_3_SHORT;
- else
- {
- a.le = *apdu? *apdu : 256;
- apdu++; apdulen--;
- if (apdulen)
- {
- log_error ("osc_send_apdu: APDU larger than specified\n");
- return SC_ERROR_CMD_TOO_LONG;
- }
- a.cse = SC_APDU_CASE_4_SHORT;
- }
- }
-
- a.resp = result;
- a.resplen = DIM(result);
-
- err = sc_transmit_apdu (reader_table[slot].osc.scard, &a);
- if (err)
- {
- log_error ("sc_apdu_transmit failed: %s\n", sc_strerror (err));
- return err;
- }
-
- if (*buflen < 2 || a.resplen > *buflen - 2)
- {
- log_error ("osc_send_apdu: provided buffer too short to store result\n");
- return SC_ERROR_BUFFER_TOO_SMALL;
- }
- memcpy (buffer, a.resp, a.resplen);
- buffer[a.resplen] = a.sw1;
- buffer[a.resplen+1] = a.sw2;
- *buflen = a.resplen + 2;
- return 0;
-}
-
-#endif /* HAVE_OPENSC */
-
-
-
-/*
- Driver Access
- */
-
-
-static int
-lock_slot (int slot)
-{
-#ifdef USE_GNU_PTH
- if (!pth_mutex_acquire (&reader_table[slot].lock, 0, NULL))
- {
- log_error ("failed to acquire apdu lock: %s\n", strerror (errno));
- return SW_HOST_LOCKING_FAILED;
- }
-#endif /*USE_GNU_PTH*/
- return 0;
-}
-
-static int
-trylock_slot (int slot)
-{
-#ifdef USE_GNU_PTH
- if (!pth_mutex_acquire (&reader_table[slot].lock, TRUE, NULL))
- {
- if (errno == EBUSY)
- return SW_HOST_BUSY;
- log_error ("failed to acquire apdu lock: %s\n", strerror (errno));
- return SW_HOST_LOCKING_FAILED;
- }
-#endif /*USE_GNU_PTH*/
- return 0;
-}
-
-static void
-unlock_slot (int slot)
-{
-#ifdef USE_GNU_PTH
- if (!pth_mutex_release (&reader_table[slot].lock))
- log_error ("failed to release apdu lock: %s\n", strerror (errno));
-#endif /*USE_GNU_PTH*/
-}
-
-
-/* Open the reader and return an internal slot number or -1 on
- error. If PORTSTR is NULL we default to a suitable port (for ctAPI:
- the first USB reader. For PC/SC the first listed reader). If
- OpenSC support is compiled in, we first try to use OpenSC. */
-int
-apdu_open_reader (const char *portstr)
-{
- 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 /* HAVE_LIBUSB */
-
-#ifdef HAVE_OPENSC
- if (!opt.disable_opensc)
- {
- int port = portstr? atoi (portstr) : 0;
-
- return open_osc_reader (port);
- }
-#endif /* HAVE_OPENSC */
-
-
- if (opt.ctapi_driver && *opt.ctapi_driver)
- {
- int port = portstr? atoi (portstr) : 32768;
-
- if (!ct_api_loaded)
- {
- void *handle;
-
- handle = dlopen (opt.ctapi_driver, RTLD_LAZY);
- if (!handle)
- {
- log_error ("apdu_open_reader: failed to open driver: %s\n",
- 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 CT-API driver\n");
- dlclose (handle);
- return -1;
- }
- ct_api_loaded = 1;
- }
- return open_ct_reader (port);
- }
-
-
- /* No ctAPI configured, so lets try the PC/SC API */
- if (!pcsc_api_loaded)
- {
-#ifndef NEED_PCSC_WRAPPER
- void *handle;
-
- handle = dlopen (opt.pcsc_driver, RTLD_LAZY);
- if (!handle)
- {
- log_error ("apdu_open_reader: failed to open driver `%s': %s\n",
- opt.pcsc_driver, dlerror ());
- return -1;
- }
-
- pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
- pcsc_release_context = dlsym (handle, "SCardReleaseContext");
- pcsc_list_readers = dlsym (handle, "SCardListReaders");
-#ifdef _WIN32
- if (!pcsc_list_readers)
- pcsc_list_readers = dlsym (handle, "SCardListReadersA");
-#endif
- pcsc_connect = dlsym (handle, "SCardConnect");
-#ifdef _WIN32
- if (!pcsc_connect)
- pcsc_connect = dlsym (handle, "SCardConnectA");
-#endif
- pcsc_disconnect = dlsym (handle, "SCardDisconnect");
- pcsc_status = dlsym (handle, "SCardStatus");
-#ifdef _WIN32
- if (!pcsc_status)
- pcsc_status = dlsym (handle, "SCardStatusA");
-#endif
- pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
- pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
- pcsc_transmit = dlsym (handle, "SCardTransmit");
- pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
-
- if (!pcsc_establish_context
- || !pcsc_release_context
- || !pcsc_list_readers
- || !pcsc_connect
- || !pcsc_disconnect
- || !pcsc_status
- || !pcsc_begin_transaction
- || !pcsc_end_transaction
- || !pcsc_transmit
- /* || !pcsc_set_timeout */)
- {
- /* Note that set_timeout is currently not used and also not
- available under Windows. */
- log_error ("apdu_open_reader: invalid PC/SC driver "
- "(%d%d%d%d%d%d%d%d%d%d)\n",
- !!pcsc_establish_context,
- !!pcsc_release_context,
- !!pcsc_list_readers,
- !!pcsc_connect,
- !!pcsc_disconnect,
- !!pcsc_status,
- !!pcsc_begin_transaction,
- !!pcsc_end_transaction,
- !!pcsc_transmit,
- !!pcsc_set_timeout );
- dlclose (handle);
- return -1;
- }
-#endif /*!NEED_PCSC_WRAPPER*/
- pcsc_api_loaded = 1;
- }
-
- return open_pcsc_reader (portstr);
-}
-
-
-int
-apdu_close_reader (int slot)
-{
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
- if (reader_table[slot].is_ctapi)
- return close_ct_reader (slot);
-#ifdef HAVE_LIBUSB
- else if (reader_table[slot].is_ccid)
- return close_ccid_reader (slot);
-#endif
-#ifdef HAVE_OPENSC
- else if (reader_table[slot].is_osc)
- return close_osc_reader (slot);
-#endif
- else
- return close_pcsc_reader (slot);
-}
-
-/* Enumerate all readers and return information on whether this reader
- is in use. The caller should start with SLOT set to 0 and
- increment it with each call until an error is returned. */
-int
-apdu_enum_reader (int slot, int *used)
-{
- if (slot < 0 || slot >= MAX_READER)
- return SW_HOST_NO_DRIVER;
- *used = reader_table[slot].used;
- return 0;
-}
-
-/* Do a reset for the card in reader at SLOT. */
-int
-apdu_reset (int slot)
-{
- int sw;
-
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
-
- if ((sw = lock_slot (slot)))
- return sw;
-
- if (reader_table[slot].is_ctapi)
- sw = reset_ct_reader (slot);
-#ifdef HAVE_LIBUSB
- else if (reader_table[slot].is_ccid)
- sw = reset_ccid_reader (slot);
-#endif
-#ifdef HAVE_OPENSC
- else if (reader_table[slot].is_osc)
- sw = reset_osc_reader (slot);
-#endif
- else
- sw = reset_pcsc_reader (slot);
-
- unlock_slot (slot);
- return sw;
-}
-
-
-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, long rc)
-{
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return "[invalid slot]";
- if (reader_table[slot].is_ctapi)
- return ct_error_string (rc);
-#ifdef HAVE_LIBUSB
- else if (reader_table[slot].is_ccid)
- return get_ccid_error_string (rc);
-#endif
-#ifdef HAVE_OPENSC
- else if (reader_table[slot].is_osc)
- return sc_strerror (rc);
-#endif
- else
- return pcsc_error_string (rc);
-}
-
-
-/* Retrieve the status for SLOT. The function does obnly wait fot the
- card to become available if HANG is set to true. On success the
- bits in STATUS will be set to
-
- bit 0 = card present and usable
- bit 1 = card present
- bit 2 = card active
- bit 3 = card access locked [not yet implemented]
-
- For must application, tetsing bit 0 is sufficient.
-
- CHANGED will receive the value of the counter tracking the number
- of card insertions. This value may be used to detect a card
- change.
-*/
-int
-apdu_get_status (int slot, int hang,
- unsigned int *status, unsigned int *changed)
-{
- int sw;
- unsigned int s;
-
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
-
- if ((sw = hang? lock_slot (slot) : trylock_slot (slot)))
- return sw;
-
- if (reader_table[slot].is_ctapi)
- sw = ct_get_status (slot, &s);
-#ifdef HAVE_LIBUSB
- else if (reader_table[slot].is_ccid)
- sw = get_status_ccid (slot, &s);
-#endif
-#ifdef HAVE_OPENSC
- else if (reader_table[slot].is_osc)
- sw = osc_get_status (slot, &s);
-#endif
- else
- sw = pcsc_get_status (slot, &s);
-
- unlock_slot (slot);
-
- if (sw)
- return sw;
-
- if (status)
- *status = s;
- if (changed)
- *changed = reader_table[slot].change_counter;
- return 0;
-}
-
-
-/* Dispatcher for the actual send_apdu function. Note, that this
- function should be called in locked state. */
-static int
-send_apdu (int slot, unsigned char *apdu, size_t apdulen,
- unsigned char *buffer, size_t *buflen)
-{
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
- if (reader_table[slot].is_ctapi)
- 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
- else if (reader_table[slot].is_osc)
- return osc_send_apdu (slot, apdu, apdulen, buffer, buflen);
-#endif
- else
- return pcsc_send_apdu (slot, apdu, apdulen, buffer, buflen);
-}
-
-/* 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)
-{
-#define RESULTLEN 256
- unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in
- the driver. */
- size_t resultlen;
- unsigned char apdu[5+256+1];
- size_t apdulen;
- int sw;
- long rc; /* we need a long here due to PC/SC. */
-
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
-
- 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;
-
- if ((sw = lock_slot (slot)))
- return sw;
-
- 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);
- resultlen = RESULTLEN;
- 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));
- unlock_slot (slot);
- 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 || sw == SW_EOF_REACHED)
- {
- if (retbuf)
- {
- *retbuf = xtrymalloc (resultlen? resultlen : 1);
- if (!*retbuf)
- {
- unlock_slot (slot);
- 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)
- {
- unlock_slot (slot);
- return SW_HOST_OUT_OF_CORE;
- }
- assert (resultlen < bufsize);
- memcpy (p, result, resultlen);
- p += resultlen;
- }
-
- do
- {
- int len = (sw & 0x00ff);
-
- if (DBG_CARD_IO)
- 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++] = len;
- memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
- resultlen = RESULTLEN;
- 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));
- unlock_slot (slot);
- 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
- || sw == SW_EOF_REACHED )
- {
- if (retbuf && resultlen)
- {
- if (p - *retbuf + resultlen > bufsize)
- {
- bufsize += resultlen > 4096? resultlen: 4096;
- tmp = xtryrealloc (*retbuf, bufsize);
- if (!tmp)
- {
- unlock_slot (slot);
- 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;
- }
- }
-
- unlock_slot (slot);
-
- if (DBG_CARD_IO && retbuf && sw == SW_SUCCESS)
- log_printhex (" dump: ", *retbuf, *retbuflen);
-
- return sw;
-#undef RESULTLEN
-}
-
-/* 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 f74bab7fe..000000000
--- a/scd/apdu.h
+++ /dev/null
@@ -1,85 +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_EOF_REACHED = 0x6282,
- SW_EEPROM_FAILURE = 0x6581,
- SW_WRONG_LENGTH = 0x6700,
- SW_CHV_WRONG = 0x6982,
- SW_CHV_BLOCKED = 0x6983,
- SW_USE_CONDITIONS = 0x6985,
- SW_BAD_PARAMETER = 0x6a80, /* (in the data field) */
- SW_NOT_SUPPORTED = 0x6a81,
- SW_FILE_NOT_FOUND = 0x6a82,
- SW_RECORD_NOT_FOUND = 0x6a83,
- 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,
- SW_HOST_NO_DRIVER = 0x10004,
- SW_HOST_NOT_SUPPORTED = 0x10005,
- SW_HOST_LOCKING_FAILED= 0x10006,
- SW_HOST_BUSY = 0x10007
-};
-
-
-
-/* Note , that apdu_open_reader returns no status word but -1 on error. */
-int apdu_open_reader (const char *portstr);
-int apdu_close_reader (int slot);
-int apdu_enum_reader (int slot, int *used);
-unsigned char *apdu_get_atr (int slot, size_t *atrlen);
-
-
-/* The apdu send functions do return status words. */
-int apdu_reset (int slot);
-int apdu_get_status (int slot, int hang,
- unsigned int *status, unsigned int *changed);
-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 c61bcca60..000000000
--- a/scd/app-common.h
+++ /dev/null
@@ -1,170 +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
-
-#if GNUPG_MAJOR_VERSION != 1
-#include <ksba.h>
-#endif
-
-struct app_local_s; /* Defined by all app-*.c. */
-
-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. */
- const char *apptype;
- unsigned int card_version;
- int did_chv1;
- int force_chv1; /* True if the card does not cache CHV1. */
- int did_chv2;
- int did_chv3;
- struct app_local_s *app_local; /* Local to the application. */
- struct {
- void (*deinit) (app_t app);
- int (*learn_status) (app_t app, ctrl_t ctrl);
- int (*readcert) (app_t app, const char *certid,
- unsigned char **cert, size_t *certlen);
- int (*getattr) (app_t app, ctrl_t ctrl, const char *name);
- int (*setattr) (app_t app, const char *name,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const unsigned char *value, size_t valuelen);
- int (*sign) (app_t 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_t 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_t 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_t app, ctrl_t ctrl,
- const char *keynostr, unsigned int flags,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
- int (*change_pin) (app_t app, ctrl_t ctrl,
- const char *chvnostr, int reset_mode,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
- int (*check_pin) (app_t app, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg);
- } fnc;
-
-};
-
-#if GNUPG_MAJOR_VERSION == 1
-int app_select_openpgp (app_t app);
-int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
-#else
-/*-- app-help.c --*/
-gpg_error_t app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip);
-size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
-
-
-/*-- app.c --*/
-app_t select_application (ctrl_t ctrl, int slot, const char *name);
-void release_application (app_t app);
-int app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp);
-int app_write_learn_status (app_t app, ctrl_t ctrl);
-int app_readcert (app_t app, const char *certid,
- unsigned char **cert, size_t *certlen);
-int app_getattr (app_t app, ctrl_t ctrl, const char *name);
-int app_setattr (app_t app, const char *name,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg,
- const unsigned char *value, size_t valuelen);
-int app_sign (app_t 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_t 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_t 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_t app, ctrl_t ctrl,
- const char *keynostr, unsigned int flags,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
-int app_get_challenge (app_t app, size_t nbytes, unsigned char *buffer);
-int app_change_pin (app_t app, ctrl_t ctrl,
- const char *chvnostr, int reset_mode,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
-int app_check_pin (app_t app, const char *keyidstr,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg);
-
-
-/*-- app-openpgp.c --*/
-int app_select_openpgp (app_t app);
-
-int app_openpgp_cardinfo (app_t app,
- char **serialno,
- char **disp_name,
- char **pubkey_url,
- unsigned char **fpr1,
- unsigned char **fpr2,
- unsigned char **fpr3);
-int app_openpgp_storekey (app_t 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_t app, int keyno,
- unsigned char **m, size_t *mlen,
- unsigned char **e, size_t *elen);
-/*-- app-nks.c --*/
-int app_select_nks (app_t app);
-
-/*-- app-dinsig.c --*/
-int app_select_dinsig (app_t app);
-
-
-#endif
-
-
-
-#endif /*GNUPG_SCD_APP_COMMON_H*/
-
-
-
diff --git a/scd/app-dinsig.c b/scd/app-dinsig.c
deleted file mode 100644
index 38fbc79ee..000000000
--- a/scd/app-dinsig.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/* app-dinsig.c - The DINSIG (DIN V 66291-1) card application.
- * Copyright (C) 2002, 2004 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 card 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 user 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.
-*/
-
-
-
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <time.h>
-
-#include "scdaemon.h"
-
-#include "iso7816.h"
-#include "app-common.h"
-#include "tlv.h"
-
-
-static int
-do_learn_status (app_t app, ctrl_t ctrl)
-{
- gpg_error_t err;
- char ct_buf[100], id_buf[100];
- char hexkeygrip[41];
- size_t len, certoff;
- unsigned char *der;
- size_t derlen;
- ksba_cert_t cert;
- int fid;
-
- /* Return the certificate of the card holder. */
- fid = 0xC000;
- len = app_help_read_length_of_cert (app->slot, fid, &certoff);
- if (!len)
- return 0; /* Card has not been personalized. */
-
- sprintf (ct_buf, "%d", 101);
- sprintf (id_buf, "DINSIG.%04X", fid);
- send_status_info (ctrl, "CERTINFO",
- ct_buf, strlen (ct_buf),
- id_buf, strlen (id_buf),
- NULL, (size_t)0);
-
- /* Now we need to read the certificate, so that we can get the
- public key out of it. */
- err = iso7816_read_binary (app->slot, certoff, len-certoff, &der, &derlen);
- if (err)
- {
- log_info ("error reading entire certificate from FID 0x%04X: %s\n",
- fid, gpg_strerror (err));
- return 0;
- }
-
- err = ksba_cert_new (&cert);
- if (err)
- {
- xfree (der);
- return err;
- }
- err = ksba_cert_init_from_mem (cert, der, derlen);
- xfree (der); der = NULL;
- if (err)
- {
- log_error ("failed to parse the certificate at FID 0x%04X: %s\n",
- fid, gpg_strerror (err));
- ksba_cert_release (cert);
- return err;
- }
- err = app_help_get_keygrip_string (cert, hexkeygrip);
- if (err)
- {
- log_error ("failed to calculate the keygrip for FID 0x%04X\n", fid);
- ksba_cert_release (cert);
- return gpg_error (GPG_ERR_CARD);
- }
- ksba_cert_release (cert);
-
- sprintf (id_buf, "DINSIG.%04X", fid);
- send_status_info (ctrl, "KEYPAIRINFO",
- hexkeygrip, 40,
- id_buf, strlen (id_buf),
- NULL, (size_t)0);
- return 0;
-}
-
-
-
-
-/* Read the certificate with id CERTID (as returned by learn_status in
- the CERTINFO status lines) and return it in the freshly allocated
- buffer put into CERT and the length of the certificate put into
- CERTLEN.
-
- FIXME: This needs some cleanups and caching with do_learn_status.
-*/
-static int
-do_readcert (app_t app, const char *certid,
- unsigned char **cert, size_t *certlen)
-{
- int fid;
- gpg_error_t err;
- unsigned char *buffer;
- const unsigned char *p;
- size_t buflen, n;
- int class, tag, constructed, ndef;
- size_t totobjlen, objlen, hdrlen;
- int rootca = 0;
-
- *cert = NULL;
- *certlen = 0;
- if (strncmp (certid, "DINSIG.", 7) )
- return gpg_error (GPG_ERR_INV_ID);
- certid += 7;
- if (!hexdigitp (certid) || !hexdigitp (certid+1)
- || !hexdigitp (certid+2) || !hexdigitp (certid+3)
- || certid[4])
- return gpg_error (GPG_ERR_INV_ID);
- fid = xtoi_4 (certid);
- if (fid != 0xC000 )
- return gpg_error (GPG_ERR_NOT_FOUND);
-
- /* Read the entire file. fixme: This could be optimized by first
- reading the header to figure out how long the certificate
- actually is. */
- err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
- if (err)
- {
- log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
- return err;
- }
-
- err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
- if (err)
- {
- log_error ("error reading certificate from FID 0x%04X: %s\n",
- fid, gpg_strerror (err));
- return err;
- }
-
- if (!buflen || *buffer == 0xff)
- {
- log_info ("no certificate contained in FID 0x%04X\n", fid);
- err = gpg_error (GPG_ERR_NOT_FOUND);
- goto leave;
- }
-
- /* Now figure something out about the object. */
- p = buffer;
- n = buflen;
- err = parse_ber_header (&p, &n, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (err)
- goto leave;
- if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed )
- ;
- else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed )
- rootca = 1;
- else
- return gpg_error (GPG_ERR_INV_OBJ);
- totobjlen = objlen + hdrlen;
- assert (totobjlen <= buflen);
-
- err = parse_ber_header (&p, &n, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (err)
- goto leave;
-
- if (rootca)
- ;
- else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
- {
- const unsigned char *save_p;
-
- /* The certificate seems to be contained in a userCertificate
- container. Skip this and assume the following sequence is
- the certificate. */
- if (n < objlen)
- {
- err = gpg_error (GPG_ERR_INV_OBJ);
- goto leave;
- }
- p += objlen;
- n -= objlen;
- save_p = p;
- err = parse_ber_header (&p, &n, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (err)
- goto leave;
- if ( !(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed) )
- return gpg_error (GPG_ERR_INV_OBJ);
- totobjlen = objlen + hdrlen;
- assert (save_p + totobjlen <= buffer + buflen);
- memmove (buffer, save_p, totobjlen);
- }
-
- *cert = buffer;
- buffer = NULL;
- *certlen = totobjlen;
-
- leave:
- xfree (buffer);
- return err;
-}
-
-
-/* Verify the PIN if required. */
-static int
-verify_pin (app_t app,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- if (!app->did_chv1 || app->force_chv1 )
- {
- char *pinvalue;
- int rc;
-
- rc = pincb (pincb_arg, "PIN", &pinvalue);
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- /* We require the PIN to be at least 6 and at max 8 bytes.
- According to the specs, this should all be ASCII but we don't
- check this. */
- if (strlen (pinvalue) < 6)
- {
- log_error ("PIN is too short; minimum length is 6\n");
- xfree (pinvalue);
- return gpg_error (GPG_ERR_BAD_PIN);
- }
- else if (strlen (pinvalue) > 8)
- {
- log_error ("PIN is too large; maximum length is 8\n");
- xfree (pinvalue);
- return gpg_error (GPG_ERR_BAD_PIN);
- }
-
- rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
- if (rc)
- {
- log_error ("verify PIN failed\n");
- xfree (pinvalue);
- return rc;
- }
- app->did_chv1 = 1;
- xfree (pinvalue);
- }
-
- return 0;
-}
-
-
-
-/* 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;
- that callback should return the PIN in an allocated buffer and
- store that in the 3rd argument. */
-static int
-do_sign (app_t 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;
- int fid;
- unsigned char data[35]; /* Must be large enough for a SHA-1 digest
- + the largest OID _prefix above. */
-
- if (!keyidstr || !*keyidstr)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (indatalen != 20 && indatalen != 16 && indatalen != 35)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- /* Check that the provided ID is vaid. This is not really needed
- but we do it to to enforce correct usage by the caller. */
- if (strncmp (keyidstr, "DINSIG.", 7) )
- return gpg_error (GPG_ERR_INV_ID);
- keyidstr += 7;
- if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
- || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
- || keyidstr[4])
- return gpg_error (GPG_ERR_INV_ID);
- fid = xtoi_4 (keyidstr);
- if (fid != 0xC000)
- return gpg_error (GPG_ERR_NOT_FOUND);
-
- /* Prepare the DER object from INDATA. */
- if (indatalen == 35)
- {
- /* Alright, the caller was so kind to send us an already
- prepared DER object. Check that it is what we want and that
- it matches the hash algorithm. */
- if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15))
- ;
- else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15))
- ;
- else
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
- memcpy (data, indata, indatalen);
- }
- else
- {
- 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);
- }
-
- rc = verify_pin (app, pincb, pincb_arg);
- if (!rc)
- rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
- return rc;
-}
-
-
-
-/* Select the DINSIG application on the card in SLOT. This function
- must be used before any other DINSIG application functions. */
-int
-app_select_dinsig (APP app)
-{
- static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x66, 0x01 };
- int slot = app->slot;
- int rc;
-
- rc = iso7816_select_application (slot, aid, sizeof aid);
- if (!rc)
- {
- app->apptype = "DINSIG";
-
- app->fnc.learn_status = do_learn_status;
- app->fnc.readcert = do_readcert;
- app->fnc.getattr = NULL;
- app->fnc.setattr = NULL;
- app->fnc.genkey = NULL;
- app->fnc.sign = do_sign;
- app->fnc.auth = NULL;
- app->fnc.decipher = NULL;
- app->fnc.change_pin = NULL;
- app->fnc.check_pin = NULL;
-
- app->force_chv1 = 1;
- }
-
- return rc;
-}
diff --git a/scd/app-help.c b/scd/app-help.c
deleted file mode 100644
index 1c3c52b15..000000000
--- a/scd/app-help.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/* app-help.c - Application helper functions
- * Copyright (C) 2004 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 "scdaemon.h"
-#include "app-common.h"
-#include "iso7816.h"
-#include "tlv.h"
-
-/* Return the KEYGRIP for the certificate CERT as an hex encoded
- string in the user provided buffer HEXKEYGRIP which must be of at
- least 41 bytes. */
-gpg_error_t
-app_help_get_keygrip_string (ksba_cert_t cert, char *hexkeygrip)
-{
- gpg_error_t err;
- gcry_sexp_t s_pkey;
- ksba_sexp_t p;
- size_t n;
- unsigned char array[20];
- int i;
-
- p = ksba_cert_get_public_key (cert);
- if (!p)
- return gpg_error (GPG_ERR_BUG);
- n = gcry_sexp_canon_len (p, 0, NULL, NULL);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- err = gcry_sexp_sscan (&s_pkey, NULL, p, n);
- xfree (p);
- if (err)
- return err; /* Can't parse that S-expression. */
- if (!gcry_pk_get_keygrip (s_pkey, array))
- {
- gcry_sexp_release (s_pkey);
- return gpg_error (GPG_ERR_GENERAL); /* Failed to calculate the keygrip.*/
- }
- gcry_sexp_release (s_pkey);
-
- for (i=0; i < 20; i++)
- sprintf (hexkeygrip+i*2, "%02X", array[i]);
-
- return 0;
-}
-
-
-
-/* Given the SLOT and the File ID FID, return the length of the
- certificate contained in that file. Returns 0 if the file does not
- exists or does not contain a certificate. If R_CERTOFF is not
- NULL, the length the header will be stored at this address; thus to
- parse the X.509 certificate a read should start at that offset.
-
- On success the file is still selected.
-*/
-size_t
-app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff)
-{
- gpg_error_t err;
- unsigned char *buffer;
- const unsigned char *p;
- size_t buflen, n;
- int class, tag, constructed, ndef;
- size_t resultlen, objlen, hdrlen;
-
- err = iso7816_select_file (slot, fid, 0, NULL, NULL);
- if (err)
- {
- log_info ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
- return 0;
- }
-
- err = iso7816_read_binary (slot, 0, 32, &buffer, &buflen);
- if (err)
- {
- log_info ("error reading certificate from FID 0x%04X: %s\n",
- fid, gpg_strerror (err));
- return 0;
- }
-
- if (!buflen || *buffer == 0xff)
- {
- log_info ("no certificate contained in FID 0x%04X\n", fid);
- xfree (buffer);
- return 0;
- }
-
- p = buffer;
- n = buflen;
- err = parse_ber_header (&p, &n, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (err)
- {
- log_info ("error parsing certificate in FID 0x%04X: %s\n",
- fid, gpg_strerror (err));
- xfree (buffer);
- return 0;
- }
-
- /* All certificates should commence with a SEQUENCE except for the
- special ROOT CA which are enclosed in a SET. */
- if ( !(class == CLASS_UNIVERSAL && constructed
- && (tag == TAG_SEQUENCE || tag == TAG_SET)))
- {
- log_info ("contents of FID 0x%04X does not look like a certificate\n",
- fid);
- return 0;
- }
-
- resultlen = objlen + hdrlen;
- if (r_certoff)
- {
- /* The callers want the offset to the actual certificate. */
- *r_certoff = hdrlen;
-
- err = parse_ber_header (&p, &n, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (err)
- return 0;
-
- if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
- {
- /* The certificate seems to be contained in a
- userCertificate container. Assume the following sequence
- is the certificate. */
- *r_certoff += hdrlen + objlen;
- if (*r_certoff > resultlen)
- {
- *r_certoff = 0;
- return 0; /* That should never happen. */
- }
- }
- else
- *r_certoff = 0;
- }
-
- return resultlen;
-}
-
-
diff --git a/scd/app-nks.c b/scd/app-nks.c
deleted file mode 100644
index e69b59879..000000000
--- a/scd/app-nks.c
+++ /dev/null
@@ -1,515 +0,0 @@
-/* app-nks.c - The Telesec NKS 2.0 card application.
- * Copyright (C) 2004 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 <time.h>
-
-#include "scdaemon.h"
-
-#include "iso7816.h"
-#include "app-common.h"
-#include "tlv.h"
-
-static struct {
- int fid; /* File ID. */
- int certtype; /* Type of certificate or 0 if it is not a certificate. */
- int iskeypair; /* If true has the FID of the correspoding certificate. */
- int issignkey; /* True if file is a key usable for signing. */
- int isenckey; /* True if file is a key usable for decryption. */
-} filelist[] = {
- { 0x4531, 0, 0xC000, 1, 0 },
- { 0xC000, 101 },
- { 0x4331, 100 },
- { 0x4332, 100 },
- { 0xB000, 110 },
- { 0x45B1, 0, 0xC200, 0, 1 },
- { 0xC200, 101 },
- { 0x43B1, 100 },
- { 0x43B2, 100 },
- { 0, 0 }
-};
-
-
-
-/* Read the file with FID, assume it contains a public key and return
- its keygrip in the caller provided 41 byte buffer R_GRIPSTR. */
-static gpg_error_t
-keygripstr_from_pk_file (int slot, int fid, char *r_gripstr)
-{
- gpg_error_t err;
- unsigned char grip[20];
- unsigned char *buffer[2];
- size_t buflen[2];
- gcry_sexp_t sexp;
- int i;
-
- err = iso7816_select_file (slot, fid, 0, NULL, NULL);
- if (err)
- return err;
- err = iso7816_read_record (slot, 1, 1, 0, &buffer[0], &buflen[0]);
- if (err)
- return err;
- err = iso7816_read_record (slot, 2, 1, 0, &buffer[1], &buflen[1]);
- if (err)
- {
- xfree (buffer[0]);
- return err;
- }
-
- for (i=0; i < 2; i++)
- {
- /* Check that the value appears like an integer encoded as
- Simple-TLV. We don't check the tag because the tests cards I
- have use 1 for both, the modulus and the exponent - the
- example in the documentation gives 2 for the exponent. */
- if (buflen[i] < 3)
- err = gpg_error (GPG_ERR_TOO_SHORT);
- else if (buffer[i][1] != buflen[i]-2 )
- err = gpg_error (GPG_ERR_INV_OBJ);
- }
-
- if (!err)
- err = gcry_sexp_build (&sexp, NULL,
- "(public-key (rsa (n %b) (e %b)))",
- (int)buflen[0]-2, buffer[0]+2,
- (int)buflen[1]-2, buffer[1]+2);
-
- xfree (buffer[0]);
- xfree (buffer[1]);
- if (err)
- return err;
-
- if (!gcry_pk_get_keygrip (sexp, grip))
- {
- err = gpg_error (GPG_ERR_INTERNAL); /* i.e. RSA not supported by
- libgcrypt. */
- }
- else
- {
- for (i=0; i < 20; i++)
- sprintf (r_gripstr+i*2, "%02X", grip[i]);
- }
- gcry_sexp_release (sexp);
- return err;
-}
-
-
-
-static int
-do_learn_status (APP app, CTRL ctrl)
-{
- gpg_error_t err;
- char ct_buf[100], id_buf[100];
- int i;
-
- /* Output information about all useful objects. */
- for (i=0; filelist[i].fid; i++)
- {
- if (filelist[i].certtype)
- {
- size_t len;
-
- len = app_help_read_length_of_cert (app->slot,
- filelist[i].fid, NULL);
- if (len)
- {
- /* FIXME: We should store the length in the application's
- context so that a following readcert does only need to
- read that many bytes. */
- sprintf (ct_buf, "%d", filelist[i].certtype);
- sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
- send_status_info (ctrl, "CERTINFO",
- ct_buf, strlen (ct_buf),
- id_buf, strlen (id_buf),
- NULL, (size_t)0);
- }
- }
- else if (filelist[i].iskeypair)
- {
- char gripstr[40+1];
-
- err = keygripstr_from_pk_file (app->slot, filelist[i].fid, gripstr);
- if (err)
- log_error ("can't get keygrip from FID 0x%04X: %s\n",
- filelist[i].fid, gpg_strerror (err));
- else
- {
- sprintf (id_buf, "NKS-DF01.%04X", filelist[i].fid);
- send_status_info (ctrl, "KEYPAIRINFO",
- gripstr, 40,
- id_buf, strlen (id_buf),
- NULL, (size_t)0);
- }
- }
- }
-
- return 0;
-}
-
-
-
-
-/* Read the certificate with id CERTID (as returned by learn_status in
- the CERTINFO status lines) and return it in the freshly allocated
- buffer put into CERT and the length of the certificate put into
- CERTLEN. */
-static int
-do_readcert (app_t app, const char *certid,
- unsigned char **cert, size_t *certlen)
-{
- int i, fid;
- gpg_error_t err;
- unsigned char *buffer;
- const unsigned char *p;
- size_t buflen, n;
- int class, tag, constructed, ndef;
- size_t totobjlen, objlen, hdrlen;
- int rootca = 0;
-
- *cert = NULL;
- *certlen = 0;
- if (strncmp (certid, "NKS-DF01.", 9) )
- return gpg_error (GPG_ERR_INV_ID);
- certid += 9;
- if (!hexdigitp (certid) || !hexdigitp (certid+1)
- || !hexdigitp (certid+2) || !hexdigitp (certid+3)
- || certid[4])
- return gpg_error (GPG_ERR_INV_ID);
- fid = xtoi_4 (certid);
- for (i=0; filelist[i].fid; i++)
- if ((filelist[i].certtype || filelist[i].iskeypair)
- && filelist[i].fid == fid)
- break;
- if (!filelist[i].fid)
- return gpg_error (GPG_ERR_NOT_FOUND);
-
- /* If the requested objects is a plain public key, redirect it to
- the corresponding certificate. The whole system is a bit messy
- becuase we sometime use the key directly or let the caller
- retrieve the key from the certificate. The valid point behind
- that is to support not-yet stored certificates. */
- if (filelist[i].iskeypair)
- fid = filelist[i].iskeypair;
-
-
- /* Read the entire file. fixme: This could be optimized by first
- reading the header to figure out how long the certificate
- actually is. */
- err = iso7816_select_file (app->slot, fid, 0, NULL, NULL);
- if (err)
- {
- log_error ("error selecting FID 0x%04X: %s\n", fid, gpg_strerror (err));
- return err;
- }
-
- err = iso7816_read_binary (app->slot, 0, 0, &buffer, &buflen);
- if (err)
- {
- log_error ("error reading certificate from FID 0x%04X: %s\n",
- fid, gpg_strerror (err));
- return err;
- }
-
- if (!buflen || *buffer == 0xff)
- {
- log_info ("no certificate contained in FID 0x%04X\n", fid);
- err = gpg_error (GPG_ERR_NOT_FOUND);
- goto leave;
- }
-
- /* Now figure something out about the object. */
- p = buffer;
- n = buflen;
- err = parse_ber_header (&p, &n, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (err)
- goto leave;
- if ( class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed )
- ;
- else if ( class == CLASS_UNIVERSAL && tag == TAG_SET && constructed )
- rootca = 1;
- else
- return gpg_error (GPG_ERR_INV_OBJ);
- totobjlen = objlen + hdrlen;
- assert (totobjlen <= buflen);
-
- err = parse_ber_header (&p, &n, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (err)
- goto leave;
-
- if (rootca)
- ;
- else if (class == CLASS_UNIVERSAL && tag == TAG_OBJECT_ID && !constructed)
- {
- const unsigned char *save_p;
-
- /* The certificate seems to be contained in a userCertificate
- container. Skip this and assume the following sequence is
- the certificate. */
- if (n < objlen)
- {
- err = gpg_error (GPG_ERR_INV_OBJ);
- goto leave;
- }
- p += objlen;
- n -= objlen;
- save_p = p;
- err = parse_ber_header (&p, &n, &class, &tag, &constructed,
- &ndef, &objlen, &hdrlen);
- if (err)
- goto leave;
- if ( !(class == CLASS_UNIVERSAL && tag == TAG_SEQUENCE && constructed) )
- return gpg_error (GPG_ERR_INV_OBJ);
- totobjlen = objlen + hdrlen;
- assert (save_p + totobjlen <= buffer + buflen);
- memmove (buffer, save_p, totobjlen);
- }
-
- *cert = buffer;
- buffer = NULL;
- *certlen = totobjlen;
-
- leave:
- xfree (buffer);
- return err;
-}
-
-
-/* Verify the PIN if required. */
-static int
-verify_pin (app_t app,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- /* Note that force_chv1 is never set but we do it here anyway so
- that other applications may euse this function. For example it
- makes sense to set force_chv1 for German signature law cards.
- NKS is very similar to the DINSIG draft standard. */
- if (!app->did_chv1 || app->force_chv1 )
- {
- char *pinvalue;
- int rc;
-
- rc = pincb (pincb_arg, "PIN", &pinvalue);
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- /* The follwoing limits are due to TCOS but also defined in the
- NKS specs. */
- if (strlen (pinvalue) < 6)
- {
- log_error ("PIN is too short; minimum length is 6\n");
- xfree (pinvalue);
- return gpg_error (GPG_ERR_BAD_PIN);
- }
- else if (strlen (pinvalue) > 16)
- {
- log_error ("PIN is too large; maximum length is 16\n");
- xfree (pinvalue);
- return gpg_error (GPG_ERR_BAD_PIN);
- }
-
- /* Also it is possible to use a local PIN, we use the gloabl
- PIN for this application. */
- rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue));
- if (rc)
- {
- log_error ("verify PIN failed\n");
- xfree (pinvalue);
- return rc;
- }
- app->did_chv1 = 1;
- xfree (pinvalue);
- }
-
- return 0;
-}
-
-
-
-/* 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;
- that callback should return the PIN in an allocated buffer and
- store that in the 3rd argument. */
-static int
-do_sign (app_t 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, i;
- int fid;
- unsigned char data[35]; /* Must be large enough for a SHA-1 digest
- + the largest OID _prefix above. */
-
- if (!keyidstr || !*keyidstr)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (indatalen != 20 && indatalen != 16 && indatalen != 35)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- /* Check that the provided ID is vaid. This is not really needed
- but we do it to to enforce correct usage by the caller. */
- if (strncmp (keyidstr, "NKS-DF01.", 9) )
- return gpg_error (GPG_ERR_INV_ID);
- keyidstr += 9;
- if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
- || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
- || keyidstr[4])
- return gpg_error (GPG_ERR_INV_ID);
- fid = xtoi_4 (keyidstr);
- for (i=0; filelist[i].fid; i++)
- if (filelist[i].iskeypair && filelist[i].fid == fid)
- break;
- if (!filelist[i].fid)
- return gpg_error (GPG_ERR_NOT_FOUND);
- if (!filelist[i].issignkey)
- return gpg_error (GPG_ERR_INV_ID);
-
- /* Prepare the DER object from INDATA. */
- if (indatalen == 35)
- {
- /* Alright, the caller was so kind to send us an already
- prepared DER object. Check that it is waht we want and that
- it matches the hash algorithm. */
- if (hashalgo == GCRY_MD_SHA1 && !memcmp (indata, sha1_prefix, 15))
- ;
- else if (hashalgo == GCRY_MD_RMD160 && !memcmp (indata, rmd160_prefix,15))
- ;
- else
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
- memcpy (data, indata, indatalen);
- }
- else
- {
- 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);
- }
-
- rc = verify_pin (app, pincb, pincb_arg);
- if (!rc)
- rc = iso7816_compute_ds (app->slot, data, 35, outdata, outdatalen);
- 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. */
-static int
-do_decipher (app_t 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 )
-{
- static const unsigned char mse_parm[] = {
- 0x80, 1, 0x10, /* Select algorithm RSA. */
- 0x84, 1, 0x81 /* Select locak secret key 1 for descryption. */
- };
- int rc, i;
- int fid;
-
- if (!keyidstr || !*keyidstr || !indatalen)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- /* Check that the provided ID is vaid. This is not really needed
- but we do it to to enforce correct usage by the caller. */
- if (strncmp (keyidstr, "NKS-DF01.", 9) )
- return gpg_error (GPG_ERR_INV_ID);
- keyidstr += 9;
- if (!hexdigitp (keyidstr) || !hexdigitp (keyidstr+1)
- || !hexdigitp (keyidstr+2) || !hexdigitp (keyidstr+3)
- || keyidstr[4])
- return gpg_error (GPG_ERR_INV_ID);
- fid = xtoi_4 (keyidstr);
- for (i=0; filelist[i].fid; i++)
- if (filelist[i].iskeypair && filelist[i].fid == fid)
- break;
- if (!filelist[i].fid)
- return gpg_error (GPG_ERR_NOT_FOUND);
- if (!filelist[i].isenckey)
- return gpg_error (GPG_ERR_INV_ID);
-
- /* Do the TCOS specific MSE. */
- rc = iso7816_manage_security_env (app->slot,
- 0xC1, 0xB8,
- mse_parm, sizeof mse_parm);
- if (!rc)
- rc = verify_pin (app, pincb, pincb_arg);
- if (!rc)
- rc = iso7816_decipher (app->slot, indata, indatalen, 0x81,
- outdata, outdatalen);
- return rc;
-}
-
-
-
-/* Select the NKS 2.0 application on the card in SLOT. */
-int
-app_select_nks (APP app)
-{
- static char const aid[] = { 0xD2, 0x76, 0x00, 0x00, 0x03, 0x01, 0x02 };
- int slot = app->slot;
- int rc;
-
- rc = iso7816_select_application (slot, aid, sizeof aid);
- if (!rc)
- {
- app->apptype = "NKS";
-
- app->fnc.learn_status = do_learn_status;
- app->fnc.readcert = do_readcert;
- app->fnc.getattr = NULL;
- app->fnc.setattr = NULL;
- app->fnc.genkey = NULL;
- app->fnc.sign = do_sign;
- app->fnc.auth = NULL;
- app->fnc.decipher = do_decipher;
- app->fnc.change_pin = NULL;
- app->fnc.check_pin = NULL;
- }
-
- return rc;
-}
-
-
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
deleted file mode 100644
index f40951941..000000000
--- a/scd/app-openpgp.c
+++ /dev/null
@@ -1,1640 +0,0 @@
-/* app-openpgp.c - The OpenPGP card application.
- * Copyright (C) 2003, 2004 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 <time.h>
-
-#if GNUPG_MAJOR_VERSION == 1
-/* This is used with GnuPG version < 1.9. The code has been source
- copied from the current GnuPG >= 1.9 and is maintained over
- there. */
-#include "options.h"
-#include "errors.h"
-#include "memory.h"
-#include "util.h"
-#include "i18n.h"
-#include "cardglue.h"
-#else /* GNUPG_MAJOR_VERSION != 1 */
-#include "scdaemon.h"
-#endif /* GNUPG_MAJOR_VERSION != 1 */
-
-#include "iso7816.h"
-#include "app-common.h"
-#include "tlv.h"
-
-
-static struct {
- int tag;
- int constructed;
- int get_from; /* Constructed DO with this DO or 0 for direct access. */
- int binary;
- int dont_cache;
- int flush_on_error;
- char *desc;
-} data_objects[] = {
- { 0x005E, 0, 0, 1, 0, 0, "Login Data" },
- { 0x5F50, 0, 0, 0, 0, 0, "URL" },
- { 0x0065, 1, 0, 1, 0, 0, "Cardholder Related Data"},
- { 0x005B, 0, 0x65, 0, 0, 0, "Name" },
- { 0x5F2D, 0, 0x65, 0, 0, 0, "Language preferences" },
- { 0x5F35, 0, 0x65, 0, 0, 0, "Sex" },
- { 0x006E, 1, 0, 1, 0, 0, "Application Related Data" },
- { 0x004F, 0, 0x6E, 1, 0, 0, "AID" },
- { 0x0073, 1, 0, 1, 0, 0, "Discretionary Data Objects" },
- { 0x0047, 0, 0x6E, 1, 0, 0, "Card Capabilities" },
- { 0x00C0, 0, 0x6E, 1, 0, 0, "Extended Card Capabilities" },
- { 0x00C1, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Signature" },
- { 0x00C2, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Decryption" },
- { 0x00C3, 0, 0x6E, 1, 0, 0, "Algorithm Attributes Authentication" },
- { 0x00C4, 0, 0x6E, 1, 0, 1, "CHV Status Bytes" },
- { 0x00C5, 0, 0x6E, 1, 0, 0, "Fingerprints" },
- { 0x00C6, 0, 0x6E, 1, 0, 0, "CA Fingerprints" },
- { 0x007A, 1, 0, 1, 0, 0, "Security Support Template" },
- { 0x0093, 0, 0x7A, 1, 1, 0, "Digital Signature Counter" },
- { 0 }
-};
-
-
-struct cache_s {
- struct cache_s *next;
- int tag;
- size_t length;
- unsigned char data[1];
-};
-
-struct app_local_s {
- struct cache_s *cache;
-};
-
-
-static unsigned long convert_sig_counter_value (const unsigned char *value,
- size_t valuelen);
-static unsigned long get_sig_counter (APP app);
-
-/* Deconstructor. */
-static void
-do_deinit (app_t app)
-{
- if (app && app->app_local)
- {
- struct cache_s *c, *c2;
-
- for (c = app->app_local->cache; c; c = c2)
- {
- c2 = c->next;
- xfree (c);
- }
- xfree (app->app_local);
- app->app_local = NULL;
- }
-}
-
-
-/* Wrapper around iso7816_get_data which first tries to get the data
- from the cache. */
-static gpg_error_t
-get_cached_data (app_t app, int tag,
- unsigned char **result, size_t *resultlen)
-{
- gpg_error_t err;
- int i;
- unsigned char *p;
- size_t len;
- struct cache_s *c;
-
-
- *result = NULL;
- *resultlen = 0;
-
- if (app->app_local)
- {
- for (c=app->app_local->cache; c; c = c->next)
- if (c->tag == tag)
- {
- p = xtrymalloc (c->length);
- if (!p)
- return gpg_error (gpg_err_code_from_errno (errno));
- memcpy (p, c->data, c->length);
- *resultlen = c->length;
- *result = p;
- return 0;
- }
- }
-
- err = iso7816_get_data (app->slot, tag, &p, &len);
- if (err)
- return err;
- *result = p;
- *resultlen = len;
-
- /* Check whether we should cache this object. */
- for (i=0; data_objects[i].tag; i++)
- if (data_objects[i].tag == tag)
- {
- if (data_objects[i].dont_cache)
- return 0;
- break;
- }
-
- /* No, cache it. */
- if (!app->app_local)
- app->app_local = xtrycalloc (1, sizeof *app->app_local);
-
- /* Note that we can safely ignore out of core errors. */
- if (app->app_local)
- {
- for (c=app->app_local->cache; c; c = c->next)
- assert (c->tag != tag);
-
- c = xtrymalloc (sizeof *c + len);
- if (c)
- {
- memcpy (c->data, p, len);
- c->length = len;
- c->tag = tag;
- c->next = app->app_local->cache;
- app->app_local->cache = c;
- }
- }
-
- return 0;
-}
-
-/* Remove DO at TAG from the cache. */
-static void
-flush_cache_item (app_t app, int tag)
-{
- struct cache_s *c, *cprev;
- int i;
-
- if (!app->app_local)
- return;
-
- for (c=app->app_local->cache, cprev=NULL; c ; cprev=c, c = c->next)
- if (c->tag == tag)
- {
- if (cprev)
- cprev->next = c->next;
- else
- app->app_local->cache = c->next;
- xfree (c);
-
- for (c=app->app_local->cache; c ; c = c->next)
- assert (c->tag != tag); /* Oops: duplicated entry. */
- return;
- }
-
- /* Try again if we have an outer tag. */
- for (i=0; data_objects[i].tag; i++)
- if (data_objects[i].tag == tag && data_objects[i].get_from
- && data_objects[i].get_from != tag)
- flush_cache_item (app, data_objects[i].get_from);
-}
-
-/* Flush all entries from the cache which might be out of sync after
- an error. */
-static void
-flush_cache_after_error (app_t app)
-{
- int i;
-
- for (i=0; data_objects[i].tag; i++)
- if (data_objects[i].flush_on_error)
- flush_cache_item (app, data_objects[i].tag);
-}
-
-
-/* Flush the entire cache. */
-static void
-flush_cache (app_t app)
-{
- if (app && app->app_local)
- {
- struct cache_s *c, *c2;
-
- for (c = app->app_local->cache; c; c = c2)
- {
- c2 = c->next;
- xfree (c);
- }
- app->app_local->cache = NULL;
- }
-}
-
-
-/* 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 (app_t app, 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 = get_cached_data (app, data_objects[i].get_from,
- &buffer, &buflen);
- if (!rc)
- {
- const unsigned char *s;
-
- s = find_tlv (buffer, buflen, tag, &valuelen);
- 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 = get_cached_data (app, tag, &buffer, &buflen);
- if (!rc)
- {
- value = buffer;
- valuelen = buflen;
- }
- }
-
- if (!rc)
- {
- *nbytes = valuelen;
- *result = value;
- return buffer;
- }
- return NULL;
-}
-
-
-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 (gpg_err_code (rc) == GPG_ERR_NO_OBJ)
- ;
- else if (rc)
- log_info ("DO `%s' not available: %s\n",
- data_objects[i].desc, gpg_strerror (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);
- 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 gpg_error (gpg_err_code_from_errno (errno));
-
- *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: %s\n",gpg_strerror (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);
-}
-
-/* Implement the GETATTR command. This is similar to the LEARN
- command but returns just one value via the status interface. */
-static int
-do_getattr (APP app, CTRL ctrl, const char *name)
-{
- static struct {
- const char *name;
- int tag;
- int special;
- } table[] = {
- { "DISP-NAME", 0x005B },
- { "LOGIN-DATA", 0x005E },
- { "DISP-LANG", 0x5F2D },
- { "DISP-SEX", 0x5F35 },
- { "PUBKEY-URL", 0x5F50 },
- { "KEY-FPR", 0x00C5, 3 },
- { "CA-FPR", 0x00C6, 3 },
- { "CHV-STATUS", 0x00C4, 1 },
- { "SIG-COUNTER", 0x0093, 2 },
- { "SERIALNO", 0x004F, -1 },
- { "AID", 0x004F },
- { NULL, 0 }
- };
- int idx, i;
- void *relptr;
- unsigned char *value;
- size_t valuelen;
-
- for (idx=0; table[idx].name && strcmp (table[idx].name, name); idx++)
- ;
- if (!table[idx].name)
- return gpg_error (GPG_ERR_INV_NAME);
-
- if (table[idx].special == -1)
- {
- /* The serial number is very special. We could have used the
- AID DO to retrieve it, but we have it already in the app
- context and the stamp argument is required anyway which we
- can't by other means. The AID DO is available anyway but not
- hex formatted. */
- char *serial;
- time_t stamp;
- char tmp[50];
-
- if (!app_get_serial_and_stamp (app, &serial, &stamp))
- {
- sprintf (tmp, "%lu", (unsigned long)stamp);
- send_status_info (ctrl, "SERIALNO",
- serial, strlen (serial),
- tmp, strlen (tmp),
- NULL, 0);
- xfree (serial);
- }
- return 0;
- }
-
- relptr = get_one_do (app, table[idx].tag, &value, &valuelen);
- if (relptr)
- {
- if (table[idx].special == 1)
- {
- 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, table[idx].name,
- numbuf, strlen (numbuf), NULL, 0);
- }
- else if (table[idx].special == 2)
- {
- char numbuf[50];
-
- sprintf (numbuf, "%lu", convert_sig_counter_value (value, valuelen));
- send_status_info (ctrl, table[idx].name,
- numbuf, strlen (numbuf), NULL, 0);
- }
- else if (table[idx].special == 3)
- {
- if (valuelen >= 60)
- for (i=0; i < 3; i++)
- send_fpr_if_not_null (ctrl, "KEY-FPR", i+1, value+i*20);
- }
- else
- send_status_info (ctrl, table[idx].name, value, valuelen, NULL, 0);
-
- xfree (relptr);
- }
- return 0;
-}
-
-
-static int
-do_learn_status (APP app, CTRL ctrl)
-{
- do_getattr (app, ctrl, "DISP-NAME");
- do_getattr (app, ctrl, "DISP-LANG");
- do_getattr (app, ctrl, "DISP-SEX");
- do_getattr (app, ctrl, "PUBKEY-URL");
- do_getattr (app, ctrl, "LOGIN-DATA");
- do_getattr (app, ctrl, "KEY-FPR");
- do_getattr (app, ctrl, "CA-FPR");
- do_getattr (app, ctrl, "CHV-STATUS");
- do_getattr (app, ctrl, "SIG-COUNTER");
-
- return 0;
-}
-
-
-/* Verify CHV2 if required. Depending on the configuration of the
- card CHV1 will also be verified. */
-static int
-verify_chv2 (app_t app,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- int rc = 0;
-
- if (!app->did_chv2)
- {
- char *pinvalue;
-
- rc = pincb (pincb_arg, "PIN", &pinvalue);
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- if (strlen (pinvalue) < 6)
- {
- log_error ("prassphrase (CHV2) is too short; minimum length is 6\n");
- xfree (pinvalue);
- return gpg_error (GPG_ERR_BAD_PIN);
- }
-
- rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
- if (rc)
- {
- log_error ("verify CHV2 failed: %s\n", gpg_strerror (rc));
- xfree (pinvalue);
- flush_cache_after_error (app);
- return rc;
- }
- app->did_chv2 = 1;
-
- if (!app->did_chv1 && !app->force_chv1)
- {
- rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
- if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
- rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
- if (rc)
- {
- log_error ("verify CHV1 failed: %s\n", gpg_strerror (rc));
- xfree (pinvalue);
- flush_cache_after_error (app);
- return rc;
- }
- app->did_chv1 = 1;
- }
- xfree (pinvalue);
- }
- return rc;
-}
-
-/* Verify CHV3 if required. */
-static int
-verify_chv3 (APP app,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- int rc = 0;
-
- if (!opt.allow_admin)
- {
- log_info ("access to admin commands is not configured\n");
- return gpg_error (GPG_ERR_EACCES);
- }
-
- if (!app->did_chv3)
- {
- char *pinvalue;
-
- rc = pincb (pincb_arg, "Admin PIN", &pinvalue);
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- if (strlen (pinvalue) < 6)
- {
- log_error ("prassphrase (CHV3) is too short; minimum length is 6\n");
- xfree (pinvalue);
- return gpg_error (GPG_ERR_BAD_PIN);
- }
-
- rc = iso7816_verify (app->slot, 0x83, pinvalue, strlen (pinvalue));
- xfree (pinvalue);
- if (rc)
- {
- log_error ("verify CHV3 failed: %s\n", gpg_strerror (rc));
- flush_cache_after_error (app);
- return rc;
- }
- app->did_chv3 = 1;
- }
- return rc;
-}
-
-
-/* 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;
- int special;
- } table[] = {
- { "DISP-NAME", 0x005B },
- { "LOGIN-DATA", 0x005E },
- { "DISP-LANG", 0x5F2D },
- { "DISP-SEX", 0x5F35 },
- { "PUBKEY-URL", 0x5F50 },
- { "CHV-STATUS-1", 0x00C4, 1 },
- { "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);
-
- rc = verify_chv3 (app, pincb, pincb_arg);
- if (rc)
- return rc;
-
- /* Flush the cache before writing it, so that the next get operation
- will reread the data from the card and thus get synced in case of
- errors (e.g. data truncated by the card). */
- flush_cache_item (app, table[idx].tag);
- 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));
-
- if (table[idx].special == 1)
- app->force_chv1 = (valuelen && *value == 0);
-
- 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)
- {
- /* we always require that the PIN is entered. */
- app->did_chv3 = 0;
- rc = verify_chv3 (app, pincb, pincb_arg);
- if (rc)
- goto leave;
- }
- else if (chvno == 1 || chvno == 2)
- {
- /* CHV1 and CVH2 should always have the same value, thus we
- enforce it here. */
- int save_force = app->force_chv1;
-
- app->force_chv1 = 0;
- app->did_chv1 = 0;
- app->did_chv2 = 0;
- rc = verify_chv2 (app, pincb, pincb_arg);
- app->force_chv1 = save_force;
- if (rc)
- goto leave;
- }
- else
- {
- rc = gpg_error (GPG_ERR_INV_ID);
- goto leave;
- }
-
- if (chvno == 3)
- app->did_chv3 = 0;
- else
- app->did_chv1 = app->did_chv2 = 0;
-
- rc = pincb (pincb_arg, chvno == 3? "New Admin PIN" : "New 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, 0x81,
- pinvalue, strlen (pinvalue));
- if (!rc)
- rc = iso7816_reset_retry_counter (app->slot, 0x82,
- pinvalue, strlen (pinvalue));
- }
- else
- {
- if (chvno == 1 || chvno == 2)
- {
- rc = iso7816_change_reference_data (app->slot, 0x81, NULL, 0,
- pinvalue, strlen (pinvalue));
- if (!rc)
- rc = iso7816_change_reference_data (app->slot, 0x82, NULL, 0,
- pinvalue, strlen (pinvalue));
- }
- else
- rc = iso7816_change_reference_data (app->slot, 0x80 + chvno, NULL, 0,
- pinvalue, strlen (pinvalue));
- }
- xfree (pinvalue);
- if (rc)
- flush_cache_after_error (app);
-
- 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--;
-
- /* We flush the cache to increase the traffic before a key
- generation. This _might_ help a card to gather more entropy. */
- flush_cache (app);
-
- 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);
- 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");
-
-
- rc = verify_chv3 (app, pincb, pincb_arg);
- if (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);
- 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);
- 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);
- 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
-convert_sig_counter_value (const unsigned char *value, size_t valuelen)
-{
- unsigned long ul;
-
- 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;
- }
- return ul;
-}
-
-static unsigned long
-get_sig_counter (APP app)
-{
- void *relptr;
- unsigned char *value;
- size_t valuelen;
- unsigned long ul;
-
- relptr = get_one_do (app, 0x0093, &value, &valuelen);
- if (!relptr)
- return 0;
- ul = convert_sig_counter_value (value, valuelen);
- 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 = get_cached_data (app, 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);
- 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;
-}
-
-
- /* 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 we
- assume that this is okay. */
-static int
-check_against_given_fingerprint (APP app, const char *fpr, int keyno)
-{
- unsigned char tmp[20];
- const char *s;
- int n;
-
- 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[n] = xtoi_2 (s);
- return compare_fingerprint (app, keyno, tmp);
-}
-
-
-
-/* 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. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 1) : 0;
- 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);
-
- if (!app->did_chv1 || app->force_chv1 )
- {
- char *pinvalue;
-
- {
- char *prompt;
- if (asprintf (&prompt, "PIN [sigs done: %lu]", sigcount) < 0)
- return gpg_error_from_errno (errno);
- rc = pincb (pincb_arg, prompt, &pinvalue);
- free (prompt);
- }
- if (rc)
- {
- log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
- return rc;
- }
-
- if (strlen (pinvalue) < 6)
- {
- log_error ("prassphrase (CHV1) is too short; minimum length is 6\n");
- xfree (pinvalue);
- return gpg_error (GPG_ERR_BAD_PIN);
- }
-
- rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
- if (rc)
- {
- log_error ("verify CHV1 failed\n");
- xfree (pinvalue);
- flush_cache_after_error (app);
- return rc;
- }
- app->did_chv1 = 1;
- if (!app->did_chv2)
- {
- /* We should also verify CHV2. */
- rc = iso7816_verify (app->slot, 0x82, pinvalue, strlen (pinvalue));
- if (gpg_err_code (rc) == GPG_ERR_BAD_PIN)
- rc = gpg_error (GPG_ERR_PIN_NOT_SYNCED);
- if (rc)
- {
- log_error ("verify CHV2 failed\n");
- xfree (pinvalue);
- flush_cache_after_error (app);
- return rc;
- }
- app->did_chv2 = 1;
- }
- xfree (pinvalue);
- }
-
- 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. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 3) : 0;
- if (rc)
- return rc;
-
- rc = verify_chv2 (app, pincb, pincb_arg);
- if (!rc)
- 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. */
- rc = fpr? check_against_given_fingerprint (app, fpr, 2) : 0;
- if (rc)
- return rc;
-
- rc = verify_chv2 (app, pincb, pincb_arg);
- if (!rc)
- rc = iso7816_decipher (app->slot, indata, indatalen, 0,
- outdata, outdatalen);
- return rc;
-}
-
-
-/* Perform a simple verify operation for CHV1 and CHV2, so that
- further operations won't ask for CHV2 and it is possible to do a
- cheap check on the PIN: If there is something wrong with the PIN
- entry system, only the regular CHV will get blocked and not the
- dangerous CHV3. KEYIDSTR is the usual card's serial number; an
- optional fingerprint part will be ignored. */
-static int
-do_check_pin (APP app, const char *keyidstr,
- int (pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- unsigned char tmp_sn[20];
- const char *s;
- int n;
-
- if (!keyidstr || !*keyidstr)
- 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 == '/')
- ; /* We ignore a fingerprint. */
- 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);
- /* Yes, there is a race conditions: The user might pull the card
- right here and we won't notice that. However this is not a
- problem and the check above is merely for a graceful failure
- between operations. */
-
- return verify_chv2 (app, pincb, pincb_arg);
-}
-
-
-
-
-/* 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)
-{
- static char const aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
- int slot = app->slot;
- int rc;
- unsigned char *buffer;
- size_t buflen;
- void *relptr;
-
- rc = iso7816_select_application (slot, aid, sizeof aid);
- if (!rc)
- {
- app->apptype = "OPENPGP";
-
- app->did_chv1 = 0;
- app->did_chv2 = 0;
- app->did_chv3 = 0;
-
- /* The OpenPGP card returns the serial number as part of the
- AID; because we prefer to use OpenPGP serial numbers, we
- replace a possibly already set one from a EF.GDO with this
- one. Note, that for current OpenPGP cards, no EF.GDO exists
- and thus it won't matter at all. */
- rc = iso7816_get_data (slot, 0x004F, &buffer, &buflen);
- if (rc)
- goto leave;
- if (opt.verbose)
- {
- log_info ("got AID: ");
- log_printhex ("", buffer, buflen);
- }
-
- app->card_version = buffer[6] << 8;
- app->card_version |= buffer[7];
- xfree (app->serialno);
- app->serialno = buffer;
- app->serialnolen = buflen;
- buffer = NULL;
-
- relptr = get_one_do (app, 0x00C4, &buffer, &buflen);
- if (!relptr)
- {
- log_error ("can't access CHV Status Bytes - invalid OpenPGP card?\n");
- goto leave;
- }
- app->force_chv1 = (buflen && *buffer == 0);
- xfree (relptr);
-
- if (opt.verbose > 1)
- dump_all_do (slot);
-
- app->fnc.deinit = do_deinit;
- app->fnc.learn_status = do_learn_status;
- app->fnc.readcert = NULL;
- app->fnc.getattr = do_getattr;
- 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;
- app->fnc.check_pin = do_check_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, 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, 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, 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--;
-
- rc = verify_chv3 (app, pincb, pincb_arg);
- if (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=%s\n", gpg_strerror (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);
- 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);
- 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);
- 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 a9a9243eb..000000000
--- a/scd/app.c
+++ /dev/null
@@ -1,391 +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 "scdaemon.h"
-#include "app-common.h"
-#include "apdu.h"
-#include "iso7816.h"
-#include "tlv.h"
-
-
-/* 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
- NULL if no application was found or no card is present. */
-APP
-select_application (ctrl_t ctrl, int slot, const char *name)
-{
- int rc;
- APP app;
- unsigned char *result = NULL;
- size_t resultlen;
-
- app = xtrycalloc (1, sizeof *app);
- if (!app)
- {
- rc = gpg_error (gpg_err_code_from_errno (errno));
- log_info ("error allocating context: %s\n", gpg_strerror (rc));
- return NULL;
- }
- app->slot = slot;
-
- /* Fixme: We should now first check whether a card is at all
- present. */
-
- /* Try to read the GDO file first to get a default serial number. */
- rc = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
- if (!rc)
- rc = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
- if (!rc)
- rc = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
- if (!rc)
- {
- size_t n;
- const unsigned char *p;
-
- p = find_tlv (result, resultlen, 0x5A, &n);
- if (p && n && n >= (resultlen - (p - result)))
- {
- /* The GDO file is pretty short, thus we simply reuse it for
- storing the serial number. */
- memmove (result, p, n);
- app->serialno = result;
- app->serialnolen = n;
- }
- else
- xfree (result);
- result = NULL;
- }
-
-
- rc = gpg_error (GPG_ERR_NOT_FOUND);
-
- if (!name || !strcmp (name, "openpgp"))
- rc = app_select_openpgp (app);
- if (rc && (!name || !strcmp (name, "nks")))
- rc = app_select_nks (app);
- if (rc && (!name || !strcmp (name, "dinsig")))
- rc = app_select_dinsig (app);
- if (rc && name)
- rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
-
- if (rc)
- {
- if (name)
- log_info ("can't select application `%s': %s\n",
- name, gpg_strerror (rc));
- else
- log_info ("no supported card application found: %s\n",
- gpg_strerror (rc));
- xfree (app);
- return NULL;
- }
-
- app->initialized = 1;
- return app;
-}
-
-
-void
-release_application (app_t app)
-{
- if (!app)
- return;
-
- if (app->fnc.deinit)
- {
- app->fnc.deinit (app);
- app->fnc.deinit = NULL;
- }
-
- xfree (app->serialno);
- xfree (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. If STAMP is not
- of interest, NULL may be passed. */
-int
-app_get_serial_and_stamp (app_t app, char **serial, time_t *stamp)
-{
- unsigned char *buf, *p;
- int i;
-
- if (!app || !serial)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- *serial = NULL;
- if (stamp)
- *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);
-
- if (app->apptype)
- send_status_info (ctrl, "APPTYPE",
- app->apptype, strlen (app->apptype), NULL, 0);
-
- return app->fnc.learn_status (app, ctrl);
-}
-
-
-/* Read the certificate with id CERTID (as returned by learn_status in
- the CERTINFO status lines) and return it in the freshly allocated
- buffer put into CERT and the length of the certificate put into
- CERTLEN. */
-int
-app_readcert (app_t app, const char *certid,
- unsigned char **cert, size_t *certlen)
-{
- if (!app)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.readcert)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- return app->fnc.readcert (app, certid, cert, certlen);
-}
-
-
-/* Perform a GETATTR operation. */
-int
-app_getattr (APP app, CTRL ctrl, const char *name)
-{
- if (!app || !name || !*name)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.getattr)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- return app->fnc.getattr (app, ctrl, name);
-}
-
-/* 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;
-}
-
-
-/* Perform a VERIFY operation without doing anything lese. This may
- be used to initialze a the PION cache for long lasting other
- operations. Its use is highly application dependent. */
-int
-app_check_pin (APP app, const char *keyidstr,
- int (*pincb)(void*, const char *, char **),
- void *pincb_arg)
-{
- int rc;
-
- if (!app || !keyidstr || !*keyidstr || !pincb)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!app->initialized)
- return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
- if (!app->fnc.check_pin)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
- rc = app->fnc.check_pin (app, keyidstr, pincb, pincb_arg);
- if (opt.verbose)
- log_info ("operation check_pin result: %s\n", gpg_strerror (rc));
- return rc;
-}
-
diff --git a/scd/atr.c b/scd/atr.c
deleted file mode 100644
index 6475e83f8..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 <assert.h>
-
-#include "scdaemon.h"
-#include "apdu.h"
-#include "atr.h"
-#include "dynload.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 cefaf120f..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 (ksba_cert_t 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 df09bfb57..000000000
--- a/scd/card-dinsig.c
+++ /dev/null
@@ -1,258 +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 "scdaemon.h"
-#include <ksba.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;
- ksba_cert_t 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;
-
- rc = ksba_cert_new (&cert);
- if (rc)
- {
- xfree (buf);
- return rc;
- }
-
- rc = ksba_cert_init_from_mem (cert, buf, buflen);
- xfree (buf);
- if (rc)
- {
- log_error ("failed to parse the certificate at idx %d: %s\n",
- idx, gpg_strerror (rc));
- ksba_cert_release (cert);
- return rc;
- }
- 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 gpg_error (gpg_err_code_from_errno (errno));
- 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 = gpg_error (gpg_err_code_from_errno (errno));
- 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 ae3ef148f..000000000
--- a/scd/card-p15.c
+++ /dev/null
@@ -1,500 +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 "scdaemon.h"
-#include <ksba.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 gpg_error (gpg_err_code_from_errno (errno));
-
- /* OpenSC (0.7.0) is a bit strange in that the get_objects functions
- tries to be a bit too clever and implicitly does an enumeration
- 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;
- 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;
- ksba_cert_t 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_CERT);
- 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);
- }
-
- rc = ksba_cert_new (&cert);
- if (rc)
- {
- sc_pkcs15_free_certificate (certder);
- return rc;
- }
- rc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len);
- sc_pkcs15_free_certificate (certder);
- if (rc)
- {
- log_error ("failed to parse the certificate for private key %d: %s\n",
- idx, gpg_strerror (rc));
- ksba_cert_release (cert);
- return rc;
- }
- 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 gpg_error (gpg_err_code_from_errno (errno));
- p = stpcpy (p, "P15-5015.");
- for (i=0; i < pinfo->id.len; i++, p += 2)
- sprintf (p, "%02X", pinfo->id.value[i]);
- *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 gpg_error (gpg_err_code_from_errno (errno));
- p = stpcpy (p, "P15-5015.");
- for (i=0; i < cinfo->id.len; i++, p += 2)
- sprintf (p, "%02X", cinfo->id.value[i]);
- *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 = gpg_error (gpg_err_code_from_errno (errno));
- 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_SECKEY);
- }
-
- 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", gpg_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 gpg_error (gpg_err_code_from_errno (errno));
-
- 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 gpg_error (gpg_err_code_from_errno (errno));
-
- 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 9ec2a52c5..000000000
--- a/scd/card.c
+++ /dev/null
@@ -1,570 +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 "scdaemon.h"
-#include <ksba.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;
- }
- /* It does not make much sense to further distingusih the error
- source between OpenSC and SCD. Thus we use SCD as source
- here. */
- return gpg_err_make (GPG_ERR_SOURCE_SCD, e);
-}
-
-/* Get the keygrip from CERT, return 0 on success */
-int
-card_help_get_keygrip (ksba_cert_t cert, unsigned char *array)
-{
- gcry_sexp_t s_pkey;
- int rc;
- ksba_sexp_t 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 whether 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;
-
- if (opt.disable_opensc)
- return gpg_error (GPG_ERR_NOT_SUPPORTED);
-
- card = xtrycalloc (1, sizeof *card);
- if (!card)
- return gpg_error (gpg_err_code_from_errno (errno));
- 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 gpg_error (gpg_err_code_from_errno (errno));
- 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);
- 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 = gpg_error (gpg_err_code_from_errno (errno));
- 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 = gpg_error (gpg_err_code_from_errno (errno));
- }
- 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
- 110 := Root CA cert (DINSIG)
- */
-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/ccid-driver.c b/scd/ccid-driver.c
deleted file mode 100644
index cd0bee6ef..000000000
--- a/scd/ccid-driver.c
+++ /dev/null
@@ -1,1277 +0,0 @@
-/* ccid-driver.c - USB ChipCardInterfaceDevices driver
- * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
- * Written by Werner Koch.
- *
- * 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
- *
- * ALTERNATIVELY, this file may be distributed under the terms of the
- * following license, in which case the provisions of this license are
- * required INSTEAD OF the GNU General Public License. If you wish to
- * allow use of your version of this file only under the terms of the
- * GNU General Public License, and not to allow others to use your
- * version of this file under the terms of the following license,
- * indicate your decision by deleting this paragraph and the license
- * below.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, and the entire permission notice in its entirety,
- * including the disclaimer of warranties.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-
-/* 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"
-
-#define DRVNAME "ccid-driver: "
-
-
-/* Depending on how this source is used we either define our error
- output to go to stderr or to the jnlib based logging functions. We
- use the latter when GNUPG_MAJOR_VERSION is defines or when both,
- GNUPG_SCD_MAIN_HEADER and HAVE_JNLIB_LOGGING are defined.
-*/
-#if defined(GNUPG_MAJOR_VERSION) \
- || (defined(GNUPG_SCD_MAIN_HEADER) && defined(HAVE_JNLIB_LOGGING))
-
-#if defined(GNUPG_SCD_MAIN_HEADER)
-# include GNUPG_SCD_MAIN_HEADER
-#elif GNUPG_MAJOR_VERSION == 1 /* GnuPG Version is < 1.9. */
-# include "options.h"
-# include "util.h"
-# include "memory.h"
-# include "cardglue.h"
-# else /* This is the modularized GnuPG 1.9 or later. */
-# include "scdaemon.h"
-#endif
-
-/* Disable all debugging output for now. */
-#undef DBG_CARD_IO
-#define DBG_CARD_IO 0
-
-/* Define to print information pertaining the T=1 protocol. */
-#undef DEBUG_T1
-
-
-# define DEBUGOUT(t) do { if (DBG_CARD_IO) \
- log_debug (DRVNAME t); } while (0)
-# define DEBUGOUT_1(t,a) do { if (DBG_CARD_IO) \
- log_debug (DRVNAME t,(a)); } while (0)
-# define DEBUGOUT_2(t,a,b) do { if (DBG_CARD_IO) \
- log_debug (DRVNAME t,(a),(b)); } while (0)
-# define DEBUGOUT_3(t,a,b,c) do { if (DBG_CARD_IO) \
- log_debug (DRVNAME t,(a),(b),(c));} while (0)
-# define DEBUGOUT_CONT(t) do { if (DBG_CARD_IO) \
- log_printf (t); } while (0)
-# define DEBUGOUT_CONT_1(t,a) do { if (DBG_CARD_IO) \
- log_printf (t,(a)); } while (0)
-# define DEBUGOUT_CONT_2(t,a,b) do { if (DBG_CARD_IO) \
- log_printf (t,(a),(b)); } while (0)
-# define DEBUGOUT_CONT_3(t,a,b,c) do { if (DBG_CARD_IO) \
- log_printf (t,(a),(b),(c)); } while (0)
-# define DEBUGOUT_LF() do { if (DBG_CARD_IO) \
- log_printf ("\n"); } while (0)
-
-#else /* Other usage of this source - don't use gnupg specifics. */
-
-# define DEBUGOUT(t) fprintf (stderr, DRVNAME t)
-# define DEBUGOUT_1(t,a) fprintf (stderr, DRVNAME t, (a))
-# define DEBUGOUT_2(t,a,b) fprintf (stderr, DRVNAME t, (a), (b))
-# define DEBUGOUT_3(t,a,b,c) fprintf (stderr, DRVNAME t, (a), (b), (c))
-# define DEBUGOUT_CONT(t) fprintf (stderr, t)
-# define DEBUGOUT_CONT_1(t,a) fprintf (stderr, t, (a))
-# define DEBUGOUT_CONT_2(t,a,b) fprintf (stderr, t, (a), (b))
-# define DEBUGOUT_CONT_3(t,a,b,c) fprintf (stderr, t, (a), (b), (c))
-# define DEBUGOUT_LF() putc ('\n', stderr)
-
-#endif /* This source not used by scdaemon. */
-
-
-
-
-
-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_ns;
- unsigned char t1_nr;
- int nonnull_nad;
- int auto_ifsd;
- int max_ifsd;
- int ifsd;
-};
-
-
-static unsigned int compute_edc (const unsigned char *data, size_t datalen,
- int use_crc);
-static int bulk_out (ccid_driver_t handle, unsigned char *msg, size_t msglen);
-static int bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
- size_t *nread, int expected_type, int seqno);
-
-
-
-/* Convert a little endian stored 4 byte value into an unsigned
- integer. */
-static unsigned int
-convert_le_u32 (const unsigned char *buf)
-{
- return buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
-}
-
-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;
-}
-
-
-
-
-/* Parse a CCID descriptor, optionally print all available features
- and test whether this reader is usable by this driver. Returns 0
- if it is usable.
-
- Note, that this code is based on the one in lsusb.c of the
- usb-utils package, I wrote on 2003-09-01. -wk. */
-static int
-parse_ccid_descriptor (ccid_driver_t handle,
- const unsigned char *buf, size_t buflen)
-{
- unsigned int i;
- unsigned int us;
- int have_t1 = 0, have_tpdu=0, have_auto_conf = 0;
-
-
- handle->nonnull_nad = 0;
- handle->auto_ifsd = 0;
- handle->max_ifsd = 32;
- handle->ifsd = 0;
- if (buflen < 54 || buf[0] < 54)
- {
- DEBUGOUT ("CCID device descriptor is too short\n");
- return -1;
- }
-
- DEBUGOUT ("ChipCard Interface Descriptor:\n");
- DEBUGOUT_1 (" bLength %5u\n", buf[0]);
- DEBUGOUT_1 (" bDescriptorType %5u\n", buf[1]);
- DEBUGOUT_2 (" bcdCCID %2x.%02x", buf[3], buf[2]);
- if (buf[3] != 1 || buf[2] != 0)
- DEBUGOUT_CONT(" (Warning: Only accurate for version 1.0)");
- DEBUGOUT_LF ();
-
- DEBUGOUT_1 (" nMaxSlotIndex %5u\n", buf[4]);
- DEBUGOUT_2 (" bVoltageSupport %5u %s\n",
- buf[5], (buf[5] == 1? "5.0V" : buf[5] == 2? "3.0V"
- : buf[5] == 3? "1.8V":"?"));
-
- us = convert_le_u32 (buf+6);
- DEBUGOUT_1 (" dwProtocols %5u ", us);
- if ((us & 1))
- DEBUGOUT_CONT (" T=0");
- if ((us & 2))
- {
- DEBUGOUT_CONT (" T=1");
- have_t1 = 1;
- }
- if ((us & ~3))
- DEBUGOUT_CONT (" (Invalid values detected)");
- DEBUGOUT_LF ();
-
- us = convert_le_u32(buf+10);
- DEBUGOUT_1 (" dwDefaultClock %5u\n", us);
- us = convert_le_u32(buf+14);
- DEBUGOUT_1 (" dwMaxiumumClock %5u\n", us);
- DEBUGOUT_1 (" bNumClockSupported %5u\n", buf[18]);
- us = convert_le_u32(buf+19);
- DEBUGOUT_1 (" dwDataRate %7u bps\n", us);
- us = convert_le_u32(buf+23);
- DEBUGOUT_1 (" dwMaxDataRate %7u bps\n", us);
- DEBUGOUT_1 (" bNumDataRatesSupp. %5u\n", buf[27]);
-
- us = convert_le_u32(buf+28);
- DEBUGOUT_1 (" dwMaxIFSD %5u\n", us);
- handle->max_ifsd = us;
-
- us = convert_le_u32(buf+32);
- DEBUGOUT_1 (" dwSyncProtocols %08X ", us);
- if ((us&1))
- DEBUGOUT_CONT ( " 2-wire");
- if ((us&2))
- DEBUGOUT_CONT ( " 3-wire");
- if ((us&4))
- DEBUGOUT_CONT ( " I2C");
- DEBUGOUT_LF ();
-
- us = convert_le_u32(buf+36);
- DEBUGOUT_1 (" dwMechanical %08X ", us);
- if ((us & 1))
- DEBUGOUT_CONT (" accept");
- if ((us & 2))
- DEBUGOUT_CONT (" eject");
- if ((us & 4))
- DEBUGOUT_CONT (" capture");
- if ((us & 8))
- DEBUGOUT_CONT (" lock");
- DEBUGOUT_LF ();
-
- us = convert_le_u32(buf+40);
- DEBUGOUT_1 (" dwFeatures %08X\n", us);
- if ((us & 0x0002))
- {
- DEBUGOUT (" Auto configuration based on ATR\n");
- have_auto_conf = 1;
- }
- if ((us & 0x0004))
- DEBUGOUT (" Auto activation on insert\n");
- if ((us & 0x0008))
- DEBUGOUT (" Auto voltage selection\n");
- if ((us & 0x0010))
- DEBUGOUT (" Auto clock change\n");
- if ((us & 0x0020))
- DEBUGOUT (" Auto baud rate change\n");
- if ((us & 0x0040))
- DEBUGOUT (" Auto parameter negotation made by CCID\n");
- else if ((us & 0x0080))
- DEBUGOUT (" Auto PPS made by CCID\n");
- else if ((us & (0x0040 | 0x0080)))
- DEBUGOUT (" WARNING: conflicting negotation features\n");
-
- if ((us & 0x0100))
- DEBUGOUT (" CCID can set ICC in clock stop mode\n");
- if ((us & 0x0200))
- {
- DEBUGOUT (" NAD value other than 0x00 accepted\n");
- handle->nonnull_nad = 1;
- }
- if ((us & 0x0400))
- {
- DEBUGOUT (" Auto IFSD exchange\n");
- handle->auto_ifsd = 1;
- }
-
- if ((us & 0x00010000))
- {
- DEBUGOUT (" TPDU level exchange\n");
- have_tpdu = 1;
- }
- else if ((us & 0x00020000))
- DEBUGOUT (" Short APDU level exchange\n");
- else if ((us & 0x00040000))
- DEBUGOUT (" Short and extended APDU level exchange\n");
- else if ((us & 0x00070000))
- DEBUGOUT (" WARNING: conflicting exchange levels\n");
-
- us = convert_le_u32(buf+44);
- DEBUGOUT_1 (" dwMaxCCIDMsgLen %5u\n", us);
-
- DEBUGOUT ( " bClassGetResponse ");
- if (buf[48] == 0xff)
- DEBUGOUT_CONT ("echo\n");
- else
- DEBUGOUT_CONT_1 (" %02X\n", buf[48]);
-
- DEBUGOUT ( " bClassEnvelope ");
- if (buf[49] == 0xff)
- DEBUGOUT_CONT ("echo\n");
- else
- DEBUGOUT_1 (" %02X\n", buf[48]);
-
- DEBUGOUT ( " wlcdLayout ");
- if (!buf[50] && !buf[51])
- DEBUGOUT_CONT ("none\n");
- else
- DEBUGOUT_CONT_2 ("%u cols %u lines\n", buf[50], buf[51]);
-
- DEBUGOUT_1 (" bPINSupport %5u ", buf[52]);
- if ((buf[52] & 1))
- DEBUGOUT_CONT ( " verification");
- if ((buf[52] & 2))
- DEBUGOUT_CONT ( " modification");
- DEBUGOUT_LF ();
-
- DEBUGOUT_1 (" bMaxCCIDBusySlots %5u\n", buf[53]);
-
- if (buf[0] > 54) {
- DEBUGOUT (" junk ");
- for (i=54; i < buf[0]-54; i++)
- DEBUGOUT_CONT_1 (" %02X", buf[i]);
- DEBUGOUT_LF ();
- }
-
- if (!have_t1 || !have_tpdu || !have_auto_conf)
- {
- DEBUGOUT ("this drivers requires that the reader supports T=1, "
- "TPDU level exchange and auto configuration - "
- "this is not available\n");
- return -1;
- }
- else
- return 0;
-}
-
-
-/* Read the device information, return all required data and check
- that the device is usable for us. Returns 0 on success or an error
- code. */
-static int
-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++)
- {
- struct usb_config_descriptor *config = dev->config + cfg_no;
- int ifc_no;
-
- for (ifc_no=0; ifc_no < config->bNumInterfaces; ifc_no++)
- {
- struct usb_interface *interface = config->interface + ifc_no;
- int set_no;
-
- for (set_no=0; set_no < interface->num_altsetting; set_no++)
- {
- struct usb_interface_descriptor *ifcdesc
- = interface->altsetting + set_no;
-
- if (ifcdesc->bInterfaceClass == 11
- && ifcdesc->bInterfaceSubClass == 0
- && ifcdesc->bInterfaceProtocol == 0)
- {
- if (ifcdesc->extra)
- {
- if (!parse_ccid_descriptor (handle,
- ifcdesc->extra,
- ifcdesc->extralen))
- return 0; /* okay. we can use it. */
- }
- }
- }
- }
- }
- return -1; /* No suitable device found. */
-}
-
-
-/* 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)
- {
- DEBUGOUT_1 ("usb_create_match failed: %d\n", rc);
- return -1;
- }
-
- while (usb_find_device(match, dev, &dev) >= 0)
- {
- 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 = -1;
- free (*handle);
- *handle = NULL;
- goto leave;
- }
-
- rc = read_device_info (*handle, dev);
- if (rc)
- {
- DEBUGOUT ("device not supported\n");
- free (*handle);
- *handle = NULL;
- goto leave;
- }
-
- rc = usb_open (dev, &idev);
- if (rc)
- {
- DEBUGOUT_1 ("usb_open failed: %d\n", rc);
- free (*handle);
- *handle = NULL;
- 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;
- 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? */
-
- 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);
-
- if (!rc && !*handle)
- rc = -1; /* In case we didn't enter the while loop at all. */
-
- return rc;
-}
-
-
-/* Close the reader HANDLE. */
-int
-ccid_close_reader (ccid_driver_t handle)
-{
- if (!handle || !handle->idev)
- return 0;
-
- {
- int rc;
- unsigned char msg[100];
- size_t msglen;
- unsigned char seqno;
-
- msg[0] = PC_to_RDR_IccPowerOff;
- 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);
- msglen = 10;
-
- rc = bulk_out (handle, msg, msglen);
- if (!rc)
- bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_SlotStatus, seqno);
- }
-
- usb_release_interface (handle->idev, 0);
- usb_close (handle->idev);
- handle->idev = NULL;
- free (handle);
- return 0;
-}
-
-
-/* Return False if a card is present and powered. */
-int
-ccid_check_card_presence (ccid_driver_t handle)
-{
-
- return -1;
-}
-
-
-/* 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)
- DEBUGOUT_1 ("usb_bulk_write error: %s\n", strerror (errno));
- else
- DEBUGOUT_1 ("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. SEQNO
- is the sequence number used to send the request and EXPECTED_TYPE
- the type of message we expect. Does checks on the ccid
- header. Returns 0 on success. */
-static int
-bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
- size_t *nread, int expected_type, int seqno)
-{
- int i, rc;
- size_t msglen;
-
- retry:
- rc = usb_bulk_read (handle->idev,
- 0x82,
- buffer, length,
- 10000 /* ms timeout */ );
- /* Fixme: instead of using a 10 second timeout we should better
- handle the timeout here and retry if appropriate. */
- if (rc < 0)
- {
- DEBUGOUT_1 ("usb_bulk_read error: %s\n", strerror (errno));
- return -1;
- }
-
- *nread = msglen = rc;
-
- if (msglen < 10)
- {
- DEBUGOUT_1 ("bulk-in msg too short (%u)\n", (unsigned int)msglen);
- return -1;
- }
- if (buffer[0] != expected_type)
- {
- DEBUGOUT_1 ("unexpected bulk-in msg type (%02x)\n", buffer[0]);
- return -1;
- }
- if (buffer[5] != 0)
- {
- DEBUGOUT_1 ("unexpected bulk-in slot (%d)\n", buffer[5]);
- return -1;
- }
- if (buffer[6] != seqno)
- {
- DEBUGOUT_2 ("bulk-in seqno does not match (%d/%d)\n",
- seqno, buffer[6]);
- return -1;
- }
-
- if ( !(buffer[7] & 0x03) && (buffer[7] & 0xC0) == 0x80)
- {
- /* Card present and active, time extension requested. */
- DEBUGOUT_2 ("time extension requested (%02X,%02X)\n",
- buffer[7], buffer[8]);
- goto retry;
- }
-
- DEBUGOUT_3 ("status: %02X error: %02X octet[9]: %02X\n"
- " data:", buffer[7], buffer[8], buffer[9] );
- for (i=10; i < msglen; i++)
- DEBUGOUT_CONT_1 (" %02X", buffer[i]);
- DEBUGOUT_LF ();
-
- 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)
- {
- DEBUGOUT_1 ("usb_intr_read error: %s\n", strerror (errno));
- return -1;
- }
-
- msglen = rc;
- rc = 0;
-
- if (msglen < 1)
- {
- DEBUGOUT ("intr-in msg too short\n");
- return -1;
- }
-
- if (msg[0] == RDR_to_PC_NotifySlotChange)
- {
- DEBUGOUT ("notify slot change:");
- for (i=1; i < msglen; i++)
- for (j=0; j < 4; j++)
- DEBUGOUT_CONT_3 (" %d:%c%c",
- (i-1)*4+j,
- (msg[i] & (1<<(j*2)))? 'p':'-',
- (msg[i] & (2<<(j*2)))? '*':' ');
- DEBUGOUT_LF ();
- }
- else if (msg[0] == RDR_to_PC_HardwareError)
- {
- DEBUGOUT ("hardware error occured\n");
- }
- else
- {
- DEBUGOUT_1 ("unknown intr-in msg of type %02X\n", msg[0]);
- }
-
- return 0;
-}
-
-
-
-int
-ccid_slot_status (ccid_driver_t handle, int *statusbits)
-{
- 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, RDR_to_PC_SlotStatus, seqno);
- if (rc)
- return rc;
- *statusbits = (msg[7] & 3);
-
- 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];
- unsigned char *tpdu;
- size_t msglen, tpdulen;
- unsigned char seqno;
- int use_crc = 0;
- unsigned int edc;
- 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, RDR_to_PC_DataBlock, seqno);
- if (rc)
- return rc;
-
- if (atr)
- {
- size_t n = msglen - 10;
-
- if (n > maxatrlen)
- n = maxatrlen;
- memcpy (atr, msg+10, n);
- *atrlen = n;
- }
-
- /* Setup parameters to select T=1. */
- msg[0] = PC_to_RDR_SetParameters;
- msg[5] = 0; /* slot */
- msg[6] = seqno = handle->seqno++;
- msg[7] = 1; /* Select T=1. */
- msg[8] = 0; /* RFU */
- msg[9] = 0; /* RFU */
-
- /* FIXME: Get those values from the ATR. */
- msg[10]= 0x01; /* Fi/Di */
- msg[11]= 0x10; /* LRC, direct convention. */
- msg[12]= 0; /* Extra guardtime. */
- msg[13]= 0x41; /* BWI/CWI */
- msg[14]= 0; /* No clock stoppping. */
- msg[15]= 254; /* IFSC */
- msg[16]= 0; /* Does not support non default NAD values. */
- set_msg_len (msg, 7);
- msglen = 10 + 7;
-
- DEBUGOUT ("sending");
- for (i=0; i < msglen; i++)
- DEBUGOUT_CONT_1 (" %02X", msg[i]);
- DEBUGOUT_LF ();
-
- rc = bulk_out (handle, msg, msglen);
- if (rc)
- return rc;
- /* Note that we ignore the error code on purpose. */
- bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Parameters, seqno);
-
-
- /* Send an S-Block with our maximun IFSD to the CCID. */
- if (!handle->auto_ifsd)
- {
- tpdu = msg+10;
- /* NAD: DAD=1, SAD=0 */
- tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
- tpdu[1] = (0xc0 | 0 | 1); /* S-block request: change IFSD */
- tpdu[2] = 1;
- tpdu[3] = handle->max_ifsd? handle->max_ifsd : 32;
- tpdulen = 4;
- edc = compute_edc (tpdu, tpdulen, use_crc);
- if (use_crc)
- tpdu[tpdulen++] = (edc >> 8);
- tpdu[tpdulen++] = edc;
-
- msg[0] = PC_to_RDR_XfrBlock;
- msg[5] = 0; /* slot */
- msg[6] = seqno = handle->seqno++;
- msg[7] = 0;
- msg[8] = 0; /* RFU */
- msg[9] = 0; /* RFU */
- set_msg_len (msg, tpdulen);
- msglen = 10 + tpdulen;
-
- DEBUGOUT ("sending");
- for (i=0; i < msglen; i++)
- DEBUGOUT_CONT_1 (" %02X", msg[i]);
- DEBUGOUT_LF ();
-
-#ifdef DEBUG_T1
- fprintf (stderr, "T1: put %c-block seq=%d\n",
- ((msg[11] & 0xc0) == 0x80)? 'R' :
- (msg[11] & 0x80)? 'S' : 'I',
- ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)));
-#endif
-
- rc = bulk_out (handle, msg, msglen);
- if (rc)
- return rc;
-
- /* Fixme: The next line for the current Valgrid without support
- for USB IOCTLs. */
- memset (msg, 0, sizeof msg);
-
- rc = bulk_in (handle, msg, sizeof msg, &msglen,
- RDR_to_PC_DataBlock, seqno);
- if (rc)
- return rc;
-
- tpdu = msg + 10;
- tpdulen = msglen - 10;
-
- if (tpdulen < 4)
- {
- DEBUGOUT ("cannot yet handle short blocks!\n");
- return -1;
- }
-
-#ifdef DEBUG_T1
- fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
- ((msg[11] & 0xc0) == 0x80)? 'R' :
- (msg[11] & 0x80)? 'S' : 'I',
- ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
- ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0
- );
-#endif
- if ((tpdu[1] & 0xe0) != 0xe0 || tpdu[2] != 1)
- {
- DEBUGOUT ("invalid response for S-block (Change-IFSD)\n");
- return -1;
- }
- DEBUGOUT_1 ("IFSD has been set to %d\n", tpdu[3]);
- }
-
- return 0;
-}
-
-
-
-
-static unsigned int
-compute_edc (const unsigned char *data, size_t datalen, int use_crc)
-{
- if (use_crc)
- {
- return 0x42; /* Not yet implemented. */
- }
- else
- {
- unsigned char crc = 0;
-
- for (; datalen; datalen--)
- crc ^= *data++;
- return crc;
- }
-}
-
-
-/*
- 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 nodes.
-
- 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_buf, size_t apdu_buflen,
- unsigned char *resp, size_t maxresplen, size_t *nresp)
-{
- int rc;
- unsigned char send_buffer[10+259], recv_buffer[10+259];
- const unsigned char *apdu;
- size_t apdulen;
- unsigned char *msg, *tpdu, *p;
- size_t msglen, tpdulen, last_tpdulen, n;
- unsigned char seqno;
- int i;
- unsigned int edc;
- int use_crc = 0;
- size_t dummy_nresp;
- int next_chunk = 1;
- int sending = 1;
- int retries = 0;
-
- if (!nresp)
- nresp = &dummy_nresp;
- *nresp = 0;
-
- tpdulen = 0; /* Avoid compiler warning about no initialization. */
- msg = send_buffer;
- for (;;)
- {
- if (next_chunk)
- {
- next_chunk = 0;
-
- apdu = apdu_buf;
- apdulen = apdu_buflen;
- assert (apdulen);
-
- /* Construct an I-Block. */
- if (apdulen > 254)
- return -1; /* Invalid length. */
-
- tpdu = msg+10;
- /* NAD: DAD=1, SAD=0 */
- tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
- tpdu[1] = ((handle->t1_ns & 1) << 6); /* I-block */
- if (apdulen > 128 /* fixme: replace by ifsc */)
- {
- apdulen = 128;
- apdu_buf += 128;
- apdu_buflen -= 128;
- tpdu[1] |= (1 << 5); /* Set more bit. */
- }
- tpdu[2] = apdulen;
- memcpy (tpdu+3, apdu, apdulen);
- tpdulen = 3 + apdulen;
- edc = compute_edc (tpdu, tpdulen, use_crc);
- if (use_crc)
- tpdu[tpdulen++] = (edc >> 8);
- tpdu[tpdulen++] = edc;
- }
-
- 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, tpdulen);
- msglen = 10 + tpdulen;
- last_tpdulen = tpdulen;
-
- DEBUGOUT ("sending");
- for (i=0; i < msglen; i++)
- DEBUGOUT_CONT_1 (" %02X", msg[i]);
- DEBUGOUT_LF ();
-
-#ifdef DEBUG_T1
- fprintf (stderr, "T1: put %c-block seq=%d\n",
- ((msg[11] & 0xc0) == 0x80)? 'R' :
- (msg[11] & 0x80)? 'S' : 'I',
- ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)));
-#endif
-
- rc = bulk_out (handle, msg, msglen);
- if (rc)
- return rc;
-
- /* Fixme: The next line for the current Valgrid without support
- for USB IOCTLs. */
- memset (recv_buffer, 0, sizeof recv_buffer);
-
- msg = recv_buffer;
- rc = bulk_in (handle, msg, sizeof recv_buffer, &msglen,
- RDR_to_PC_DataBlock, seqno);
- if (rc)
- return rc;
-
- tpdu = msg + 10;
- tpdulen = msglen - 10;
-
- if (tpdulen < 4)
- {
- DEBUGOUT ("cannot yet handle short blocks!\n");
- return -1;
- }
-
-#ifdef DEBUG_T1
- fprintf (stderr, "T1: got %c-block seq=%d err=%d\n",
- ((msg[11] & 0xc0) == 0x80)? 'R' :
- (msg[11] & 0x80)? 'S' : 'I',
- ((msg[11] & 0x80)? !!(msg[11]& 0x10) : !!(msg[11] & 0x40)),
- ((msg[11] & 0xc0) == 0x80)? (msg[11] & 0x0f) : 0
- );
-#endif
-
- if (!(tpdu[1] & 0x80))
- { /* This is an I-block. */
- retries = 0;
- if (sending)
- { /* last block sent was successful. */
- handle->t1_ns ^= 1;
- sending = 0;
- }
-
- if (!!(tpdu[1] & 0x40) != handle->t1_nr)
- { /* Reponse does not match our sequence number. */
- msg = send_buffer;
- tpdu = msg+10;
- /* NAD: DAD=1, SAD=0 */
- tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
- tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4 | 2); /* R-block */
- tpdu[2] = 0;
- tpdulen = 3;
- edc = compute_edc (tpdu, tpdulen, use_crc);
- if (use_crc)
- tpdu[tpdulen++] = (edc >> 8);
- tpdu[tpdulen++] = edc;
-
- continue;
- }
-
- handle->t1_nr ^= 1;
-
- p = tpdu + 3; /* Skip the prologue field. */
- n = tpdulen - 3 - 1; /* Strip the epilogue field. */
- /* fixme: verify the checksum. */
- if (resp)
- {
- if (n > maxresplen)
- {
- DEBUGOUT_2 ("provided buffer too short for received data "
- "(%u/%u)\n",
- (unsigned int)n, (unsigned int)maxresplen);
- return -1;
- }
-
- memcpy (resp, p, n);
- resp += n;
- *nresp += n;
- maxresplen -= n;
- }
-
- if (!(tpdu[1] & 0x20))
- return 0; /* No chaining requested - ready. */
-
- msg = send_buffer;
- tpdu = msg+10;
- /* NAD: DAD=1, SAD=0 */
- tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
- tpdu[1] = (0x80 | (handle->t1_nr & 1) << 4); /* R-block */
- tpdu[2] = 0;
- tpdulen = 3;
- edc = compute_edc (tpdu, tpdulen, use_crc);
- if (use_crc)
- tpdu[tpdulen++] = (edc >> 8);
- tpdu[tpdulen++] = edc;
- }
- else if ((tpdu[1] & 0xc0) == 0x80)
- { /* This is a R-block. */
- if ( (tpdu[1] & 0x0f))
- { /* Error: repeat last block */
- if (++retries > 3)
- {
- DEBUGOUT ("3 failed retries\n");
- return -1;
- }
- msg = send_buffer;
- tpdulen = last_tpdulen;
- }
- else if (sending && !!(tpdu[1] & 0x40) == handle->t1_ns)
- { /* Reponse does not match our sequence number. */
- DEBUGOUT ("R-block with wrong seqno received on more bit\n");
- return -1;
- }
- else if (sending)
- { /* Send next chunk. */
- retries = 0;
- msg = send_buffer;
- next_chunk = 1;
- handle->t1_ns ^= 1;
- }
- else
- {
- DEBUGOUT ("unexpected ACK R-block received\n");
- return -1;
- }
- }
- else
- { /* This is a S-block. */
- retries = 0;
- DEBUGOUT_2 ("T1 S-block %s received cmd=%d\n",
- (tpdu[1] & 0x20)? "response": "request",
- (tpdu[1] & 0x1f));
- if ( !(tpdu[1] & 0x20) && (tpdu[1] & 0x1f) == 3 && tpdu[2])
- { /* Wait time extension request. */
- unsigned char bwi = tpdu[3];
- msg = send_buffer;
- tpdu = msg+10;
- /* NAD: DAD=1, SAD=0 */
- tpdu[0] = handle->nonnull_nad? ((1 << 4) | 0): 0;
- tpdu[1] = (0xc0 | 0x20 | 3); /* S-block response */
- tpdu[2] = 1;
- tpdu[3] = bwi;
- tpdulen = 4;
- edc = compute_edc (tpdu, tpdulen, use_crc);
- if (use_crc)
- tpdu[tpdulen++] = (edc >> 8);
- tpdu[tpdulen++] = edc;
- DEBUGOUT_1 ("T1 waittime extension of bwi=%d\n", bwi);
- }
- else
- return -1;
- }
- } /* end T=1 protocol loop. */
-
- return 0;
-}
-
-
-
-
-#ifdef TEST
-int
-main (int argc, char **argv)
-{
- int rc;
- ccid_driver_t ccid;
- unsigned int slotstat;
-
- 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, &slotstat);
- 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*/
diff --git a/scd/ccid-driver.h b/scd/ccid-driver.h
deleted file mode 100644
index 8b86eb1a5..000000000
--- a/scd/ccid-driver.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* 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
- *
- * ALTERNATIVELY, this file may be distributed under the terms of the
- * following license, in which case the provisions of this license are
- * required INSTEAD OF the GNU General Public License. If you wish to
- * allow use of your version of this file only under the terms of the
- * GNU General Public License, and not to allow others to use your
- * version of this file under the terms of the following license,
- * indicate your decision by deleting this paragraph and the license
- * below.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, and the entire permission notice in its entirety,
- * including the disclaimer of warranties.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
- * OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#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_close_reader (ccid_driver_t handle);
-int ccid_get_atr (ccid_driver_t handle,
- unsigned char *atr, size_t maxatrlen, size_t *atrlen);
-int ccid_slot_status (ccid_driver_t handle, int *statusbits);
-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*/
-
-
-
diff --git a/scd/command.c b/scd/command.c
deleted file mode 100644
index 6fa100ff9..000000000
--- a/scd/command.c
+++ /dev/null
@@ -1,1268 +0,0 @@
-/* command.c - SCdaemon command handler
- * Copyright (C) 2001, 2002, 2003, 2004 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 <signal.h>
-
-#include <assuan.h>
-
-#include "scdaemon.h"
-#include <ksba.h>
-#include "app-common.h"
-#include "apdu.h" /* Required for apdu_*_reader (). */
-
-/* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
-#define MAXLEN_PIN 100
-
-
-/* We keep track of the primary client using scdaemon. This one will
- for example receive signal on card change. */
-static ctrl_t primary_connection;
-
-
-#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;
- int event_signal; /* Or 0 if not used. */
-};
-
-
-/* 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)));
-}
-
-
-/* Reset the card and free the application context. With DO_CLOSE set
- to true, close the reader and don't do just a reset. */
-static void
-do_reset (ctrl_t ctrl, int do_close)
-{
- 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)
- {
- release_application (ctrl->app_ctx);
- ctrl->app_ctx = NULL;
- }
- if (ctrl->reader_slot != -1)
- {
- if (do_close || apdu_reset (ctrl->reader_slot))
- {
- apdu_close_reader (ctrl->reader_slot);
- ctrl->reader_slot = -1;
- }
- }
-}
-
-
-static void
-reset_notify (ASSUAN_CONTEXT ctx)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
-
- do_reset (ctrl, 0);
-}
-
-
-static int
-option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
-{
- ctrl_t ctrl = assuan_get_pointer (ctx);
-
- if (!strcmp (key, "event-signal"))
- {
- /* A value of 0 is allowed to reset the event signal. */
- int i = *value? atoi (value) : -1;
- if (i < 0)
- return ASSUAN_Parameter_Error;
- ctrl->server_local->event_signal = i;
- }
-
- 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_t ctrl, const char *apptype)
-{
- int slot;
-
- if (ctrl->app_ctx)
- return 0; /* Already initialized for one specific application. */
- if (ctrl->card_ctx)
- return 0; /* Already initialized using a card context. */
-
- if (ctrl->reader_slot != -1)
- slot = ctrl->reader_slot;
- else
- slot = apdu_open_reader (opt.reader_port);
- ctrl->reader_slot = slot;
- if (slot != -1)
- ctrl->app_ctx = select_application (ctrl, slot, apptype);
- if (!ctrl->app_ctx)
- { /* No application found - fall back to old mode. */
- /* Note that we should rework the old code to use the
- application paradigma too. */
- int rc;
-
- /* If an APPTYPE was requested and it is not pkcs#15, we return
- an error here. */
- if (apptype && !(!strcmp (apptype, "P15") || !strcmp (apptype, "p15")))
- rc = gpg_error (GPG_ERR_NOT_SUPPORTED);
- else
- 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 the
- 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 [APPTYPE]
-
- Return the serial number of the card using a status reponse. This
- functon should be used to check for the presence of a card.
-
- If APPTYPE is given, an application of that type is selected and an
- error is returned if the application is not supported or available.
- The default is to auto-select the application using a hardwired
- preference system. Note, that a future extension to this function
- may allow to specify a list and order of applications to try.
-
- 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, *line? line:NULL)))
- 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
- 110 := Root CA cert (DINSIG)
-
- 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
- escaping 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, NULL)))
- 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);
- }
-
- /* If we are using the modern application paradigma, let the
- application print out its collection of useful status
- information. */
- if (!rc && ctrl->app_ctx)
- rc = app_write_learn_status (ctrl->app_ctx, ctrl);
-
- /* Return information about the certificates. FIXME: Move this into
- an app-p15.c*/
- for (idx=0; !rc && !ctrl->app_ctx; 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 = gpg_error (gpg_err_code_from_errno (errno));
- 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. FIXME: Move this into an
- app-p15.c */
- for (idx=0; !rc && !ctrl->app_ctx; 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 = gpg_error (gpg_err_code_from_errno (errno));
- 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;
-
- 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, NULL)))
- return rc;
-
- line = xstrdup (line); /* Need a copy of the line. */
- if (ctrl->app_ctx)
- {
- rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
- if (rc)
- log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
- }
- else
- {
- rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
- if (rc)
- log_error ("card_read_cert failed: %s\n", gpg_strerror (rc));
- }
- xfree (line);
- line = NULL;
- 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;
- ksba_cert_t kc = NULL;
- ksba_sexp_t p;
-
- if ((rc = open_card (ctrl, NULL)))
- return rc;
-
- line = xstrdup (line); /* Need a copy of the line. */
- if (ctrl->app_ctx)
- {
- rc = app_readcert (ctrl->app_ctx, line, &cert, &ncert);
- if (rc)
- log_error ("app_readcert failed: %s\n", gpg_strerror (rc));
- }
- else
- {
- rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
- if (rc)
- log_error ("card_read_cert failed: %s\n", gpg_strerror (rc));
- }
- xfree (line);
- line = NULL;
- if (rc)
- goto leave;
-
- rc = ksba_cert_new (&kc);
- if (rc)
- {
- xfree (cert);
- goto leave;
- }
- rc = ksba_cert_init_from_mem (kc, cert, ncert);
- if (rc)
- {
- log_error ("failed to parse the certificate: %s\n", gpg_strerror (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;
- unsigned 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 gpg_error (gpg_err_code_from_errno (errno));
-
- /* 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, NULL)))
- 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 = xtrystrdup (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);
- xfree (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, NULL)))
- 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 = xtrystrdup (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);
- xfree (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, NULL)))
- return rc;
-
- keyidstr = xtrystrdup (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);
- xfree (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);
-}
-
-
-/* GETATTR <name>
-
- This command is used to retrieve data from a smartcard. The
- allowed names depend on the currently selected smartcard
- application. NAME must be percent and '+' escaped. The value is
- returned through status message, see the LESRN command for details.
-
- However, the current implementation assumes that Name is not escaped;
- this works as long as noone uses arbitrary escaping.
-
-*/
-static int
-cmd_getattr (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- char *keyword;
-
- if ((rc = open_card (ctrl, NULL)))
- return rc;
-
- keyword = line;
- for (; *line && !spacep (line); line++)
- ;
- if (*line)
- *line++ = 0;
-
- /* (We ignore any garbage for now.) */
-
- rc = app_getattr (ctrl->app_ctx, ctrl, keyword);
-
- 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 *orig_line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- char *keyword;
- int keywordlen;
- size_t nbytes;
- char *line, *linebuf;
-
- if ((rc = open_card (ctrl, NULL)))
- return rc;
-
- /* We need to use a copy of LINE, because PIN_CB uses the same
- context and thus reuses the Assuan provided LINE. */
- line = linebuf = xtrystrdup (orig_line);
- if (!line)
- return ASSUAN_Out_Of_Core;
-
- 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);
- xfree (linebuf);
-
- 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 (*line && !spacep (line))
- line++;
- while (spacep (line))
- line++;
- }
- if (!*line)
- return set_error (Parameter_Error, "no key number given");
- keyno = line;
- while (*line && !spacep (line))
- line++;
- *line = 0;
-
- if ((rc = open_card (ctrl, NULL)))
- return rc;
-
- if (!ctrl->app_ctx)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- keyno = xtrystrdup (keyno);
- if (!keyno)
- return ASSUAN_Out_Of_Core;
- rc = app_genkey (ctrl->app_ctx, ctrl, keyno, force? 1:0, pin_cb, ctx);
- xfree (keyno);
- 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, NULL)))
- 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 (*line && !spacep (line))
- line++;
- while (spacep (line))
- line++;
- }
- if (!*line)
- return set_error (Parameter_Error, "no CHV number given");
- chvnostr = line;
- while (*line && !spacep (line))
- line++;
- *line = 0;
-
- if ((rc = open_card (ctrl, NULL)))
- return rc;
-
- if (!ctrl->app_ctx)
- return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
-
- chvnostr = xtrystrdup (chvnostr);
- if (!chvnostr)
- return ASSUAN_Out_Of_Core;
- 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));
- xfree (chvnostr);
- return map_to_assuan_status (rc);
-}
-
-
-/* CHECKPIN <hexified_id>
-
- */
-static int
-cmd_checkpin (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- char *keyidstr;
-
- if ((rc = open_card (ctrl, NULL)))
- 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 = xtrystrdup (line);
- if (!keyidstr)
- return ASSUAN_Out_Of_Core;
-
- rc = app_check_pin (ctrl->app_ctx,
- keyidstr,
- pin_cb, ctx);
- xfree (keyidstr);
- if (rc)
- log_error ("app_check_pin 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 },
- { "GETATTR", cmd_getattr },
- { "SETATTR", cmd_setattr },
- { "GENKEY", cmd_genkey },
- { "RANDOM", cmd_random },
- { "PASSWD", cmd_passwd },
- { "CHECKPIN", cmd_checkpin },
- { 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 ());
-
- /* Store the primary connection's assuan context. */
- if (!primary_connection)
- primary_connection = &ctrl;
-
- /* We open the reader right at startup so that the ticker is able to
- update the status file. */
- if (ctrl.reader_slot == -1)
- ctrl.reader_slot = apdu_open_reader (opt.reader_port);
-
- /* Command processing loop. */
- 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;
- }
- }
-
- /* The next client will be the primary conenction if this one
- terminates. */
- if (primary_connection == &ctrl)
- primary_connection = NULL;
-
- do_reset (&ctrl, 1); /* 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);
-}
-
-
-
-void
-scd_update_reader_status_file (void)
-{
- static struct {
- int any;
- unsigned int status;
- unsigned int changed;
- } last[10];
- int slot;
- int used;
- unsigned int status, changed;
-
- /* Note, that we only try to get the status, becuase it does not
- make sense to wait here for a operation to complete. If we are
- so busy working with the card, delays in the status file updated
- are should be acceptable. */
- for (slot=0; (slot < DIM(last)
- &&!apdu_enum_reader (slot, &used)); slot++)
- if (used && !apdu_get_status (slot, 0, &status, &changed))
- {
- if (!last[slot].any || last[slot].status != status
- || last[slot].changed != changed )
- {
- char *fname;
- char templ[50];
- FILE *fp;
-
- last[slot].any = 1;
- last[slot].status = status;
- last[slot].changed = changed;
-
- log_info ("updating status of slot %d to 0x%04X\n", slot, status);
-
- sprintf (templ, "reader_%d.status", slot);
- fname = make_filename (opt.homedir, templ, NULL );
- fp = fopen (fname, "w");
- if (fp)
- {
- fprintf (fp, "%s\n",
- (status & 1)? "USABLE":
- (status & 4)? "ACTIVE":
- (status & 2)? "PRESENT": "NOCARD");
- fclose (fp);
- }
- xfree (fname);
-
- /* Send a signal to the primary client, if any. */
- if (primary_connection && primary_connection->server_local
- && primary_connection->server_local->assuan_ctx)
- {
- pid_t pid = assuan_get_pid (primary_connection
- ->server_local->assuan_ctx);
- int signo = primary_connection->server_local->event_signal;
-
- log_info ("client pid is %d, sending signal %d\n", pid, signo);
- if (pid != (pid_t)(-1) && pid && signo > 0)
- kill (pid, signo);
- }
- }
- }
-}
diff --git a/scd/iso7816.c b/scd/iso7816.c
deleted file mode 100644
index fd3f0485c..000000000
--- a/scd/iso7816.c
+++ /dev/null
@@ -1,617 +0,0 @@
-/* iso7816.c - ISO 7816 commands
- * Copyright (C) 2003, 2004 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>
-
-#if defined(GNUPG_SCD_MAIN_HEADER)
-#include GNUPG_SCD_MAIN_HEADER
-#elif GNUPG_MAJOR_VERSION == 1
-/* This is used with GnuPG version < 1.9. The code has been source
- copied from the current GnuPG >= 1.9 and is maintained over
- there. */
-#include "options.h"
-#include "errors.h"
-#include "memory.h"
-#include "util.h"
-#include "i18n.h"
-#else /* GNUPG_MAJOR_VERSION != 1 */
-#include "scdaemon.h"
-#endif /* GNUPG_MAJOR_VERSION != 1 */
-
-#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_MSE 0x22
-#define CMD_PSO 0x2A
-#define CMD_INTERNAL_AUTHENTICATE 0x88
-#define CMD_GENERATE_KEYPAIR 0x47
-#define CMD_GET_CHALLENGE 0x84
-#define CMD_READ_BINARY 0xB0
-#define CMD_READ_RECORD 0xB2
-
-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_FILE_NOT_FOUND: ec = GPG_ERR_ENOENT; break;
- case SW_RECORD_NOT_FOUND:ec= GPG_ERR_NOT_FOUND; 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;
- case SW_HOST_NOT_SUPPORTED: ec = GPG_ERR_NOT_SUPPORTED; break;
- case SW_HOST_LOCKING_FAILED: ec = GPG_ERR_BUG; break;
- case SW_HOST_BUSY: ec = GPG_ERR_EBUSY; 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 a GPG error code. Note that ISO error codes are
- internally mapped. */
-gpg_error_t
-iso7816_select_application (int slot, const char *aid, size_t aidlen)
-{
- static char const openpgp_aid[] = { 0xD2, 0x76, 0x00, 0x01, 0x24, 0x01 };
- int sw;
- int p1 = 0x0C; /* No FCI to be returned. */
-
- if (aidlen == sizeof openpgp_aid
- && !memcmp (aid, openpgp_aid, sizeof openpgp_aid))
- p1 = 0; /* The current openpgp cards don't allow 0x0c. */
-
- sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, p1, aidlen, aid);
- return map_sw (sw);
-}
-
-
-gpg_error_t
-iso7816_select_file (int slot, int tag, int is_dir,
- unsigned char **result, size_t *resultlen)
-{
- int sw, p0, p1;
- unsigned char tagbuf[2];
-
- tagbuf[0] = (tag >> 8) & 0xff;
- tagbuf[1] = tag & 0xff;
-
- if (result || resultlen)
- {
- *result = NULL;
- *resultlen = 0;
- return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- }
- else
- {
- p0 = (tag == 0x3F00)? 0: is_dir? 1:2;
- p1 = 0x0c; /* No FC return. */
- sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE,
- p0, p1, 2, tagbuf );
- return map_sw (sw);
- }
-
- return 0;
-}
-
-
-/* This is a private command currently only working for TCOS cards. */
-gpg_error_t
-iso7816_list_directory (int slot, int list_dirs,
- 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, 0x80, 0xAA, list_dirs? 1:2, 0, -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);
-}
-
-
-
-/* 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 gpg_error (gpg_err_code_from_errno (errno));
- 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);
-}
-
-/* Manage Security Environment. This is a weird operation and there
- is no easy abstraction for it. Furthermore, some card seem to have
- a different interpreation of 7816-8 and thus we resort to let the
- caller decide what to do. */
-gpg_error_t
-iso7816_manage_security_env (int slot, int p1, int p2,
- const unsigned char *data, size_t datalen)
-{
- int sw;
-
- if (p1 < 0 || p1 > 255 || p2 < 0 || p2 > 255 || !data || !datalen)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- sw = apdu_send_simple (slot, 0x00, CMD_MSE, p1, p2, 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. PADIND is the padding
- indicator to be used. It should be 0 if no padding is required, a
- value of -1 suppresses the padding byte. 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,
- int padind, 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;
-
- if (padind >= 0)
- {
- /* We need to prepend the padding indicator. */
- buf = xtrymalloc (datalen + 1);
- if (!buf)
- return gpg_error (gpg_err_code_from_errno (errno));
-
- *buf = padind; /* Padding indicator. */
- memcpy (buf+1, data, datalen);
- sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, datalen+1, buf,
- result, resultlen);
- xfree (buf);
- }
- else
- {
- sw = apdu_send (slot, 0x00, CMD_PSO, 0x80, 0x86, 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_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
-do_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 do_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 do_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;
-}
-
-/* Perform a READ BINARY command requesting a maximum of NMAX bytes
- from OFFSET. With NMAX = 0 the entire file is read. The result is
- stored in a newly allocated buffer at the address passed by RESULT.
- Returns the length of this data at the address of RESULTLEN. */
-gpg_error_t
-iso7816_read_binary (int slot, size_t offset, size_t nmax,
- unsigned char **result, size_t *resultlen)
-{
- int sw;
- unsigned char *buffer;
- size_t bufferlen;
- int read_all = !nmax;
- size_t n;
-
- if (!result || !resultlen)
- return gpg_error (GPG_ERR_INV_VALUE);
- *result = NULL;
- *resultlen = 0;
-
- /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
- we check for this limit. */
- if (offset > 32767)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- do
- {
- buffer = NULL;
- bufferlen = 0;
- /* Fixme: Either the ccid driver or the TCOS cards have problems
- with an Le of 0. */
- if (read_all || nmax > 254)
- n = 254;
- else
- n = nmax;
- sw = apdu_send_le (slot, 0x00, CMD_READ_BINARY,
- ((offset>>8) & 0xff), (offset & 0xff) , -1, NULL,
- n, &buffer, &bufferlen);
-
- if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
- {
- /* Make sure that pending buffers are released. */
- xfree (buffer);
- xfree (*result);
- *result = NULL;
- *resultlen = 0;
- return map_sw (sw);
- }
- if (*result) /* Need to extend the buffer. */
- {
- unsigned char *p = xtryrealloc (*result, *resultlen + bufferlen);
- if (!p)
- {
- gpg_error_t err = gpg_error_from_errno (errno);
- xfree (buffer);
- xfree (*result);
- *result = NULL;
- *resultlen = 0;
- return err;
- }
- *result = p;
- memcpy (*result + *resultlen, buffer, bufferlen);
- *resultlen += bufferlen;
- xfree (buffer);
- buffer = NULL;
- }
- else /* Transfer the buffer into our result. */
- {
- *result = buffer;
- *resultlen = bufferlen;
- }
- offset += bufferlen;
- if (offset > 32767)
- break; /* We simply truncate the result for too large
- files. */
- if (nmax > bufferlen)
- nmax -= bufferlen;
- else
- nmax = 0;
- }
- while ((read_all && sw != SW_EOF_REACHED) || (!read_all && nmax));
-
- return 0;
-}
-
-/* Perform a READ RECORD command. RECNO gives the record number to
- read with 0 indicating the current record. RECCOUNT must be 1 (not
- all cards support reading of more than one record). SHORT_EF
- should be 0 to read the current EF or contain a short EF. The
- result is stored in a newly allocated buffer at the address passed
- by RESULT. Returns the length of this data at the address of
- RESULTLEN. */
-gpg_error_t
-iso7816_read_record (int slot, int recno, int reccount, int short_ef,
- unsigned char **result, size_t *resultlen)
-{
- int sw;
- unsigned char *buffer;
- size_t bufferlen;
-
- if (!result || !resultlen)
- return gpg_error (GPG_ERR_INV_VALUE);
- *result = NULL;
- *resultlen = 0;
-
- /* We can only encode 15 bits in p0,p1 to indicate an offset. Thus
- we check for this limit. */
- if (recno < 0 || recno > 255 || reccount != 1
- || short_ef < 0 || short_ef > 254 )
- return gpg_error (GPG_ERR_INV_VALUE);
-
- buffer = NULL;
- bufferlen = 0;
- /* Fixme: Either the ccid driver of the TCOS cards have problems
- with an Le of 0. */
- sw = apdu_send_le (slot, 0x00, CMD_READ_RECORD,
- recno,
- short_ef? short_ef : 0x04,
- -1, NULL,
- 254, &buffer, &bufferlen);
-
- if (sw != SW_SUCCESS && sw != SW_EOF_REACHED)
- {
- /* Make sure that pending buffers are released. */
- xfree (buffer);
- xfree (*result);
- *result = NULL;
- *resultlen = 0;
- return map_sw (sw);
- }
- *result = buffer;
- *resultlen = bufferlen;
-
- return 0;
-}
-
diff --git a/scd/iso7816.h b/scd/iso7816.h
deleted file mode 100644
index 8f2b150e6..000000000
--- a/scd/iso7816.h
+++ /dev/null
@@ -1,73 +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
-
-#if GNUPG_MAJOR_VERSION == 1
-#include "cardglue.h"
-#endif
-
-gpg_error_t iso7816_select_application (int slot,
- const char *aid, size_t aidlen);
-gpg_error_t iso7816_select_file (int slot, int tag, int is_dir,
- unsigned char **result, size_t *resultlen);
-gpg_error_t iso7816_list_directory (int slot, int list_dirs,
- unsigned char **result, size_t *resultlen);
-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_manage_security_env (int slot, int p1, int p2,
- 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,
- int padind,
- 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);
-
-gpg_error_t iso7816_read_binary (int slot, size_t offset, size_t nmax,
- unsigned char **result, size_t *resultlen);
-gpg_error_t iso7816_read_record (int slot, int recno, int reccount,
- int short_ef,
- unsigned char **result, size_t *resultlen);
-
-#endif /*ISO7816_H*/
diff --git a/scd/pcsc-wrapper.c b/scd/pcsc-wrapper.c
deleted file mode 100644
index 4f47ee95c..000000000
--- a/scd/pcsc-wrapper.c
+++ /dev/null
@@ -1,631 +0,0 @@
-/* pcsc-wrapper.c - Wrapper for ccessing the PC/SC service
- * Copyright (C) 2003, 2004 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
- */
-
-/*
- This wrapper is required to handle problems with the libpscslite
- library. That library assumes that pthreads are used and fails
- badly if one tries to use it with a procerss using Pth.
-
- The operation model is pretty simple: It reads requests from stdin
- and returns the answer on stdout. There is no direct mapping to the
- pcsc interface but to a higher level one which resembles the code
- used in scdaemon (apdu.c) when not using Pth or while running under
- Windows.
-
- The interface is binary consisting of a command tag and the length
- of the parameter list. The calling process needs to pass the
- version number of the interface on the command line to make sure
- that both agree on the same interface. For each port a separate
- instance of this process needs to be started.
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <dlfcn.h>
-
-
-#define PGM "pcsc-wrapper"
-
-/* Allow for a standalone build. */
-#ifdef VERSION
-#define MYVERSION_LINE PGM " (GnuPG) " VERSION
-#define BUGREPORT_LINE "\nReport bugs to <[email protected]>.\n"
-#else
-#define MYVERSION_LINE PGM
-#define BUGREPORT_LINE ""
-#endif
-
-#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
-
-
-static int verbose;
-
-
-/* PC/SC constants and function pointer. */
-#define PCSC_SCOPE_USER 0
-#define PCSC_SCOPE_TERMINAL 1
-#define PCSC_SCOPE_SYSTEM 2
-#define PCSC_SCOPE_GLOBAL 3
-
-#define PCSC_PROTOCOL_T0 1
-#define PCSC_PROTOCOL_T1 2
-#define PCSC_PROTOCOL_RAW 4
-
-#define PCSC_SHARE_EXCLUSIVE 1
-#define PCSC_SHARE_SHARED 2
-#define PCSC_SHARE_DIRECT 3
-
-#define PCSC_LEAVE_CARD 0
-#define PCSC_RESET_CARD 1
-#define PCSC_UNPOWER_CARD 2
-#define PCSC_EJECT_CARD 3
-
-struct pcsc_io_request_s {
- unsigned long protocol;
- unsigned long pci_len;
-};
-
-typedef struct pcsc_io_request_s *pcsc_io_request_t;
-
-
-static int driver_is_open; /* True if the PC/SC driver has been
- initialzied and is ready for
- operations. The follwoing variables
- are then valid. */
-static unsigned long pcsc_context; /* The current PC/CS context. */
-static unsigned long pcsc_card;
-static unsigned long pcsc_protocol;
-static unsigned char current_atr[33];
-static size_t current_atrlen;
-
-long (* pcsc_establish_context) (unsigned long scope,
- const void *reserved1,
- const void *reserved2,
- unsigned long *r_context);
-long (* pcsc_release_context) (unsigned long context);
-long (* pcsc_list_readers) (unsigned long context,
- const char *groups,
- char *readers, unsigned long*readerslen);
-long (* pcsc_connect) (unsigned long context,
- const char *reader,
- unsigned long share_mode,
- unsigned long preferred_protocols,
- unsigned long *r_card,
- unsigned long *r_active_protocol);
-long (* pcsc_disconnect) (unsigned long card,
- unsigned long disposition);
-long (* pcsc_status) (unsigned long card,
- char *reader, unsigned long *readerlen,
- unsigned long *r_state,
- unsigned long *r_protocol,
- unsigned char *atr, unsigned long *atrlen);
-long (* pcsc_begin_transaction) (unsigned long card);
-long (* pcsc_end_transaction) (unsigned long card);
-long (* pcsc_transmit) (unsigned long card,
- const pcsc_io_request_t send_pci,
- const unsigned char *send_buffer,
- unsigned long send_len,
- pcsc_io_request_t recv_pci,
- unsigned char *recv_buffer,
- unsigned long *recv_len);
-long (* pcsc_set_timeout) (unsigned long context,
- unsigned long timeout);
-
-
-
-static void
-bad_request (const char *type)
-{
- fprintf (stderr, PGM ": bad `%s' request\n", type);
- exit (1);
-}
-
-static void
-request_failed (int err)
-{
- if (!err)
- err = -1;
-
- putchar (0x81); /* Simple error/success response. */
-
- putchar (0);
- putchar (0);
- putchar (0);
- putchar (4);
-
- putchar ((err >> 24) & 0xff);
- putchar ((err >> 16) & 0xff);
- putchar ((err >> 8) & 0xff);
- putchar ((err ) & 0xff);
-
- fflush (stdout);
-}
-
-
-static void
-request_succeeded (const void *buffer, size_t buflen)
-{
- size_t len;
-
- putchar (0x81); /* Simple error/success response. */
-
- len = 4 + buflen;
- putchar ((len >> 24) & 0xff);
- putchar ((len >> 16) & 0xff);
- putchar ((len >> 8) & 0xff);
- putchar ((len ) & 0xff);
-
- /* Error code. */
- putchar (0);
- putchar (0);
- putchar (0);
- putchar (0);
-
- /* Optional reponse string. */
- if (buffer)
- fwrite (buffer, buflen, 1, stdout);
-
- fflush (stdout);
-}
-
-
-
-static unsigned long
-read_32 (FILE *fp)
-{
- int c1, c2, c3, c4;
-
- c1 = getc (stdin);
- c2 = getc (stdin);
- c3 = getc (stdin);
- c4 = getc (stdin);
- if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
- {
- fprintf (stderr, PGM ": premature EOF while parsing request\n");
- exit (1);
- }
- return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
-}
-
-
-
-static const char *
-pcsc_error_string (long err)
-{
- const char *s;
-
- if (!err)
- return "okay";
- if ((err & 0x80100000) != 0x80100000)
- return "invalid PC/SC error code";
- err &= 0xffff;
- switch (err)
- {
- case 0x0002: s = "cancelled"; break;
- case 0x000e: s = "can't dispose"; break;
- case 0x0008: s = "insufficient buffer"; break;
- case 0x0015: s = "invalid ATR"; break;
- case 0x0003: s = "invalid handle"; break;
- case 0x0004: s = "invalid parameter"; break;
- case 0x0005: s = "invalid target"; break;
- case 0x0011: s = "invalid value"; break;
- case 0x0006: s = "no memory"; break;
- case 0x0013: s = "comm error"; break;
- case 0x0001: s = "internal error"; break;
- case 0x0014: s = "unknown error"; break;
- case 0x0007: s = "waited too long"; break;
- case 0x0009: s = "unknown reader"; break;
- case 0x000a: s = "timeout"; break;
- case 0x000b: s = "sharing violation"; break;
- case 0x000c: s = "no smartcard"; break;
- case 0x000d: s = "unknown card"; break;
- case 0x000f: s = "proto mismatch"; break;
- case 0x0010: s = "not ready"; break;
- case 0x0012: s = "system cancelled"; break;
- case 0x0016: s = "not transacted"; break;
- case 0x0017: s = "reader unavailable"; break;
- case 0x0065: s = "unsupported card"; break;
- case 0x0066: s = "unresponsive card"; break;
- case 0x0067: s = "unpowered card"; break;
- case 0x0068: s = "reset card"; break;
- case 0x0069: s = "removed card"; break;
- case 0x006a: s = "inserted card"; break;
- case 0x001f: s = "unsupported feature"; break;
- case 0x0019: s = "PCI too small"; break;
- case 0x001a: s = "reader unsupported"; break;
- case 0x001b: s = "duplicate reader"; break;
- case 0x001c: s = "card unsupported"; break;
- case 0x001d: s = "no service"; break;
- case 0x001e: s = "service stopped"; break;
- default: s = "unknown PC/SC error code"; break;
- }
- return s;
-}
-
-static void
-load_pcsc_driver (const char *libname)
-{
- void *handle;
-
- handle = dlopen (libname, RTLD_LAZY);
- if (!handle)
- {
- fprintf (stderr, PGM ": failed to open driver `%s': %s",
- libname, dlerror ());
- exit (1);
- }
-
- pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
- pcsc_release_context = dlsym (handle, "SCardReleaseContext");
- pcsc_list_readers = dlsym (handle, "SCardListReaders");
- pcsc_connect = dlsym (handle, "SCardConnect");
- pcsc_disconnect = dlsym (handle, "SCardDisconnect");
- pcsc_status = dlsym (handle, "SCardStatus");
- pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
- pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
- pcsc_transmit = dlsym (handle, "SCardTransmit");
- pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
-
- if (!pcsc_establish_context
- || !pcsc_release_context
- || !pcsc_list_readers
- || !pcsc_connect
- || !pcsc_disconnect
- || !pcsc_status
- || !pcsc_begin_transaction
- || !pcsc_end_transaction
- || !pcsc_transmit
- /* || !pcsc_set_timeout */)
- {
- /* Note that set_timeout is currently not used and also not
- available under Windows. */
- fprintf (stderr,
- "apdu_open_reader: invalid PC/SC driver "
- "(%d%d%d%d%d%d%d%d%d%d)\n",
- !!pcsc_establish_context,
- !!pcsc_release_context,
- !!pcsc_list_readers,
- !!pcsc_connect,
- !!pcsc_disconnect,
- !!pcsc_status,
- !!pcsc_begin_transaction,
- !!pcsc_end_transaction,
- !!pcsc_transmit,
- !!pcsc_set_timeout );
- dlclose (handle);
- exit (1);
- }
-}
-
-
-
-
-/* Handle a open request. The argument is expected to be a string
- with the port indentification. ARGBUF is always guaranteed to be
- terminted by a 0 which is not counted in ARGLEN. We may modifiy
- ARGBUF. */
-static void
-handle_open (unsigned char *argbuf, size_t arglen)
-{
- long err;
- const char * portstr;
- char *list = NULL;
- unsigned long nreader, listlen, atrlen;
- char *p;
- unsigned long card_state, card_protocol;
- unsigned char atr[33];
-
- /* Make sure there is only the port string */
- if (arglen != strlen (argbuf))
- bad_request ("OPEN");
- portstr = argbuf;
-
- if (driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has already been opened\n");
- request_failed (-1);
- }
-
- err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
-
- err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
- if (!err)
- {
- list = malloc (nreader+1); /* Better add 1 for safety reasons. */
- if (!list)
- {
- fprintf (stderr, PGM": error allocating memory for reader list\n");
- exit (1);
- }
- err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
- }
- if (err)
- {
- fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (pcsc_context);
- free (list);
- request_failed (err);
- return;
- }
-
- listlen = nreader;
- p = list;
- while (nreader)
- {
- if (!*p && !p[1])
- break;
- fprintf (stderr, PGM": detected reader `%s'\n", p);
- if (nreader < (strlen (p)+1))
- {
- fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
- break;
- }
- nreader -= strlen (p)+1;
- p += strlen (p) + 1;
- }
-
- err = pcsc_connect (pcsc_context,
- portstr && *portstr? portstr : list,
- PCSC_SHARE_EXCLUSIVE,
- PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
- &pcsc_card,
- &pcsc_protocol);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (pcsc_context);
- free (list);
- request_failed (err);
- return;
- }
-
- atrlen = 32;
- /* (We need to pass a dummy buffer. We use LIST because it ought to
- be large enough.) */
- err = pcsc_status (pcsc_card,
- list, &listlen,
- &card_state, &card_protocol,
- atr, &atrlen);
- free (list);
- if (err)
- {
- fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- pcsc_release_context (pcsc_context);
- request_failed (err);
- return;
- }
- if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
- {
- fprintf (stderr, PGM": ATR returned by pcsc_status is too large\n");
- exit (4);
- }
- memcpy (current_atr, atr, atrlen);
- current_atrlen = atrlen;
- driver_is_open = 1;
- request_succeeded (current_atr, current_atrlen);
-}
-
-
-
-/* Handle a close request. We expect no arguments. We may modifiy
- ARGBUF. */
-static void
-handle_close (unsigned char *argbuf, size_t arglen)
-{
- if (!driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
- request_failed (-1);
- }
-
- pcsc_release_context (pcsc_context);
-
- request_succeeded (NULL, 0);
-}
-
-
-
-/* Handle a transmit request. The argument is expected to be a bufer
- with the APDU. We may modifiy ARGBUF. */
-static void
-handle_transmit (unsigned char *argbuf, size_t arglen)
-{
- long err;
- struct pcsc_io_request_s send_pci;
- unsigned long recv_len;
- unsigned char buffer[1024];
-
- /* The apdu should at least be one byte. */
- if (!arglen)
- bad_request ("TRANSMIT");
-
- if (!driver_is_open)
- {
- fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
- request_failed (-1);
- }
-
- if ((pcsc_protocol & PCSC_PROTOCOL_T1))
- send_pci.protocol = PCSC_PROTOCOL_T1;
- else
- send_pci.protocol = PCSC_PROTOCOL_T0;
- send_pci.pci_len = sizeof send_pci;
- recv_len = sizeof (buffer);
- err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
- NULL, buffer, &recv_len);
- if (err)
- {
- if (verbose)
- fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
- pcsc_error_string (err), err);
- request_failed (err);
- return;
- }
- request_succeeded (buffer, recv_len);
-}
-
-
-
-
-
-
-
-
-
-
-
-
-static void
-print_version (int with_help)
-{
- fputs (MYVERSION_LINE "\n"
- "Copyright (C) 2004 Free Software Foundation, Inc.\n"
- "This program comes with ABSOLUTELY NO WARRANTY.\n"
- "This is free software, and you are welcome to redistribute it\n"
- "under certain conditions. See the file COPYING for details.\n",
- stdout);
-
- if (with_help)
- fputs ("\n"
- "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
- "Helper to connect scdaemon to the PC/SC library\n"
- "\n"
- " --verbose enable extra informational output\n"
- " --version print version of the program and exit\n"
- " --help display this help and exit\n"
- BUGREPORT_LINE, stdout );
-
- exit (0);
-}
-
-
-int
-main (int argc, char **argv)
-{
- int last_argc = -1;
- int api_number = 0;
- int c;
-
- if (argc)
- {
- argc--; argv++;
- }
- while (argc && last_argc != argc )
- {
- last_argc = argc;
- if (!strcmp (*argv, "--"))
- {
- argc--; argv++;
- break;
- }
- else if (!strcmp (*argv, "--version"))
- print_version (0);
- else if (!strcmp (*argv, "--help"))
- print_version (1);
- else if (!strcmp (*argv, "--verbose"))
- {
- verbose = 1;
- argc--; argv++;
- }
- }
- if (argc != 1 && argc != 2)
- {
- fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
- exit (1);
- }
-
- api_number = atoi (*argv);
- argv++; argc--;
- if (api_number != 1)
- {
- fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
- exit (1);
- }
-
- load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
-
- while ((c = getc (stdin)) != EOF)
- {
- size_t arglen;
- unsigned char argbuffer[2048];
-
- arglen = read_32 (stdin);
- if (arglen >= sizeof argbuffer - 1)
- {
- fprintf (stderr, PGM ": request too long\n");
- exit (1);
- }
- if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
- {
- fprintf (stderr, PGM ": error reading request: %s\n",
- strerror (errno));
- exit (1);
- }
- argbuffer[arglen] = 0;
- switch (c)
- {
- case 1:
- handle_open (argbuffer, arglen);
- break;
-
- case 2:
- handle_close (argbuffer, arglen);
- exit (0);
- break;
-
- case 3:
- handle_transmit (argbuffer, arglen);
- break;
-
- default:
- fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
- exit (1);
- }
- free (argbuffer);
- }
- return 0;
-}
-
-
-
-/*
-Local Variables:
-compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
-End:
-*/
diff --git a/scd/sc-copykeys.c b/scd/sc-copykeys.c
deleted file mode 100644
index 78cb2acc8..000000000
--- a/scd/sc-copykeys.c
+++ /dev/null
@@ -1,735 +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,
- octapiDriver,
- oDebug,
- oDebugAll,
-
-aTest };
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 301, NULL, 0, "@Options:\n " },
-
- { oVerbose, "verbose", 0, "verbose" },
- { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
- { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"},
- { 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;
- const char *reader_port = NULL;
- 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;
- case oReaderPort: reader_port = pargs.r.ret_str; break;
- case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; 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);
- 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 3882e1dfd..000000000
--- a/scd/sc-investigate.c
+++ /dev/null
@@ -1,770 +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>
-#include <ctype.h>
-#include <unistd.h>
-
-#ifdef HAVE_READLINE_READLINE_H
-#include <readline/readline.h>
-#include <readline/history.h>
-#endif
-
-#define JNLIB_NEED_LOG_LOGV
-#include "scdaemon.h"
-#include <gcrypt.h>
-
-#include "apdu.h" /* for open_reader */
-#include "atr.h"
-#include "app-common.h"
-#include "iso7816.h"
-
-#define _(a) (a)
-
-#define CONTROL_D ('D' - 'A' + 1)
-
-
-enum cmd_and_opt_values
-{
- oInteractive = 'i',
- oVerbose = 'v',
- oQuiet = 'q',
- oReaderPort = 500,
- octapiDriver,
-
- oDebug,
- oDebugAll,
-
- oDisableCCID,
-
-
- oGenRandom,
-
-aTest };
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 301, NULL, 0, "@Options:\n " },
-
- { oInteractive, "interactive", 0, "start in interactive explorer mode"},
- { oQuiet, "quiet", 0, "quiet" },
- { oVerbose, "verbose", 0, "verbose" },
- { oReaderPort, "reader-port", 2, "|N|connect to reader at port N"},
- { octapiDriver, "ctapi-driver", 2, "NAME|use NAME as ctAPI driver"},
- { oDisableCCID, "disable-ccid", 0,
-#ifdef HAVE_LIBUSB
- "do not use the internal CCID driver"
-#else
- "@"
-#endif
- },
- { 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 void interactive_shell (int slot);
-static void dump_other_cards (int slot);
-
-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;
- const char *reader_port = NULL;
- unsigned long gen_random = 0;
- int interactive = 0;
-
- set_strusage (my_strusage);
- gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
- log_set_prefix ("sc-investigate", 1);
-
- /* Try to auto set the character set. */
- set_native_charset (NULL);
-
- /* 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 oQuiet: opt.quiet++; break;
- case oDebug: opt.debug |= pargs.r.ret_ulong; break;
- case oDebugAll: opt.debug = ~0; break;
- case oReaderPort: reader_port = pargs.r.ret_str; break;
- case octapiDriver: opt.ctapi_driver = pargs.r.ret_str; break;
- case oDisableCCID: opt.disable_ccid = 1; break;
- case oGenRandom: gen_random = pargs.r.ret_ulong; break;
- case oInteractive: interactive = 1; 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 && !opt.quiet)
- {
- rc = atr_dump (slot, stdout);
- if (rc)
- log_error ("can't dump ATR: %s\n", gpg_strerror (rc));
- }
-
- if (interactive)
- interactive_shell (slot);
- else
- {
- struct app_ctx_s appbuf;
-
- /* Fixme: We better use app.c directly. */
- memset (&appbuf, 0, sizeof appbuf);
- appbuf.slot = slot;
- rc = app_select_openpgp (&appbuf);
- if (rc)
- {
- if (!opt.quiet)
- log_info ("selecting openpgp failed: %s\n", gpg_strerror (rc));
- memset (&appbuf, 0, sizeof appbuf);
- appbuf.slot = slot;
- rc = app_select_dinsig (&appbuf);
- if (rc)
- {
- if (!opt.quiet)
- log_info ("selecting dinsig failed: %s\n", gpg_strerror (rc));
- dump_other_cards (slot);
- }
- else
- {
- appbuf.initialized = 1;
- log_info ("dinsig application selected\n");
- }
- }
- 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 */
-}
-
-
-
-/* Dump BUFFER of length NBYTES in a nicely human readable format. */
-static void
-dump_buffer (const unsigned char *buffer, size_t nbytes)
-{
- int i;
-
- while (nbytes)
- {
- for (i=0; i < 16 && i < nbytes; i++)
- printf ("%02X%s ", buffer[i], i==8? " ":"");
- for (; i < 16; i++)
- printf (" %s ", i==8? " ":"");
- putchar (' ');
- putchar (' ');
- for (i=0; i < 16 && i < nbytes; i++)
- if (isprint (buffer[i]))
- putchar (buffer[i]);
- else
- putchar ('.');
- nbytes -= i;
- buffer += i;
- for (; i < 16; i++)
- putchar (' ');
- putchar ('\n');
- }
-}
-
-
-static void
-dump_or_store_buffer (const char *arg,
- const unsigned char *buffer, size_t nbytes)
-{
- const char *s = strchr (arg, '>');
- int append;
- FILE *fp;
-
- if (!s)
- {
- dump_buffer (buffer, nbytes);
- return;
- }
- if ((append = (*++s == '>')))
- s++;
- fp = fopen (s, append? "ab":"wb");
- if (!fp)
- {
- log_error ("failed to create `%s': %s\n", s, strerror (errno));
- return;
- }
- if (nbytes && fwrite (buffer, nbytes, 1, fp) != 1)
- log_error ("failed to write to `%s': %s\n", s, strerror (errno));
- if (fclose (fp))
- log_error ("failed to close `%s': %s\n", s, strerror (errno));
-}
-
-
-/* Convert STRING into a a newly allocated buffer and return the
- length of the buffer in R_LENGTH. Detect xx:xx:xx... sequence and
- unhexify that one. */
-static unsigned char *
-pin_to_buffer (const char *string, size_t *r_length)
-{
- unsigned char *buffer = xmalloc (strlen (string)+1);
- const char *s;
- size_t n;
-
- for (s=string, n=0; *s; s += 3)
- {
- if (hexdigitp (s) && hexdigitp (s+1) && (s[2]==':'||!s[2]))
- {
- buffer[n++] = xtoi_2 (s);
- if (!s[2])
- break;
- }
- else
- {
- memcpy (buffer, string, strlen (string));
- *r_length = strlen (string);
- return buffer;
- }
- }
- *r_length = n;
- return buffer;
-}
-
-
-static char *
-read_line (int use_readline, char *prompt)
-{
- static char buf[256];
-
-#ifdef HAVE_READLINE
- if (use_readline)
- {
- char *line = readline (prompt);
- if (line)
- trim_spaces (line);
- if (line && strlen (line) > 2 )
- add_history (line);
- return line;
- }
-#endif
- /* Either we don't have readline or we are not running
- interactively */
-#ifndef HAVE_READLINE
- printf ("%s", prompt );
-#endif
- fflush(stdout);
- if (!fgets(buf, sizeof(buf), stdin))
- return NULL;
- if (!strlen(buf))
- return NULL;
- if (buf[strlen (buf)-1] == '\n')
- buf[strlen (buf)-1] = 0;
- trim_spaces (buf);
- return buf;
-}
-
-/* Run a shell for interactive exploration of the card. */
-static void
-interactive_shell (int slot)
-{
- enum cmdids
- {
- cmdNOP = 0,
- cmdQUIT, cmdHELP,
- cmdSELECT,
- cmdCHDIR,
- cmdLS,
- cmdAPP,
- cmdREAD,
- cmdREADREC,
- cmdREADSHORTREC,
- cmdDEBUG,
- cmdVERIFY,
- cmdCHANGEREF,
-
- cmdINVCMD
- };
- static struct
- {
- const char *name;
- enum cmdids id;
- const char *desc;
- } cmds[] = {
- { "quit" , cmdQUIT , "quit this menu" },
- { "q" , cmdQUIT , NULL },
- { "help" , cmdHELP , "show this help" },
- { "?" , cmdHELP , NULL },
- { "debug" , cmdDEBUG, "set debugging flags" },
- { "select" , cmdSELECT, "select file (EF)" },
- { "s" , cmdSELECT, NULL },
- { "chdir" , cmdCHDIR, "change directory (select DF)"},
- { "cd" , cmdCHDIR, NULL },
- { "ls" , cmdLS, "list directory (some cards only)"},
- { "app" , cmdAPP, "select application"},
- { "read" , cmdREAD, "read binary" },
- { "rb" , cmdREAD, NULL },
- { "readrec", cmdREADREC, "read record(s)" },
- { "rr" , cmdREADREC, NULL },
- { "rsr" , cmdREADSHORTREC, "readshortrec RECNO SHORT_EF" },
- { "verify" , cmdVERIFY, "verify CHVNO PIN" },
- { "ver" , cmdVERIFY, NULL },
- { "changeref", cmdCHANGEREF, "change reference data" },
- { NULL, cmdINVCMD }
- };
- enum cmdids cmd = cmdNOP;
- int use_readline = isatty (fileno(stdin));
- char *line;
- gpg_error_t err = 0;
- unsigned char *result = NULL;
- size_t resultlen;
-
-#ifdef HAVE_READLINE
- if (use_readline)
- using_history ();
-#endif
-
- for (;;)
- {
- int arg_number;
- const char *arg_string = "";
- const char *arg_next = "";
- char *p;
- int i;
-
- if (err)
- printf ("command failed: %s\n", gpg_strerror (err));
- err = 0;
- xfree (result);
- result = NULL;
-
- printf ("\n");
- do
- {
- line = read_line (use_readline, "cmd> ");
- }
- while ( line && *line == '#' );
-
- arg_number = 0;
- if (!line || *line == CONTROL_D)
- cmd = cmdQUIT;
- else if (!*line)
- cmd = cmdNOP;
- else {
- if ((p=strchr (line,' ')))
- {
- char *endp;
-
- *p++ = 0;
- trim_spaces (line);
- trim_spaces (p);
- arg_number = strtol (p, &endp, 0);
- arg_string = p;
- if (endp != p)
- {
- arg_next = endp;
- while ( spacep (arg_next) )
- arg_next++;
- }
- }
-
- for (i=0; cmds[i].name; i++ )
- if (!ascii_strcasecmp (line, cmds[i].name ))
- break;
-
- cmd = cmds[i].id;
- }
-
- switch (cmd)
- {
- case cmdHELP:
- for (i=0; cmds[i].name; i++ )
- if (cmds[i].desc)
- printf("%-10s %s\n", cmds[i].name, _(cmds[i].desc) );
- break;
-
- case cmdQUIT:
- goto leave;
-
- case cmdNOP:
- break;
-
- case cmdDEBUG:
- if (!*arg_string)
- opt.debug = opt.debug? 0 : 2048;
- else
- opt.debug = arg_number;
- break;
-
- case cmdSELECT:
- err = iso7816_select_file (slot, arg_number, 0, NULL, NULL);
- break;
-
- case cmdCHDIR:
- err = iso7816_select_file (slot, arg_number, 1, NULL, NULL);
- break;
-
- case cmdLS:
- err = iso7816_list_directory (slot, 1, &result, &resultlen);
- if (!err || gpg_err_code (err) == GPG_ERR_ENOENT)
- err = iso7816_list_directory (slot, 0, &result, &resultlen);
- /* FIXME: Do something with RESULT. */
- break;
-
- case cmdAPP:
- {
- app_t app;
-
- app = select_application (NULL, slot, *arg_string? arg_string:NULL);
- if (app)
- {
- char *sn;
-
- app_get_serial_and_stamp (app, &sn, NULL);
- log_info ("application `%s' ready; sn=%s\n",
- app->apptype?app->apptype:"?", sn? sn:"[none]");
- release_application (app);
- }
- }
- break;
-
- case cmdREAD:
- err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
- if (!err)
- dump_or_store_buffer (arg_string, result, resultlen);
- break;
-
- case cmdREADREC:
- if (*arg_string == '*' && (!arg_string[1] || arg_string[1] == ' '))
- {
- /* Fixme: Can't write to a file yet. */
- for (i=1, err=0; !err; i++)
- {
- xfree (result); result = NULL;
- err = iso7816_read_record (slot, i, 1, 0,
- &result, &resultlen);
- if (!err)
- dump_buffer (result, resultlen);
- }
- if (gpg_err_code (err) == GPG_ERR_NOT_FOUND)
- err = 0;
- }
- else
- {
- err = iso7816_read_record (slot, arg_number, 1, 0,
- &result, &resultlen);
- if (!err)
- dump_or_store_buffer (arg_string, result, resultlen);
- }
- break;
-
- case cmdREADSHORTREC:
- {
- int short_ef;
-
- short_ef = strtol (arg_next, NULL, 0);
-
- if (short_ef < 1 || short_ef > 254)
- printf ("error: short EF must be between 1 and 254\n");
- else
- {
- err = iso7816_read_record (slot, arg_number, 1, short_ef,
- &result, &resultlen);
- if (!err)
- dump_or_store_buffer (arg_string, result, resultlen);
- }
- }
- break;
-
- case cmdVERIFY:
- if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31)
- printf ("error: invalid CHVNO\n");
- else
- {
- unsigned char *pin;
- size_t pinlen;
-
- pin = pin_to_buffer (arg_next, &pinlen);
- err = iso7816_verify (slot, arg_number, pin, pinlen);
- xfree (pin);
- }
- break;
-
- case cmdCHANGEREF:
- {
- const char *newpin = arg_next;
-
- while ( *newpin && !spacep (newpin) )
- newpin++;
- while ( spacep (newpin) )
- newpin++;
-
- if (arg_number < 0 || arg_number > 255 || (arg_number & 127) > 31)
- printf ("error: invalid CHVNO\n");
- else if (!*arg_next || !*newpin || newpin == arg_next)
- printf ("usage: changeref CHVNO OLDPIN NEWPIN\n");
- else
- {
- char *oldpin = xstrdup (arg_next);
- unsigned char *oldpin_buf, *newpin_buf;
- size_t oldpin_len, newpin_len;
-
- for (p=oldpin; *p && !spacep (p); p++ )
- ;
- *p = 0;
- oldpin_buf = pin_to_buffer (oldpin, &oldpin_len);
- newpin_buf = pin_to_buffer (newpin, &newpin_len);
-
- err = iso7816_change_reference_data (slot, arg_number,
- oldpin_buf, oldpin_len,
- newpin_buf, newpin_len);
-
- xfree (newpin_buf);
- xfree (oldpin_buf);
- xfree (oldpin);
- }
- }
- break;
-
- case cmdINVCMD:
- default:
- printf ("\n");
- printf ("Invalid command (try \"help\")\n");
- break;
- } /* End command switch. */
- } /* End of main menu loop. */
-
- leave:
- ;
-}
-
-
-
-/* Figure out whether the current card is a German Geldkarte and print
- what we know about it. */
-static int
-dump_geldkarte (int slot)
-{
- unsigned char *r = NULL;
- size_t rlen;
- const char *t;
-
- if (iso7816_read_record (slot, 1, 1, 0xbc, &r, &rlen))
- return -1;
- /* We require that the record is at least 24 bytes, the first byte
- is 0x67 and the filler byte is correct. */
- if (rlen < 24 || *r != 0x67 || r[22])
- return -1;
-
- /* The short Bankleitzahl consists of 3 bytes at offset 1. */
- switch (r[1])
- {
- case 0x21: t = "Oeffentlich-rechtliche oder private Bank"; break;
- case 0x22: t = "Privat- oder Gesch�ftsbank"; break;
- case 0x25: t = "Sparkasse"; break;
- case 0x26:
- case 0x29: t = "Genossenschaftsbank"; break;
- default:
- xfree (r);
- return -1; /* Probably not a Geldkarte. */
- }
-
- printf ("KBLZ .....: %02X-%02X%02X (%s)\n", r[1], r[2], r[3], t);
- printf ("Card-No ..: %02X%02X%02X%02X%02X\n", r[4], r[5], r[6], r[7], r[8]);
-
-/* Byte 10 enth�lt im linken Halbbyte eine Pr�fziffer, die nach dem */
-/* Verfahren 'Luhn formula for computing modulus 10' �ber die Ziffern der */
-/* ersten 9 Byte berechnet ist. */
-
-/* Das rechte Halbbyte wird zu 'D' gesetzt. */
-
-/* F�r die Berechnung der Luhn-Pr�fziffer sind die folgenden Schritte */
-/* durchzuf�hren: */
-
-/* Schritt 1: Mit der rechtesten Ziffer beginnend ist einschlie�lich dieser */
-/* Ziffer jede �bern�chste Ziffer zu verdoppeln (mit 2 multiplizieren). */
-
-/* Schritt 2: Die einzelnen Ziffern der Produkte aus Schritt 1 und die bei */
-/* diesen Multiplikationen unber�hrt gebliebenen Ziffern sind zu addieren. */
-
-/* Schritt 3: Das Ergebnis der Addition aus Schritt 2 ist von dem auf die */
-/* n�chst h�here Zahl mit der Einerstelle 0 aufgerundeten Ergebnis der */
-/* Addition aus Schritt 2 abzuziehen. Wenn das Ergebnis der Addition aus */
-/* Schritt 2 bereits eine Zahl mit der Einerstelle 0 ergibt (z.B. 30, 40, */
-/* usw.), ist die Pr�fziffer 0. */
-
-/* Beispiel: Kartennummer ohne Pr�fziffer: 992 839 871 */
-
-/* 9 9 2 8 3 9 8 7 1 */
-
-/* x 2 x 2 x 2 x 2 x 2 Schritt 1 */
-
-/* 18 4 6 16 2 */
-
-/* 1+8 +9 +4 +8 +6 +9 +1+6 +7 +2 = 61 Schritt 2 */
-
-/* 70-61 = 9 Schritt 3 */
-
-/* Pr�fziffer zu 992 839 871 = 9 */
-
-
- printf ("Expires at: %02X/%02X\n", r[11], r[10] );
- printf ("Valid from: %02X.%02X.%02X\n", r[14], r[13], r[12]);
- printf ("Country ..: %02X%02X\n", r[15], r[16]);
- printf ("Currency .: %c%c%c\n", isascii (r[17])? r[17]:' ',
- isascii (r[18])? r[18]:' ', isascii (r[19])? r[19]:' ');
- printf ("Cur.-Mult : %s\n",
- r[20] == 0x01? "0.01":
- r[20] == 0x02? "0.1":
- r[20] == 0x04? "1":
- r[20] == 0x08? "10":
- r[20] == 0x10? "100":
- r[20] == 0x20? "1000": "?");
- printf ("ZKA ChipID: %02X\n", r[21]);
- printf ("OS version: %02X\n", r[23]);
-
- xfree (r);
- return 0;
-}
-
-
-
-/* Try to figure out the type of teh card and dump its contents. */
-static void
-dump_other_cards (int slot)
-{
-
- if (!dump_geldkarte (slot))
- return;
-
-}
-
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
deleted file mode 100644
index 5e9737ae4..000000000
--- a/scd/scdaemon.c
+++ /dev/null
@@ -1,933 +0,0 @@
-/* scdaemon.c - The GnuPG Smartcard Daemon
- * Copyright (C) 2001, 2002, 2004 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>
-#ifdef USE_GNU_PTH
-# include <pth.h>
-#endif
-
-#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"
-#include "app-common.h"
-
-
-enum cmd_and_opt_values
-{ aNull = 0,
- oCsh = 'c',
- oQuiet = 'q',
- oSh = 's',
- oVerbose = 'v',
-
- oNoVerbose = 500,
- aGPGConfList,
- oOptions,
- oDebug,
- oDebugAll,
- oDebugLevel,
- oDebugWait,
- oDebugSC,
- oNoGreeting,
- oNoOptions,
- oHomedir,
- oNoDetach,
- oNoGrab,
- oLogFile,
- oServer,
- oDaemon,
- oBatch,
- oReaderPort,
- octapiDriver,
- opcscDriver,
- oDisableCCID,
- oDisableOpenSC,
- oAllowAdmin,
- oDenyAdmin,
-
-aTest };
-
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { aGPGConfList, "gpgconf-list", 256, "@" },
-
- { 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, "@"},
- { oDebugAll, "debug-all" ,0, "@"},
- { oDebugLevel, "debug-level" ,2, "@"},
- { 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", 2, N_("|N|connect to reader at port N")},
- { octapiDriver, "ctapi-driver", 2, N_("|NAME|use NAME as ct-API driver")},
- { opcscDriver, "pcsc-driver", 2, N_("|NAME|use NAME as PC/SC driver")},
- { oDisableCCID, "disable-ccid", 0,
-#ifdef HAVE_LIBUSB
- N_("do not use the internal CCID driver")
-#else
- "@"
-#endif
- /* end --disable-ccid */},
- { oDisableOpenSC, "disable-opensc", 0,
-#ifdef HAVE_OPENSC
- N_("do not use the OpenSC layer")
-#else
- "@"
-#endif
- /* end --disable-opensc */},
- { oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")},
- { oDenyAdmin, "deny-admin", 0, "@" },
-
- {0}
-};
-
-
-#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
-
-
-static volatile int caught_fatal_sig = 0;
-
-/* Flag to indicate that a shutdown was requested. */
-static int shutdown_pending;
-
-/* 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];
-
-
-#ifdef USE_GNU_PTH
-/* Pth wrapper function definitions. */
-GCRY_THREAD_OPTION_PTH_IMPL;
-
-static void *ticker_thread (void *arg);
-#endif /*USE_GNU_PTH*/
-
-
-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_GT );
-#else
-#ifdef ENABLE_NLS
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE_GT, LOCALEDIR);
- textdomain (PACKAGE_GT);
-#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);
-}
-
-
-/* Setup the debugging. With a LEVEL of NULL only the active debug
- flags are propagated to the subsystems. With LEVEL set, a specific
- set of debug flags is set; thus overriding all flags already
- set. */
-static void
-set_debug (const char *level)
-{
- if (!level)
- ;
- else if (!strcmp (level, "none"))
- opt.debug = 0;
- else if (!strcmp (level, "basic"))
- opt.debug = DBG_ASSUAN_VALUE;
- else if (!strcmp (level, "advanced"))
- opt.debug = DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE;
- else if (!strcmp (level, "expert"))
- opt.debug = (DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE
- |DBG_CACHE_VALUE|DBG_CARD_IO_VALUE);
- else if (!strcmp (level, "guru"))
- opt.debug = ~0;
- else
- {
- log_error (_("invalid debug-level `%s' given\n"), level);
- scd_exit(2);
- }
-
-
- if (opt.debug && !opt.verbose)
- opt.verbose = 1;
- if (opt.debug && opt.quiet)
- opt.quiet = 0;
-
- if (opt.debug & DBG_MPI_VALUE)
- gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
- if (opt.debug & DBG_CRYPTO_VALUE )
- gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
- gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
-}
-
-
-
-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;
- gpg_error_t err;
- int may_coredump;
- char **orig_argv;
- FILE *configfp = NULL;
- char *configname = NULL;
- const char *shell;
- unsigned configlineno;
- int parse_debug = 0;
- const char *debug_level = NULL;
- 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 gpgconf_list = 0;
- const char *config_filename = NULL;
-
- 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);
- /* Try to auto set the character set. */
- set_native_charset (NULL);
-
- i18n_init ();
-
- /* Libgcrypt requires us to register the threading model first.
- Note that this will also do the pth_init. */
-#ifdef USE_GNU_PTH
- err = gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pth);
- if (err)
- {
- log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
- gpg_strerror (err));
- }
-#endif /*USE_GNU_PTH*/
-
- /* 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);
- assuan_set_assuan_log_stream (log_get_stream ());
- assuan_set_assuan_log_prefix (log_get_prefix (NULL));
-
- gcry_set_log_handler (my_gcry_logger, NULL);
- gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
-
- may_coredump = disable_core_dumps ();
-
- /* Set default options. */
- opt.pcsc_driver = DEFAULT_PCSC_DRIVER;
-
-
- 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 aGPGConfList: gpgconf_list = 1; break;
- 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 oDebugLevel: debug_level = pargs.r.ret_str; 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: opt.reader_port = 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 oDisableCCID: opt.disable_ccid = 1; break;
- case oDisableOpenSC: opt.disable_opensc = 1; break;
-
- case oAllowAdmin: opt.allow_admin = 1; break;
- case oDenyAdmin: opt.allow_admin = 0; break;
-
- default : pargs.err = configfp? 1:2; break;
- }
- }
- if (configfp)
- {
- fclose( configfp );
- configfp = NULL;
- /* Keep a copy of the config name for use by --gpgconf-list. */
- config_filename = 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);
- }
-
- set_debug (debug_level);
-
- 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");
- }
-
- if (gpgconf_list)
- {
- /* List options and default values in the GPG Conf format. */
-
- /* The following list is taken from gnupg/tools/gpgconf-comp.c. */
- /* Option flags. YOU MUST NOT CHANGE THE NUMBERS OF THE EXISTING
- FLAGS, AS THEY ARE PART OF THE EXTERNAL INTERFACE. */
-#define GC_OPT_FLAG_NONE 0UL
- /* The RUNTIME flag for an option indicates that the option can be
- changed at runtime. */
-#define GC_OPT_FLAG_RUNTIME (1UL << 3)
- /* The DEFAULT flag for an option indicates that the option has a
- default value. */
-#define GC_OPT_FLAG_DEFAULT (1UL << 4)
- /* The DEF_DESC flag for an option indicates that the option has a
- default, which is described by the value of the default field. */
-#define GC_OPT_FLAG_DEF_DESC (1UL << 5)
- /* The NO_ARG_DESC flag for an option indicates that the argument has
- a default, which is described by the value of the ARGDEF field. */
-#define GC_OPT_FLAG_NO_ARG_DESC (1UL << 6)
- if (!config_filename)
- config_filename = make_filename (opt.homedir, "scdaemon.conf", NULL );
-
- printf ("gpgconf-scdaemon.conf:%lu:\"%s\n",
- GC_OPT_FLAG_DEFAULT, config_filename);
-
- printf ("verbose:%lu:\n"
- "quiet:%lu:\n"
- "debug-level:%lu:\"none:\n"
- "log-file:%lu:\n",
- GC_OPT_FLAG_NONE,
- GC_OPT_FLAG_NONE,
- GC_OPT_FLAG_DEFAULT,
- GC_OPT_FLAG_NONE );
-
- printf ("reader-port:%lu:\n", GC_OPT_FLAG_NONE );
- printf ("ctapi-driver:%lu:\n", GC_OPT_FLAG_NONE );
- printf ("pcsc-driver:%lu:\"%s:\n",
- GC_OPT_FLAG_DEFAULT, DEFAULT_PCSC_DRIVER );
-#ifdef HAVE_LIBUSB
- printf ("disable-ccid:%lu:\n", GC_OPT_FLAG_NONE );
-#endif
-#ifdef HAVE_LIBUSB
- printf ("disable-opensc:%lu:\n", GC_OPT_FLAG_NONE );
-#endif
- printf ("allow-admin:%lu:\n", GC_OPT_FLAG_NONE );
-
-
- scd_exit (0);
- }
-
- /* 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 */
-#ifdef USE_GNU_PTH
- pth_attr_t tattr;
-
- tattr = pth_attr_new();
- pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
- pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 64*1024);
- pth_attr_set (tattr, PTH_ATTR_NAME, "ticker");
-
- if (!pth_spawn (tattr, ticker_thread, NULL))
- {
- log_error ("error spawning ticker thread: %s\n", strerror (errno));
- scd_exit (2);
- }
-#endif /*USE_GNU_PTH*/
- 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)
-{
- ctrl->reader_slot = -1;
-}
-
-
-#ifdef USE_GNU_PTH
-
-static void
-handle_signal (int signo)
-{
- switch (signo)
- {
- case SIGHUP:
- log_info ("SIGHUP received - "
- "re-reading configuration and resetting cards\n");
-/* reread_configuration (); */
- break;
-
- case SIGUSR1:
- log_info ("SIGUSR1 received - no action defined\n");
- break;
-
- case SIGUSR2:
- log_info ("SIGUSR2 received - no action defined\n");
- break;
-
- case SIGTERM:
- if (!shutdown_pending)
- log_info ("SIGTERM received - shutting down ...\n");
- else
- log_info ("SIGTERM received - still %ld running threads\n",
- pth_ctrl( PTH_CTRL_GETTHREADS ));
- shutdown_pending++;
- if (shutdown_pending > 2)
- {
- log_info ("shutdown forced\n");
- log_info ("%s %s stopped\n", strusage(11), strusage(13) );
- cleanup ();
- scd_exit (0);
- }
- break;
-
- case SIGINT:
- log_info ("SIGINT received - immediate shutdown\n");
- log_info( "%s %s stopped\n", strusage(11), strusage(13));
- cleanup ();
- scd_exit (0);
- break;
-
- default:
- log_info ("signal %d received - no action defined\n", signo);
- }
-}
-
-static void
-handle_tick (void)
-{
- scd_update_reader_status_file ();
-}
-
-static void *
-ticker_thread (void *dummy_arg)
-{
- pth_event_t sigs_ev, time_ev = NULL;
- sigset_t sigs;
- int signo;
-
- sigemptyset (&sigs );
- sigaddset (&sigs, SIGHUP);
- sigaddset (&sigs, SIGUSR1);
- sigaddset (&sigs, SIGUSR2);
- sigaddset (&sigs, SIGINT);
- sigaddset (&sigs, SIGTERM);
- sigs_ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
-
- for (;;)
- {
- if (!time_ev)
- {
- time_ev = pth_event (PTH_EVENT_TIME, pth_timeout (2, 0));
- if (time_ev)
- pth_event_concat (sigs_ev, time_ev, NULL);
- }
-
- if (pth_wait (sigs_ev) < 1)
- continue;
-
- if (
-#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */
- pth_event_status (sigs_ev) == PTH_STATUS_OCCURRED
-#else
- pth_event_occurred (sigs_ev)
-#endif
- )
- handle_signal (signo);
-
- /* Always run the ticker. */
- if (!shutdown_pending)
- {
- pth_event_isolate (sigs_ev);
- pth_event_free (time_ev, PTH_FREE_ALL);
- time_ev = NULL;
- handle_tick ();
- }
- }
-
- pth_event_free (sigs_ev, PTH_FREE_ALL);
-}
-#endif /*USE_GNU_PTH*/
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
deleted file mode 100644
index 1dd32ae90..000000000
--- a/scd/scdaemon.h
+++ /dev/null
@@ -1,130 +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"
-
-
-#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 */
- const char *ctapi_driver; /* Library to access the ctAPI. */
- const char *pcsc_driver; /* Library to access the PC/SC system. */
- const char *reader_port; /* NULL or reder port to use. */
- int disable_opensc; /* Disable the use of the OpenSC framework. */
- int disable_ccid; /* Disable the use of the internal CCID driver. */
- int allow_admin; /* Allow the use of admin commands for certain
- cards. */
-} 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;
- int reader_slot; /* Slot of the open reader or -1 if not open. */
- 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 server_control_s *ctrl_t;
-typedef struct card_ctx_s *CARD;
-typedef struct app_ctx_s *APP;
-typedef struct app_ctx_s *app_t;
-
-/*-- 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, ...);
-void scd_update_reader_status_file (void);
-
-/*-- 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*/
diff --git a/scd/tlv.c b/scd/tlv.c
deleted file mode 100644
index 5b9d0d6b9..000000000
--- a/scd/tlv.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/* tlv.c - Tag-Length-Value Utilities
- * Copyright (C) 2003, 2004 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 <gpg-error.h>
-
-#include "tlv.h"
-
-static const unsigned char *
-do_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 a too deep
- nesting. */
- const unsigned char *tmp_s;
- size_t tmp_len;
-
- tmp_s = do_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;
- }
-}
-
-
-/* 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. */
-const unsigned char *
-find_tlv (const unsigned char *buffer, size_t length,
- int tag, size_t *nbytes)
-{
- return do_find_tlv (buffer, length, tag, nbytes, 0);
-}
-
-
-
-
-/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
- and the length part from the TLV triplet. Update BUFFER and SIZE
- on success. */
-gpg_error_t
-parse_ber_header (unsigned char const **buffer, size_t *size,
- int *r_class, int *r_tag,
- int *r_constructed, int *r_ndef,
- size_t *r_length, size_t *r_nhdr)
-{
- int c;
- unsigned long tag;
- const unsigned char *buf = *buffer;
- size_t length = *size;
-
- *r_ndef = 0;
- *r_length = 0;
- *r_nhdr = 0;
-
- /* Get the tag. */
- if (!length)
- return gpg_error (GPG_ERR_EOF);
- c = *buf++; length--; ++*r_nhdr;
-
- *r_class = (c & 0xc0) >> 6;
- *r_constructed = !!(c & 0x20);
- tag = c & 0x1f;
-
- if (tag == 0x1f)
- {
- tag = 0;
- do
- {
- tag <<= 7;
- if (!length)
- return gpg_error (GPG_ERR_EOF);
- c = *buf++; length--; ++*r_nhdr;
- tag |= c & 0x7f;
-
- }
- while (c & 0x80);
- }
- *r_tag = tag;
-
- /* Get the length. */
- if (!length)
- return gpg_error (GPG_ERR_EOF);
- c = *buf++; length--; ++*r_nhdr;
-
- if ( !(c & 0x80) )
- *r_length = c;
- else if (c == 0x80)
- *r_ndef = 1;
- else if (c == 0xff)
- return gpg_error (GPG_ERR_BAD_BER);
- else
- {
- unsigned long len = 0;
- int count = c & 0x7f;
-
- if (count > sizeof (len) || count > sizeof (size_t))
- return gpg_error (GPG_ERR_BAD_BER);
-
- for (; count; count--)
- {
- len <<= 8;
- if (!length)
- return gpg_error (GPG_ERR_EOF);
- c = *buf++; length--; ++*r_nhdr;
- len |= c & 0xff;
- }
- *r_length = len;
- }
-
- /* Without this kludge some example certs can't be parsed. */
- if (*r_class == CLASS_UNIVERSAL && !*r_tag)
- *r_length = 0;
-
- *buffer = buf;
- *size = length;
- return 0;
-}
diff --git a/scd/tlv.h b/scd/tlv.h
deleted file mode 100644
index 26a9905f7..000000000
--- a/scd/tlv.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/* tlv.h - Tag-Length-Value Utilities
- * Copyright (C) 2004 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 SCD_TLV_H
-#define SCD_TLV_H 1
-
-
-enum tlv_tag_class {
- CLASS_UNIVERSAL = 0,
- CLASS_APPLICATION = 1,
- CLASS_CONTEXT = 2,
- CLASS_PRIVATE =3
-};
-
-enum tlv_tag_type {
- TAG_NONE = 0,
- TAG_BOOLEAN = 1,
- TAG_INTEGER = 2,
- TAG_BIT_STRING = 3,
- TAG_OCTET_STRING = 4,
- TAG_NULL = 5,
- TAG_OBJECT_ID = 6,
- TAG_OBJECT_DESCRIPTOR = 7,
- TAG_EXTERNAL = 8,
- TAG_REAL = 9,
- TAG_ENUMERATED = 10,
- TAG_EMBEDDED_PDV = 11,
- TAG_UTF8_STRING = 12,
- TAG_REALTIVE_OID = 13,
- TAG_SEQUENCE = 16,
- TAG_SET = 17,
- TAG_NUMERIC_STRING = 18,
- TAG_PRINTABLE_STRING = 19,
- TAG_TELETEX_STRING = 20,
- TAG_VIDEOTEX_STRING = 21,
- TAG_IA5_STRING = 22,
- TAG_UTC_TIME = 23,
- TAG_GENERALIZED_TIME = 24,
- TAG_GRAPHIC_STRING = 25,
- TAG_VISIBLE_STRING = 26,
- TAG_GENERAL_STRING = 27,
- TAG_UNIVERSAL_STRING = 28,
- TAG_CHARACTER_STRING = 29,
- TAG_BMP_STRING = 30
-};
-
-
-
-/* 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.*/
-const unsigned char *find_tlv (const unsigned char *buffer, size_t length,
- int tag, size_t *nbytes);
-
-
-/* ASN.1 BER parser: Parse BUFFER of length SIZE and return the tag
- and the length part from the TLV triplet. Update BUFFER and SIZE
- on success. */
-gpg_error_t parse_ber_header (unsigned char const **buffer, size_t *size,
- int *r_class, int *r_tag,
- int *r_constructed,
- int *r_ndef, size_t *r_length, size_t *r_nhdr);
-
-
-
-#endif /* SCD_TLV_H */