diff options
Diffstat (limited to 'scd')
-rw-r--r-- | scd/ChangeLog | 659 | ||||
-rw-r--r-- | scd/Makefile.am | 85 | ||||
-rw-r--r-- | scd/apdu.c | 1981 | ||||
-rw-r--r-- | scd/apdu.h | 85 | ||||
-rw-r--r-- | scd/app-common.h | 170 | ||||
-rw-r--r-- | scd/app-dinsig.c | 427 | ||||
-rw-r--r-- | scd/app-help.c | 162 | ||||
-rw-r--r-- | scd/app-nks.c | 515 | ||||
-rw-r--r-- | scd/app-openpgp.c | 1640 | ||||
-rw-r--r-- | scd/app.c | 391 | ||||
-rw-r--r-- | scd/atr.c | 287 | ||||
-rw-r--r-- | scd/atr.h | 28 | ||||
-rw-r--r-- | scd/card-common.h | 73 | ||||
-rw-r--r-- | scd/card-dinsig.c | 258 | ||||
-rw-r--r-- | scd/card-p15.c | 500 | ||||
-rw-r--r-- | scd/card.c | 570 | ||||
-rw-r--r-- | scd/ccid-driver.c | 1277 | ||||
-rw-r--r-- | scd/ccid-driver.h | 76 | ||||
-rw-r--r-- | scd/command.c | 1268 | ||||
-rw-r--r-- | scd/iso7816.c | 617 | ||||
-rw-r--r-- | scd/iso7816.h | 73 | ||||
-rw-r--r-- | scd/pcsc-wrapper.c | 631 | ||||
-rw-r--r-- | scd/sc-copykeys.c | 735 | ||||
-rw-r--r-- | scd/sc-investigate.c | 770 | ||||
-rw-r--r-- | scd/scdaemon.c | 933 | ||||
-rw-r--r-- | scd/scdaemon.h | 130 | ||||
-rw-r--r-- | scd/tlv.c | 208 | ||||
-rw-r--r-- | scd/tlv.h | 84 |
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 */ |