aboutsummaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--agent/ChangeLog565
-rw-r--r--agent/Makefile.am62
-rw-r--r--agent/agent.h226
-rw-r--r--agent/cache.c314
-rw-r--r--agent/call-scd.c661
-rw-r--r--agent/command.c782
-rw-r--r--agent/divert-scd.c319
-rw-r--r--agent/findkey.c359
-rw-r--r--agent/genkey.c240
-rw-r--r--agent/gpg-agent.c1063
-rw-r--r--agent/keyformat.txt163
-rw-r--r--agent/learncard.c448
-rw-r--r--agent/minip12.c1140
-rw-r--r--agent/minip12.h33
-rw-r--r--agent/pkdecrypt.c138
-rw-r--r--agent/pksign.c185
-rw-r--r--agent/protect-tool.c977
-rw-r--r--agent/protect.c971
-rw-r--r--agent/query.c473
-rw-r--r--agent/sexp-parse.h98
-rw-r--r--agent/simple-pwquery.c486
-rw-r--r--agent/simple-pwquery.h69
-rw-r--r--agent/trans.c42
-rw-r--r--agent/trustlist.c306
24 files changed, 0 insertions, 10120 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
deleted file mode 100644
index 10f4d45fa..000000000
--- a/agent/ChangeLog
+++ /dev/null
@@ -1,565 +0,0 @@
-2003-07-31 Werner Koch <[email protected]>
-
- * Makefile.am (gpg_agent_LDADD): Added INTLLIBS.
- (gpg_protect_tool_SOURCES): Added simple-pwquery.[ch]
-
-2003-07-27 Werner Koch <[email protected]>
-
- Adjusted for gcry_mpi_print and gcry_mpi_scan API change.
-
-2003-07-15 Werner Koch <[email protected]>
-
- * simple-pwquery.c, simple-pwquery.h: Moved to ../common.
- * Makefile.am (gpg_protect_tool_LDADD): Add simple-pwquery.o.
- Removed it from xx_SOURCES.
-
-2003-07-04 Werner Koch <[email protected]>
-
- * gpg-agent.c (handle_connections): Kludge to allow use of Pth 1
- and 2.
-
-2003-06-30 Werner Koch <[email protected]>
-
- * call-scd.c (learn_status_cb): Store the serialno in PARM.
-
-2003-06-26 Werner Koch <[email protected]>
-
- * call-scd.c (agent_card_serialno): Don't do a RESET anymore.
-
-2003-06-25 Werner Koch <[email protected]>
-
- * command.c (cmd_scd): New.
- * call-scd.c (agent_card_scd): New.
- * divert-scd.c (divert_generic_cmd): New
-
- * call-scd.c (agent_card_learn): New callback args SINFO.
- (learn_status_cb): Pass all other status lines to the sinfo
- callback.
- * learncard.c (release_sinfo, sinfo_cb): New.
- (agent_handle_learn): Pass the new cb to the learn function and
- pass the collected information back to the client's assuan
- connection.
-
- * gpg-agent.c (main): Moved pth_init before gcry_check_version.
-
-2003-06-24 Werner Koch <[email protected]>
-
- * gpg-agent.c (handle_connections): Adjusted for Pth 2.0
-
- Adjusted for changes in the libgcrypt API. Some more fixes for the
- libgpg-error stuff.
-
-2003-06-04 Werner Koch <[email protected]>
-
- 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.
-
- * agent.h: Include gpg-error.h and errno.h
- * Makefile.am: Link with libgpg-error
-
- * query.c: assuan.h is now a system header.
- * genkey.c (agent_genkey): Fixed silly use of xmalloc by
- xtrymalloc.
-
-2003-04-29 Werner Koch <[email protected]>
-
- * command.c (register_commands): Adjusted for new Assuan semantics.
-
- * Makefile.am: Don't override LDFLAGS.
-
-2002-12-04 Werner Koch <[email protected]>
-
- * gpg-agent.c: New variable config_filename.
- (parse_rereadable_options): New.
- (main): Use it here. Add setting of default values, set
- config_filename.
- (reread_configuration): Filled with actual code.
-
-2002-12-03 Werner Koch <[email protected]>
-
- * protect-tool.c (read_key): Don't run make_canonical on a NULL
- buffer.
-
- * command.c (parse_hexstring): New.
- (cmd_sethash): Use it.
- (parse_keygrip): New.
- (cmd_havekey, cmd_sigkey): Use it.
- (cmd_passwd): New.
- * genkey.c (agent_protect_and_store): New.
- (store_key): Add arg FORCE.
- (agent_genkey): Pass false to this force of store_key.
-
-2002-11-13 Werner Koch <[email protected]>
-
- * gpg-agent.c (main): Switch all messages to utf-8.
-
- * simple-pwquery.c (agent_send_all_options): Use $GPG_TTY and
- stdin with ttyname.
-
- * cache.c (new_data): Uiih - /sizeof d/sizeof *d/.
-
-2002-11-10 Werner Koch <[email protected]>
-
- * command.c (option_handler): Fix keep_tty check.
-
-2002-11-06 Werner Koch <[email protected]>
-
- * gpg-agent.c (main): Make sure we have a default ttyname.
- * command.c (option_handler): Check opt.keep_tty here
- * query.c (start_pinentry): but not anymore here.
-
-2002-11-05 Werner Koch <[email protected]>
-
- * agent.h (opt,server_control_s): Move display and lc_ variables
- to the control struct so that they are per connection.
- * gpg-agent.c (agent_init_default_ctrl): New.
- (main): Assign those command line options to new default_* variables.
- Reset DISPLAY in server mode so that tehre is no implicit default.
- * command.c (start_command_handler): Initialize and deinitialize
- the control values.
- (option_handler): Work on the ctrl values and not on the opt.
- * query.c (start_pinentry): New argument CTRL to set the display
- connection specific. Changed all callers to pass this value.
- (agent_askpin,agent_get_passphrase,agent_get_confirmation): Add
- CTRL arg and pass it ot start_pinentry.
- * command.c (cmd_get_passphrase): Pass CTRL argument.
- * trustlist.c (agent_marktrusted): Add CTRL argument
- * command.c (cmd_marktrusted): Pass CTRL argument
- * divert-scd.c (ask_for_card): Add CTRL arg.
- (divert_pksign,divert_pkdecrypt): Ditto. Changed caller.
- (getpin_cb): Use OPAQUE to pass the CTRL variable. Changed both
- users.
- * findkey.c (unprotect): Add CTRL arg.
- (agent_key_from_file): Ditto.
-
- * query.c (unlock_pinentry): Disconnect the pinentry so that we
- start a new one for each request. This is required to support
- clients with different environments (e.g. X magic cookies).
-
-2002-09-05 Neal H. Walfield <[email protected]>
-
- * gpg-agent.c (main) [USE_GNU_PTH]: No need to call
- assuan_set_io_func as assuan is smart.
-
-2002-09-25 Werner Koch <[email protected]>
-
- * gpg-agent.c (handle_signal): Flush cache on SIGHUP.
- * cache.c (agent_flush_cache): New.
-
- * gpg-agent.c, agent.h: Add --keep-display and --keep-tty.
- * query.c (start_pinentry): Implement them. The option passing
- needs more thoughts.
-
-2002-09-09 Werner Koch <[email protected]>
-
- * gpg-agent.c (create_private_keys_directory)
- (create_directories): New.
- (main): Try to create a home directory.
-
-2002-09-04 Neal H. Walfield <[email protected]>
-
- * gpg-agent.c (main): Use sigaction, not signal.
-
-2002-09-03 Neal H. Walfield <[email protected]>
-
- * findkey.c: Include <fcntl.h>.
- (agent_write_private_key): Prefer POSIX compatibity, open and
- fdopen, over the simplicity of GNU extensions, fopen(file, "x").
-
-2002-08-22 Werner Koch <[email protected]>
-
- * query.c (agent_askpin): Provide the default desc text depending
- on the pininfo. Do the basic PIN verification only when
- min_digits is set.
-
-2002-08-21 Werner Koch <[email protected]>
-
- * query.c (agent_askpin): Hack to show the right default prompt.
- (agent_get_passphrase): Ditto.
-
- * trans.c: Removed and replaced all usages with standard _()
-
- * divert-scd.c (getpin_cb): Pass a more descritive text to the
- pinentry.
-
- * Makefile.am: Renamed the binary protect-tool to gpg-protect-tool.
- * protect-tool.c: Removed the note about internal use only.
-
- * gpg-agent.c (main): New option --daemon so that the program is
- not accidently started in the background.
-
-2002-08-16 Werner Koch <[email protected]>
-
- * call-scd.c (learn_status_cb): Handle CERTINFO status.
- (agent_card_learn): Add args for certinfo cb.
- * learncard.c (release_certinfo,certinfo_cb): New.
- (send_cert_back): New. With factored out code from ..
- (agent_handle_learn): here. Return certinfo stuff.
-
-2002-07-26 Werner Koch <[email protected]>
-
- * gpg-agent.c (main): New option --ignore-cache-for-signing.
- * command.c (option_handler): New server option
- use-cache-for-signing defaulting to true.
- (cmd_pksign): handle global and per session option.
- * findkey.c (agent_key_from_file, unprotect): New arg
- ignore_cache. Changed all callers.
- * pksign.c (agent_pksign): Likewise.
-
-2002-06-29 Werner Koch <[email protected]>
-
- * query.c (start_pinentry): Use GNUPG_DERAULT_PINENTRY.
- * call-scd.c (start_scd): Use GNUPG_DEFAULT_SCDAEMON.
-
-2002-06-28 Werner Koch <[email protected]>
-
- * protect-tool.c (export_p12_file): New.
- (main): New command --p12-export.
- * minip12.c (create_final,p12_build,compute_tag_length): New.
- (store_tag_length): New.
-
-2002-06-27 Werner Koch <[email protected]>
-
- * minip12.c (crypt_block): Renamed from decrypt_block, add arg to
- allow encryption.
-
- * Makefile.am (pkglib_PROGRAMS): Put protect-tool there.
-
- * findkey.c (agent_write_private_key,agent_key_from_file)
- (agent_key_available): Use GNUPG_PRIVATE_KEYS_DIR constant.
- * gpg-agent.c (main): Use GNUPG_DEFAULT_HOMEDIR constant.
-
- * protect-tool.c (store_private_key): New.
- (import_p12_file): Store the new file if requested.
- (main): New options --force and --store.
-
- * gpg-agent.c (main): Set a global flag when running detached.
- * query.c (start_pinentry): Pass the list of FD to keep in the
- child when not running detached.
- * call-scd.c (start_scd): Ditto.
-
-2002-06-26 Werner Koch <[email protected]>
-
- * command.c (cmd_istrusted, cmd_listtrusted, cmd_marktrusted)
- (cmd_pksign, cmd_pkdecrypt, cmd_genkey, cmd_get_passphrase)
- (cmd_learn): Print an error message for a failed operation.
-
- * simple-pwquery.c, simple-pwquery.h: New.
- * protect-tool. (get_passphrase): New, used to get a passphrase
- from the agent if none was given on the command line.
-
-2002-06-25 Werner Koch <[email protected]>
-
- * protect-tool.c (rsa_key_check): New.
- (import_p12_file): New.
- (main): New command --p12-import.
- * minip12.c, minip12.h: New.
-
-2002-06-24 Werner Koch <[email protected]>
-
- * protect-tool.c (read_file): New.
- (read_key): Factored most code out to read_file.
-
-2002-06-17 Werner Koch <[email protected]>
-
- * agent.h: Add a callback function to the pin_entry_info structure.
- * query.c (agent_askpin): Use the callback to check for a correct
- PIN. Removed the start_err_text argument because it is not
- anymore needed; changed callers.
- * findkey.c (unprotect): Replace our own check loop by a callback.
- (try_unprotect_cb): New.
- * genkey.c (reenter_compare_cb): New.
- (agent_genkey): Use this callback here. Fixed setting of the pi2
- variable and a segv in case of an empty PIN.
-
- * divert-scd.c (getpin_cb): Removed some unused stuff and
- explained what we still have to change.
-
-2002-06-12 Werner Koch <[email protected]>
-
- * gpg-agent.c (main): New option --disable-pth.
-
-2002-06-11 Werner Koch <[email protected]>
-
- * protect-tool.c: Add command --show-keygrip
- (show_keygrip): New.
-
-2002-05-23 Werner Koch <[email protected]>
-
- * call-scd.c: Seirialized all scdaeom access when using Pth.
-
- * cache.c: Made the cache Pth-thread-safe.
- (agent_unlock_cache_entry): New.
- * findkey.c (unprotect): Unlock the returned cache value.
- * command.c (cmd_get_passphrase): Ditto.
-
- * gpg-agent.c (main): Register pth_read/write with Assuan.
-
-2002-05-22 Werner Koch <[email protected]>
-
- * query.c: Serialized all pinentry access when using Pth.
-
- * gpg-agent.c (handle_signal,start_connection_thread)
- (handle_connections): New
- (main): Use the new Pth stuff to allow concurrent connections.
- * command.c (start_command_handler): Add new arg FD so that the
- fucntion can also be used for an already connected socket.
- * Makefile.am: Link with Pth.
-
-2002-05-14 Werner Koch <[email protected]>
-
- * cache.c (housekeeping, agent_put_cache): Use our time() wrapper.
-
-2002-04-26 Werner Koch <[email protected]>
-
- * cache.c (agent_put_cache): Reinitialize the creation time and
- the ttl when reusing a slot.
-
- * call-scd.c (start_scd): Print debug messages only with debug
- flags set.
- * query.c (start_pinentry): Ditto.
-
-2002-04-25 Marcus Brinkmann <[email protected]>
-
- * agent.h (agent_get_confirmation): Replace paramter prompt with
- two parameters ok and cancel.
- * query.c (agent_get_confirmation): Likewise. Implement this.
- * trustlist.c (agent_marktrusted): Fix invocation of
- agent_get_confirmation.
- * divert-scd.c (ask_for_card): Likewise.
-
-2002-04-24 Marcus Brinkmann <[email protected]>
-
- * agent.h (struct opt): Add members display, ttyname, ttytype,
- lc_ctype, and lc_messages.
- * gpg-agent.c (enum cmd_and_opt_values): Add oDisplay, oTTYname,
- oTTYtype, oLCctype, and LCmessages.
- (main): Handle these options.
- * command.c (option_handler): New function.
- (register_commands): Register option handler.
- * query.c (start_pinentry): Pass the various display and tty
- options to the pinentry.
-
-2002-04-05 Werner Koch <[email protected]>
-
- * protect-tool.c (show_file): New. Used as default action.
-
-2002-03-28 Werner Koch <[email protected]>
-
- * divert-scd.c (encode_md_for_card): Don't do the pkcs-1 padding,
- the scdaemon should take care of it.
- (ask_for_card): Hack to not display the trailing zero.
-
-2002-03-11 Werner Koch <[email protected]>
-
- * learncard.c (kpinfo_cb): Remove the content restrictions from
- the keyID.
-
-2002-03-06 Werner Koch <[email protected]>
-
- * learncard.c: New.
- * divert-scd.c (ask_for_card): The serial number is binary so
- convert it to hex here.
- * findkey.c (agent_write_private_key): New.
- * genkey.c (store_key): And use it here.
-
- * pkdecrypt.c (agent_pkdecrypt): Changed the way the diversion is done.
- * divert-scd.c (divert_pkdecrypt): Changed interface and
- implemented it.
-
-2002-03-05 Werner Koch <[email protected]>
-
- * call-scd.c (inq_needpin): New.
- (agent_card_pksign): Add getpin_cb args.
- (agent_card_pkdecrypt): New.
-
-2002-03-04 Werner Koch <[email protected]>
-
- * pksign.c (agent_pksign): Changed how the diversion is done.
- * divert-scd.c (divert_pksign): Changed interface and implemented it.
- (encode_md_for_card): New.
- * call-scd.c (agent_card_pksign): New.
-
-2002-02-28 Werner Koch <[email protected]>
-
- * pksign.c (agent_pksign): Detect whether a Smartcard is to be
- used and divert the operation in this case.
- * pkdecrypt.c (agent_pkdecrypt): Likewise
- * findkey.c (agent_key_from_file): Add optional arg shadow_info
- and have it return information about a shadowed key.
- * protect.c (agent_get_shadow_info): New.
-
- * protect.c (snext,sskip,smatch): Moved to
- * sexp-parse.h: new file.
- * divert-scd.c: New.
-
-2002-02-27 Werner Koch <[email protected]>
-
- * protect.c (agent_shadow_key): New.
-
- * command.c (cmd_learn): New command LEARN.
- * gpg-agent.c: New option --scdaemon-program.
- * call-scd.c (start_scd): New. Based on query.c
- * query.c: Add 2 more arguments to all uses of assuan_transact.
-
-2002-02-18 Werner Koch <[email protected]>
-
- * findkey.c (unprotect): Show an error message for a bad passphrase.
-
- * command.c (cmd_marktrusted): Implemented.
- * trustlist.c (agent_marktrusted): New.
- (open_list): Add APPEND arg.
-
- * query.c (agent_get_confirmation): New.
-
-2002-02-06 Werner Koch <[email protected]>
-
- * cache.c (housekeeping): Fixed linking in the remove case.
-
-2002-02-01 Werner Koch <[email protected]>
-
- * gpg-agent.c: New option --default-cache-ttl.
- * cache.c (agent_put_cache): Use it.
-
- * cache.c: Add a few debug outputs.
-
- * protect.c (agent_private_key_type): New.
- * agent.h: Add PRIVATE_KEY_ enums.
- * findkey.c (agent_key_from_file): Use it to decide whether we
- have to unprotect a key.
- (unprotect): Cache the passphrase.
-
- * findkey.c (agent_key_from_file,agent_key_available): The key
- files do now require a ".key" suffix to make a script's life
- easier.
- * genkey.c (store_key): Ditto.
-
-2002-01-31 Werner Koch <[email protected]>
-
- * genkey.c (store_key): Protect the key.
- (agent_genkey): Ask for the passphrase.
- * findkey.c (unprotect): Actually unprotect the key.
- * query.c (agent_askpin): Add an optional start_err_text.
-
-2002-01-30 Werner Koch <[email protected]>
-
- * protect.c: New.
- (hash_passphrase): Based on the GnuPG 1.0.6 version.
- * protect-tool.c: New
-
-2002-01-29 Werner Koch <[email protected]>
-
- * findkey.c (agent_key_available): New.
- * command.c (cmd_havekey): New.
- (register_commands): And register new command.
-
-2002-01-20 Werner Koch <[email protected]>
-
- * command.c (cmd_get_passphrase): Remove the plus signs.
-
- * query.c (start_pinentry): Send no-grab option to pinentry
- * gpg-agent.c (main): Move variable grab as no_grab to agent.h.
-
-2002-01-19 Werner Koch <[email protected]>
-
- * gpg-agent.c (main): Disable core dumps.
-
- * cache.c: New.
- * command.c (cmd_get_passphrase): Use the cache.
- (cmd_clear_passphrase): Ditto.
-
- * gpg-agent.c: Removed unused cruft and implement the socket
- based server.
- (my_strusage): Take bug report address from configure.ac.
- * command.c (start_command_handler): Add an argument to start as
- regular server.
- (start_command_handler): Enable Assuan logging.
-
-2002-01-15 Werner Koch <[email protected]>
-
- * trustlist.c: New.
- * command.c (cmd_istrusted, cmd_listtrusted, cmd_marktrusted): New.
-
-2002-01-07 Werner Koch <[email protected]>
-
- * genkey.c: Store the secret part and return the public part.
-
-2002-01-03 Werner Koch <[email protected]>
-
- * command.c (cmd_get_passphrase): New.
- (cmd_clear_passphrase): New.
- * query.c (agent_get_passphrase): New.
-
-2002-01-02 Werner Koch <[email protected]>
-
- * genkey.c: New.
- * command.c (cmd_genkey): New.
-
- * command.c (rc_to_assuan_status): Removed and changed all callers
- to use map_to_assuan_status.
-
-2001-12-19 Werner Koch <[email protected]>
-
- * keyformat.txt: New.
-
-2001-12-19 Marcus Brinkmann <[email protected]>
-
- * query.c (start_pinentry): Add new argument to assuan_pipe_connect.
-
-2001-12-18 Werner Koch <[email protected]>
-
- * Makefile.am: Use LIBGCRYPT macros
-
-2001-12-14 Werner Koch <[email protected]>
-
- * gpg-agent.c (main): New option --batch. New option --debug-wait
- n, so that it is possible to attach gdb when used in server mode.
- * query.c (agent_askpin): Don't ask in batch mode.
-
- * command.c: Removed the conversion macros as they are now in
- ../common/util.h.
-
-2001-12-14 Marcus Brinkmann <[email protected]>
-
- * query.c (LINELENGTH): Removed.
- (agent_askpin): Use ASSUAN_LINELENGTH, not LINELENGTH.
-
-2001-11-19 Werner Koch <[email protected]>
-
- * gpg-agent.c: Removed all GUI code, removed code for old
- protocol. New code to use the Assuan protocol as a server and
- also to communicate with a new ask-passphrase utility.
-
-2000-11-22 Werner Koch <[email protected]>
-
- * gpg-agent.c (main): csh support by Dan Winship, new options --sh
- and --csh and set default by consulting $SHELL.
-
-Mon Aug 21 17:59:17 CEST 2000 Werner Koch <[email protected]>
-
- * gpg-agent.c (passphrase_dialog): Cleanup the window and added the
- user supplied text to the window.
- (main): Fixed segv in gtk_init when used without a command to start.
-
- * gpg-agent.c: --flush option.
- (req_flush): New.
- (req_clear_passphrase): Implemented.
-
-Fri Aug 18 14:27:14 CEST 2000 Werner Koch <[email protected]>
-
- * gpg-agent.c: New.
- * Makefile.am: New.
-
-
- Copyright 2001, 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/agent/Makefile.am b/agent/Makefile.am
deleted file mode 100644
index 400aa2fd2..000000000
--- a/agent/Makefile.am
+++ /dev/null
@@ -1,62 +0,0 @@
-# Copyright (C) 2001, 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
-
-localedir = $(datadir)/locale
-INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\"
-
-bin_PROGRAMS = gpg-agent
-pkglib_PROGRAMS = gpg-protect-tool
-
-AM_CPPFLAGS = -I$(top_srcdir)/common $(LIBGCRYPT_CFLAGS) \
- $(LIBASSUAN_CFLAGS) $(PTH_CFLAGS)
-
-gpg_agent_SOURCES = \
- gpg-agent.c agent.h \
- command.c \
- query.c \
- cache.c \
- trans.c \
- findkey.c \
- pksign.c \
- pkdecrypt.c \
- genkey.c \
- protect.c \
- trustlist.c \
- divert-scd.c \
- call-scd.c \
- learncard.c \
- sexp-parse.h
-
-
-gpg_agent_LDADD = ../jnlib/libjnlib.a ../common/libcommon.a \
- $(LIBGCRYPT_LIBS) $(PTH_LIBS) $(LIBASSUAN_LIBS) \
- -lgpg-error @INTLLIBS@
-
-gpg_protect_tool_SOURCES = \
- protect-tool.c \
- protect.c \
- simple-pwquery.c simple-pwquery.h \
- minip12.c minip12.h
-
-gpg_protect_tool_LDADD = ../jnlib/libjnlib.a \
- ../common/libcommon.a ../common/libsimple-pwquery.a \
- $(LIBGCRYPT_LIBS) -lgpg-error @INTLLIBS@
-
-
diff --git a/agent/agent.h b/agent/agent.h
deleted file mode 100644
index eb4f4e32d..000000000
--- a/agent/agent.h
+++ /dev/null
@@ -1,226 +0,0 @@
-/* agent.h - Global definitions for the agent
- * 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 AGENT_H
-#define AGENT_H
-
-#ifdef GPG_ERR_SOURCE_DEFAULT
-#error GPG_ERR_SOURCE_DEFAULT already defined
-#endif
-#define GPG_ERR_SOURCE_DEFAULT GPG_ERR_SOURCE_GPGAGENT
-#include <gpg-error.h>
-#include <errno.h>
-
-#include <gcrypt.h>
-#include "../common/util.h"
-#include "../common/errors.h"
-
-/* Convenience function to be used instead of returning the old
- GNUPG_Out_Of_Core. */
-static __inline__ gpg_error_t
-out_of_core (void)
-{
- return gpg_error (gpg_err_code_from_errno (errno));
-}
-
-#define MAX_DIGEST_LEN 24
-
-/* A large struct name "opt" to keep global flags */
-struct {
- unsigned int debug; /* debug flags (DBG_foo_VALUE) */
- 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 *pinentry_program;
- const char *scdaemon_program;
- int no_grab; /* don't let the pinentry grab the keyboard */
- unsigned long def_cache_ttl;
-
- int running_detached; /* we are running detached from the tty. */
-
- int ignore_cache_for_signing;
- int keep_tty; /* don't switch the TTY (for pinentry) on request */
- int keep_display; /* don't switch the DISPLAY (for pinentry) on request */
-} 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_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)
-
-struct server_local_s;
-
-struct server_control_s {
- struct server_local_s *server_local;
- char *display;
- char *ttyname;
- char *ttytype;
- char *lc_ctype;
- char *lc_messages;
- struct {
- int algo;
- unsigned char value[MAX_DIGEST_LEN];
- int valuelen;
- } digest;
- char keygrip[20];
- int have_keygrip;
-
-};
-typedef struct server_control_s *CTRL;
-
-
-struct pin_entry_info_s {
- int min_digits; /* min. number of digits required or 0 for freeform entry */
- int max_digits; /* max. number of allowed digits allowed*/
- int max_tries;
- int failed_tries;
- int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
- void *check_cb_arg; /* optional argument which might be of use in the CB */
- const char *cb_errtext; /* used by the cb to displaye a specific error */
- size_t max_length; /* allocated length of the buffer */
- char pin[1];
-};
-
-
-enum {
- PRIVATE_KEY_UNKNOWN = 0,
- PRIVATE_KEY_CLEAR = 1,
- PRIVATE_KEY_PROTECTED = 2,
- PRIVATE_KEY_SHADOWED = 3
-};
-
-/*-- gpg-agent.c --*/
-void agent_exit (int rc); /* also implemented in other tools */
-void agent_init_default_ctrl (struct server_control_s *ctrl);
-
-/*-- command.c --*/
-void start_command_handler (int, int);
-
-/*-- findkey.c --*/
-int agent_write_private_key (const unsigned char *grip,
- const void *buffer, size_t length, int force);
-gcry_sexp_t agent_key_from_file (CTRL ctrl, const unsigned char *grip,
- unsigned char **shadow_info,
- int ignore_cache);
-int agent_key_available (const unsigned char *grip);
-
-/*-- query.c --*/
-int agent_askpin (CTRL ctrl,
- const char *desc_text, struct pin_entry_info_s *pininfo);
-int agent_get_passphrase (CTRL ctrl, char **retpass,
- const char *desc, const char *prompt,
- const char *errtext);
-int agent_get_confirmation (CTRL ctrl, const char *desc, const char *ok,
- const char *cancel);
-
-/*-- cache.c --*/
-void agent_flush_cache (void);
-int agent_put_cache (const char *key, const char *data, int ttl);
-const char *agent_get_cache (const char *key, void **cache_id);
-void agent_unlock_cache_entry (void **cache_id);
-
-
-/*-- pksign.c --*/
-int agent_pksign (CTRL ctrl, FILE *outfp, int ignore_cache);
-
-/*-- pkdecrypt.c --*/
-int agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
- FILE *outfp);
-
-/*-- genkey.c --*/
-int agent_genkey (CTRL ctrl,
- const char *keyparam, size_t keyparmlen, FILE *outfp);
-int agent_protect_and_store (CTRL ctrl, gcry_sexp_t s_skey);
-
-/*-- protect.c --*/
-int agent_protect (const unsigned char *plainkey, const char *passphrase,
- unsigned char **result, size_t *resultlen);
-int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
- unsigned char **result, size_t *resultlen);
-int agent_private_key_type (const unsigned char *privatekey);
-int agent_shadow_key (const unsigned char *pubkey,
- const unsigned char *shadow_info,
- unsigned char **result);
-int agent_get_shadow_info (const unsigned char *shadowkey,
- unsigned char const **shadow_info);
-
-
-/*-- trustlist.c --*/
-int agent_istrusted (const char *fpr);
-int agent_listtrusted (void *assuan_context);
-int agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag);
-
-
-/*-- divert-scd.c --*/
-int divert_pksign (CTRL ctrl,
- const unsigned char *digest, size_t digestlen, int algo,
- const unsigned char *shadow_info, unsigned char **r_sig);
-int divert_pkdecrypt (CTRL ctrl,
- const unsigned char *cipher,
- const unsigned char *shadow_info,
- char **r_buf, size_t *r_len);
-int divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context);
-
-
-/*-- call-scd.c --*/
-int agent_card_learn (void (*kpinfo_cb)(void*, const char *),
- void *kpinfo_cb_arg,
- void (*certinfo_cb)(void*, const char *),
- void *certinfo_cb_arg,
- void (*sinfo_cb)(void*, const char *,
- size_t, const char *),
- void *sinfo_cb_arg);
-int agent_card_serialno (char **r_serialno);
-int agent_card_pksign (const char *keyid,
- int (*getpin_cb)(void *, const char *, char*, size_t),
- void *getpin_cb_arg,
- const unsigned char *indata, size_t indatalen,
- char **r_buf, size_t *r_buflen);
-int agent_card_pkdecrypt (const char *keyid,
- int (*getpin_cb)(void *, const char *, char*,size_t),
- void *getpin_cb_arg,
- const unsigned char *indata, size_t indatalen,
- char **r_buf, size_t *r_buflen);
-int agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen);
-int agent_card_readkey (const char *id, unsigned char **r_buf);
-int agent_card_scd (const char *cmdline,
- int (*getpin_cb)(void *, const char *, char*, size_t),
- void *getpin_cb_arg, void *assuan_context);
-
-
-/*-- learncard.c --*/
-int agent_handle_learn (void *assuan_context);
-
-
-#endif /*AGENT_H*/
diff --git a/agent/cache.c b/agent/cache.c
deleted file mode 100644
index b6ab55085..000000000
--- a/agent/cache.c
+++ /dev/null
@@ -1,314 +0,0 @@
-/* cache.c - keep a cache of passphrases
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <assert.h>
-
-#include "agent.h"
-
-struct secret_data_s {
- int totallen; /* this includes the padding */
- int datalen; /* actual data length */
- char data[1];
-};
-
-typedef struct cache_item_s *ITEM;
-struct cache_item_s {
- ITEM next;
- time_t created;
- time_t accessed;
- int ttl; /* max. lifetime given in seonds */
- int lockcount;
- struct secret_data_s *pw;
- char key[1];
-};
-
-
-static ITEM thecache;
-
-
-static void
-release_data (struct secret_data_s *data)
-{
- xfree (data);
-}
-
-static struct secret_data_s *
-new_data (const void *data, size_t length)
-{
- struct secret_data_s *d;
- int total;
-
- /* we pad the data to 32 bytes so that it get more complicated
- finding something out by watching allocation patterns. This is
- usally not possible but we better assume nothing about our
- secure storage provider*/
- total = length + 32 - (length % 32);
-
- d = gcry_malloc_secure (sizeof *d + total - 1);
- if (d)
- {
- d->totallen = total;
- d->datalen = length;
- memcpy (d->data, data, length);
- }
- return d;
-}
-
-
-/* check whether there are items to expire */
-static void
-housekeeping (void)
-{
- ITEM r, rprev;
- time_t current = gnupg_get_time ();
-
- /* first expire the actual data */
- for (r=thecache; r; r = r->next)
- {
- if (!r->lockcount && r->pw && r->accessed + r->ttl < current)
- {
- if (DBG_CACHE)
- log_debug (" expired `%s' (%ds after last access)\n",
- r->key, r->ttl);
- release_data (r->pw);
- r->pw = NULL;
- r->accessed = current;
- }
- }
-
- /* second, make sure that we also remove them based on the created stamp so
- that the user has to enter it from time to time. We do this every hour */
- for (r=thecache; r; r = r->next)
- {
- if (!r->lockcount && r->pw && r->created + 60*60 < current)
- {
- if (DBG_CACHE)
- log_debug (" expired `%s' (1h after creation)\n", r->key);
- release_data (r->pw);
- r->pw = NULL;
- r->accessed = current;
- }
- }
-
- /* third, make sure that we don't have too many items in the list.
- Expire old and unused entries after 30 minutes */
- for (rprev=NULL, r=thecache; r; )
- {
- if (!r->pw && r->accessed + 60*30 < current)
- {
- if (r->lockcount)
- {
- log_error ("can't remove unused cache entry `%s' due to"
- " lockcount=%d\n",
- r->key, r->lockcount);
- r->accessed += 60*10; /* next error message in 10 minutes */
- rprev = r;
- r = r->next;
- }
- else
- {
- ITEM r2 = r->next;
- if (DBG_CACHE)
- log_debug (" removed `%s' (slot not used for 30m)\n", r->key);
- xfree (r);
- if (!rprev)
- thecache = r2;
- else
- rprev->next = r2;
- r = r2;
- }
- }
- else
- {
- rprev = r;
- r = r->next;
- }
- }
-}
-
-
-void
-agent_flush_cache (void)
-{
- ITEM r;
-
- if (DBG_CACHE)
- log_debug ("agent_flush_cache\n");
-
- for (r=thecache; r; r = r->next)
- {
- if (!r->lockcount && r->pw)
- {
- if (DBG_CACHE)
- log_debug (" flushing `%s'\n", r->key);
- release_data (r->pw);
- r->pw = NULL;
- r->accessed = 0;
- }
- else if (r->lockcount && r->pw)
- {
- if (DBG_CACHE)
- log_debug (" marked `%s' for flushing\n", r->key);
- r->accessed = 0;
- r->ttl = 0;
- }
- }
-}
-
-
-
-/* Store DATA of length DATALEN in the cache under KEY and mark it
- with a maximum lifetime of TTL seconds. If there is already data
- under this key, it will be replaced. Using a DATA of NULL deletes
- the entry */
-int
-agent_put_cache (const char *key, const char *data, int ttl)
-{
- ITEM r;
-
- if (DBG_CACHE)
- log_debug ("agent_put_cache `%s'\n", key);
- housekeeping ();
-
- if (ttl < 1)
- ttl = opt.def_cache_ttl;
- if (!ttl)
- return 0;
-
- for (r=thecache; r; r = r->next)
- {
- if (!r->lockcount && !strcmp (r->key, key))
- break;
- }
- if (r)
- { /* replace */
- if (r->pw)
- {
- release_data (r->pw);
- r->pw = NULL;
- }
- if (data)
- {
- r->created = r->accessed = gnupg_get_time ();
- r->ttl = ttl;
- r->pw = new_data (data, strlen (data)+1);
- if (!r->pw)
- log_error ("out of core while allocating new cache item\n");
- }
- }
- else if (data)
- { /* simply insert */
- r = xtrycalloc (1, sizeof *r + strlen (key));
- if (!r)
- log_error ("out of core while allocating new cache control\n");
- else
- {
- strcpy (r->key, key);
- r->created = r->accessed = gnupg_get_time ();
- r->ttl = ttl;
- r->pw = new_data (data, strlen (data)+1);
- if (!r->pw)
- {
- log_error ("out of core while allocating new cache item\n");
- xfree (r);
- }
- else
- {
- r->next = thecache;
- thecache = r;
- }
- }
- }
- return 0;
-}
-
-
-/* Try to find an item in the cache */
-const char *
-agent_get_cache (const char *key, void **cache_id)
-{
- ITEM r;
-
- if (DBG_CACHE)
- log_debug ("agent_get_cache `%s'...\n", key);
- housekeeping ();
-
- /* first try to find one with no locks - this is an updated cache
- entry: We might have entries with a lockcount and without a
- lockcount. */
- for (r=thecache; r; r = r->next)
- {
- if (!r->lockcount && r->pw && !strcmp (r->key, key))
- {
- /* put_cache does only put strings into the cache, so we
- don't need the lengths */
- r->accessed = gnupg_get_time ();
- if (DBG_CACHE)
- log_debug ("... hit\n");
- r->lockcount++;
- *cache_id = r;
- return r->pw->data;
- }
- }
- /* again, but this time get even one with a lockcount set */
- for (r=thecache; r; r = r->next)
- {
- if (r->pw && !strcmp (r->key, key))
- {
- r->accessed = gnupg_get_time ();
- if (DBG_CACHE)
- log_debug ("... hit (locked)\n");
- r->lockcount++;
- *cache_id = r;
- return r->pw->data;
- }
- }
- if (DBG_CACHE)
- log_debug ("... miss\n");
-
- *cache_id = NULL;
- return NULL;
-}
-
-
-void
-agent_unlock_cache_entry (void **cache_id)
-{
- ITEM r;
-
- for (r=thecache; r; r = r->next)
- {
- if (r == *cache_id)
- {
- if (!r->lockcount)
- log_error ("trying to unlock non-locked cache entry `%s'\n",
- r->key);
- else
- r->lockcount--;
- return;
- }
- }
-}
diff --git a/agent/call-scd.c b/agent/call-scd.c
deleted file mode 100644
index 14487f1e3..000000000
--- a/agent/call-scd.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/* call-scd.c - fork of the scdaemon to do SC operations
- * 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
- */
-
-/* Fixme: For now we have serialized all access to the scdaemon which
- make sense becuase the scdaemon can't handle concurrent connections
- right now. We should however keep a list of connections and lock
- just that connection - it migth make sense to implemtn parts of
- this in Assuan.*/
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#ifdef USE_GNU_PTH
-# include <pth.h>
-#endif
-
-#include "agent.h"
-#include <assuan.h>
-
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
-
-static ASSUAN_CONTEXT scd_ctx = NULL;
-#ifdef USE_GNU_PTH
-static pth_mutex_t scd_lock = PTH_MUTEX_INIT;
-#endif
-
-/* callback parameter for learn card */
-struct learn_parm_s {
- void (*kpinfo_cb)(void*, const char *);
- void *kpinfo_cb_arg;
- void (*certinfo_cb)(void*, const char *);
- void *certinfo_cb_arg;
- void (*sinfo_cb)(void*, const char *, size_t, const char *);
- void *sinfo_cb_arg;
-};
-
-struct inq_needpin_s {
- ASSUAN_CONTEXT ctx;
- int (*getpin_cb)(void *, const char *, char*, size_t);
- void *getpin_cb_arg;
-};
-
-struct membuf {
- size_t len;
- size_t size;
- char *buf;
- int out_of_core;
-};
-
-
-
-/* A simple implementation of a dynamic buffer. Use init_membuf() to
- create a buffer, put_membuf to append bytes and get_membuf to
- release and return the buffer. Allocation errors are detected but
- only returned at the final get_membuf(), this helps not to clutter
- the code with out of core checks. */
-
-static void
-init_membuf (struct membuf *mb, int initiallen)
-{
- mb->len = 0;
- mb->size = initiallen;
- mb->out_of_core = 0;
- mb->buf = xtrymalloc (initiallen);
- if (!mb->buf)
- mb->out_of_core = 1;
-}
-
-static void
-put_membuf (struct membuf *mb, const void *buf, size_t len)
-{
- if (mb->out_of_core)
- return;
-
- if (mb->len + len >= mb->size)
- {
- char *p;
-
- mb->size += len + 1024;
- p = xtryrealloc (mb->buf, mb->size);
- if (!p)
- {
- mb->out_of_core = 1;
- return;
- }
- mb->buf = p;
- }
- memcpy (mb->buf + mb->len, buf, len);
- mb->len += len;
-}
-
-static void *
-get_membuf (struct membuf *mb, size_t *len)
-{
- char *p;
-
- if (mb->out_of_core)
- {
- xfree (mb->buf);
- mb->buf = NULL;
- return NULL;
- }
-
- p = mb->buf;
- *len = mb->len;
- mb->buf = NULL;
- mb->out_of_core = 1; /* don't allow a reuse */
- return p;
-}
-
-
-
-
-static int
-unlock_scd (int rc)
-{
-#ifdef USE_GNU_PTH
- if (!pth_mutex_release (&scd_lock))
- {
- log_error ("failed to release the SCD lock\n");
- if (!rc)
- rc = gpg_error (GPG_ERR_INTERNAL);
- }
-#endif
- return rc;
-}
-
-/* Fork off the SCdaemon if this has not already been done */
-static int
-start_scd (void)
-{
- int rc;
- const char *pgmname;
- ASSUAN_CONTEXT ctx;
- const char *argv[3];
- int no_close_list[3];
- int i;
-
-#ifdef USE_GNU_PTH
- if (!pth_mutex_acquire (&scd_lock, 0, NULL))
- {
- log_error ("failed to acquire the SCD lock\n");
- return gpg_error (GPG_ERR_INTERNAL);
- }
-#endif
-
- if (scd_ctx)
- return 0; /* No need to serialize things because the agent is
- expected to tun as a single-thread (or may be in
- future using libpth) */
-
- if (opt.verbose)
- log_info ("no running SCdaemon - starting it\n");
-
- if (fflush (NULL))
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("error flushing pending output: %s\n", strerror (errno));
- return unlock_scd (tmperr);
- }
-
- if (!opt.scdaemon_program || !*opt.scdaemon_program)
- opt.scdaemon_program = GNUPG_DEFAULT_SCDAEMON;
- if ( !(pgmname = strrchr (opt.scdaemon_program, '/')))
- pgmname = opt.scdaemon_program;
- else
- pgmname++;
-
- argv[0] = pgmname;
- argv[1] = "--server";
- argv[2] = NULL;
-
- i=0;
- if (!opt.running_detached)
- {
- if (log_get_fd () != -1)
- no_close_list[i++] = log_get_fd ();
- no_close_list[i++] = fileno (stderr);
- }
- no_close_list[i] = -1;
-
- /* connect to the pinentry and perform initial handshaking */
- rc = assuan_pipe_connect (&ctx, opt.scdaemon_program, (char**)argv,
- no_close_list);
- if (rc)
- {
- log_error ("can't connect to the SCdaemon: %s\n",
- assuan_strerror (rc));
- return unlock_scd (gpg_error (GPG_ERR_NO_SCDAEMON));
- }
- scd_ctx = ctx;
-
- if (DBG_ASSUAN)
- log_debug ("connection to SCdaemon established\n");
- return 0;
-}
-
-
-
-static AssuanError
-learn_status_cb (void *opaque, const char *line)
-{
- struct learn_parm_s *parm = opaque;
- const char *keyword = line;
- int keywordlen;
-
- for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
- ;
- while (spacep (line))
- line++;
- if (keywordlen == 8 && !memcmp (keyword, "CERTINFO", keywordlen))
- {
- parm->certinfo_cb (parm->certinfo_cb_arg, line);
- }
- else if (keywordlen == 11 && !memcmp (keyword, "KEYPAIRINFO", keywordlen))
- {
- parm->kpinfo_cb (parm->kpinfo_cb_arg, line);
- }
- else if (keywordlen && *line)
- {
- parm->sinfo_cb (parm->sinfo_cb_arg, keyword, keywordlen, line);
- }
-
- return 0;
-}
-
-/* Perform the learn command and return a list of all private keys
- stored on the card. */
-int
-agent_card_learn (void (*kpinfo_cb)(void*, const char *),
- void *kpinfo_cb_arg,
- void (*certinfo_cb)(void*, const char *),
- void *certinfo_cb_arg,
- void (*sinfo_cb)(void*, const char *, size_t, const char *),
- void *sinfo_cb_arg)
-{
- int rc;
- struct learn_parm_s parm;
-
- rc = start_scd ();
- if (rc)
- return rc;
-
- memset (&parm, 0, sizeof parm);
- parm.kpinfo_cb = kpinfo_cb;
- parm.kpinfo_cb_arg = kpinfo_cb_arg;
- parm.certinfo_cb = certinfo_cb;
- parm.certinfo_cb_arg = certinfo_cb_arg;
- parm.sinfo_cb = sinfo_cb;
- parm.sinfo_cb_arg = sinfo_cb_arg;
- rc = assuan_transact (scd_ctx, "LEARN --force",
- NULL, NULL, NULL, NULL,
- learn_status_cb, &parm);
- if (rc)
- return unlock_scd (map_assuan_err (rc));
-
- return unlock_scd (0);
-}
-
-
-
-static AssuanError
-get_serialno_cb (void *opaque, const char *line)
-{
- char **serialno = opaque;
- const char *keyword = line;
- const char *s;
- int keywordlen, n;
-
- for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
- ;
- while (spacep (line))
- line++;
-
- if (keywordlen == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
- {
- if (*serialno)
- return ASSUAN_Unexpected_Status;
- for (n=0,s=line; hexdigitp (s); s++, n++)
- ;
- if (!n || (n&1)|| !(spacep (s) || !*s) )
- return ASSUAN_Invalid_Status;
- *serialno = xtrymalloc (n+1);
- if (!*serialno)
- return ASSUAN_Out_Of_Core;
- memcpy (*serialno, line, n);
- (*serialno)[n] = 0;
- }
-
- return 0;
-}
-
-/* Return the serial number of the card or an appropriate error. The
- serial number is returned as a hexstring. */
-int
-agent_card_serialno (char **r_serialno)
-{
- int rc;
- char *serialno = NULL;
-
- rc = start_scd ();
- if (rc)
- return rc;
-
- /* Hmm, do we really need this reset - scddaemon should do this or
- we can do this if we for some reason figure out that the
- operation might have failed due to a missing RESET. Hmmm, I feel
- this is really SCdaemon's duty */
-/* rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); */
-/* if (rc) */
-/* return unlock_scd (map_assuan_err (rc)); */
-
- rc = assuan_transact (scd_ctx, "SERIALNO",
- NULL, NULL, NULL, NULL,
- get_serialno_cb, &serialno);
- if (rc)
- {
- xfree (serialno);
- return unlock_scd (map_assuan_err (rc));
- }
- *r_serialno = serialno;
- return unlock_scd (0);
-}
-
-
-static AssuanError
-membuf_data_cb (void *opaque, const void *buffer, size_t length)
-{
- struct membuf *data = opaque;
-
- if (buffer)
- put_membuf (data, buffer, length);
- return 0;
-}
-
-/* Handle the NEEDPIN inquiry. */
-static AssuanError
-inq_needpin (void *opaque, const char *line)
-{
- struct inq_needpin_s *parm = opaque;
- char *pin;
- size_t pinlen;
- int rc;
-
- if (!(!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7])))
- {
- log_error ("unsupported inquiry `%s'\n", line);
- return ASSUAN_Inquire_Unknown;
- }
- line += 7;
-
- pinlen = 90;
- pin = gcry_malloc_secure (pinlen);
- if (!pin)
- return ASSUAN_Out_Of_Core;
-
- rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen);
- if (rc)
- rc = ASSUAN_Canceled;
- if (!rc)
- rc = assuan_send_data (parm->ctx, pin, pinlen);
- xfree (pin);
-
- return rc;
-}
-
-
-
-/* Create a signature using the current card */
-int
-agent_card_pksign (const char *keyid,
- int (*getpin_cb)(void *, const char *, char*, size_t),
- void *getpin_cb_arg,
- const unsigned char *indata, size_t indatalen,
- char **r_buf, size_t *r_buflen)
-{
- int rc, i;
- char *p, line[ASSUAN_LINELENGTH];
- struct membuf data;
- struct inq_needpin_s inqparm;
- size_t len;
- unsigned char *sigbuf;
- size_t sigbuflen;
-
- *r_buf = NULL;
- rc = start_scd ();
- if (rc)
- return rc;
-
- if (indatalen*2 + 50 > DIM(line))
- return unlock_scd (gpg_error (GPG_ERR_GENERAL));
-
- sprintf (line, "SETDATA ");
- p = line + strlen (line);
- for (i=0; i < indatalen ; i++, p += 2 )
- sprintf (p, "%02X", indata[i]);
- rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_scd (map_assuan_err (rc));
-
- init_membuf (&data, 1024);
- inqparm.ctx = scd_ctx;
- inqparm.getpin_cb = getpin_cb;
- inqparm.getpin_cb_arg = getpin_cb_arg;
- snprintf (line, DIM(line)-1, "PKSIGN %s", keyid);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (scd_ctx, line,
- membuf_data_cb, &data,
- inq_needpin, &inqparm,
- NULL, NULL);
- if (rc)
- {
- xfree (get_membuf (&data, &len));
- return unlock_scd (map_assuan_err (rc));
- }
- sigbuf = get_membuf (&data, &sigbuflen);
-
- /* create an S-expression from it which is formatted like this:
- "(7:sig-val(3:rsa(1:sSIGBUFLEN:SIGBUF)))" */
- *r_buflen = 21 + 11 + sigbuflen + 4;
- *r_buf = xtrymalloc (*r_buflen);
- if (!*r_buf)
- {
- gpg_error_t tmperr = out_of_core ();
- xfree (*r_buf);
- return unlock_scd (tmperr);
- }
- p = stpcpy (*r_buf, "(7:sig-val(3:rsa(1:s" );
- sprintf (p, "%u:", (unsigned int)sigbuflen);
- p += strlen (p);
- memcpy (p, sigbuf, sigbuflen);
- p += sigbuflen;
- strcpy (p, ")))");
- xfree (sigbuf);
-
- assert (gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL));
- return unlock_scd (0);
-}
-
-/* Decipher INDATA using the current card. Note that the returned value is */
-int
-agent_card_pkdecrypt (const char *keyid,
- int (*getpin_cb)(void *, const char *, char*, size_t),
- void *getpin_cb_arg,
- const unsigned char *indata, size_t indatalen,
- char **r_buf, size_t *r_buflen)
-{
- int rc, i;
- char *p, line[ASSUAN_LINELENGTH];
- struct membuf data;
- struct inq_needpin_s inqparm;
- size_t len;
-
- *r_buf = NULL;
- rc = start_scd ();
- if (rc)
- return rc;
-
- /* FIXME: use secure memory where appropriate */
- if (indatalen*2 + 50 > DIM(line))
- return unlock_scd (gpg_error (GPG_ERR_GENERAL));
-
- sprintf (line, "SETDATA ");
- p = line + strlen (line);
- for (i=0; i < indatalen ; i++, p += 2 )
- sprintf (p, "%02X", indata[i]);
- rc = assuan_transact (scd_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_scd (map_assuan_err (rc));
-
- init_membuf (&data, 1024);
- inqparm.ctx = scd_ctx;
- inqparm.getpin_cb = getpin_cb;
- inqparm.getpin_cb_arg = getpin_cb_arg;
- snprintf (line, DIM(line)-1, "PKDECRYPT %s", keyid);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (scd_ctx, line,
- membuf_data_cb, &data,
- inq_needpin, &inqparm,
- NULL, NULL);
- if (rc)
- {
- xfree (get_membuf (&data, &len));
- return unlock_scd (map_assuan_err (rc));
- }
- *r_buf = get_membuf (&data, r_buflen);
- if (!*r_buf)
- return unlock_scd (gpg_error (GPG_ERR_ENOMEM));
-
- return unlock_scd (0);
-}
-
-
-
-/* Read a certificate with ID into R_BUF and R_BUFLEN. */
-int
-agent_card_readcert (const char *id, char **r_buf, size_t *r_buflen)
-{
- int rc;
- char line[ASSUAN_LINELENGTH];
- struct membuf data;
- size_t len;
-
- *r_buf = NULL;
- rc = start_scd ();
- if (rc)
- return rc;
-
- init_membuf (&data, 1024);
- snprintf (line, DIM(line)-1, "READCERT %s", id);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (scd_ctx, line,
- membuf_data_cb, &data,
- NULL, NULL,
- NULL, NULL);
- if (rc)
- {
- xfree (get_membuf (&data, &len));
- return unlock_scd (map_assuan_err (rc));
- }
- *r_buf = get_membuf (&data, r_buflen);
- if (!*r_buf)
- return unlock_scd (gpg_error (GPG_ERR_ENOMEM));
-
- return unlock_scd (0);
-}
-
-
-
-/* Read a key with ID and return it in an allocate buffer pointed to
- by r_BUF as a valid S-expression. */
-int
-agent_card_readkey (const char *id, unsigned char **r_buf)
-{
- int rc;
- char line[ASSUAN_LINELENGTH];
- struct membuf data;
- size_t len, buflen;
-
- *r_buf = NULL;
- rc = start_scd ();
- if (rc)
- return rc;
-
- init_membuf (&data, 1024);
- snprintf (line, DIM(line)-1, "READKEY %s", id);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (scd_ctx, line,
- membuf_data_cb, &data,
- NULL, NULL,
- NULL, NULL);
- if (rc)
- {
- xfree (get_membuf (&data, &len));
- return unlock_scd (map_assuan_err (rc));
- }
- *r_buf = get_membuf (&data, &buflen);
- if (!*r_buf)
- return unlock_scd (gpg_error (GPG_ERR_ENOMEM));
-
- if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL))
- {
- xfree (*r_buf); *r_buf = NULL;
- return unlock_scd (gpg_error (GPG_ERR_INV_VALUE));
- }
-
- return unlock_scd (0);
-}
-
-
-
-
-static AssuanError
-pass_status_thru (void *opaque, const char *line)
-{
- ASSUAN_CONTEXT ctx = opaque;
- char keyword[200];
- int i;
-
- for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
- keyword[i] = *line;
- keyword[i] = 0;
- /* truncate any remaining keyword stuff. */
- for (; *line && !spacep (line); line++)
- ;
- while (spacep (line))
- line++;
-
- assuan_write_status (ctx, keyword, line);
- return 0;
-}
-
-static AssuanError
-pass_data_thru (void *opaque, const void *buffer, size_t length)
-{
- ASSUAN_CONTEXT ctx = opaque;
-
- assuan_send_data (ctx, buffer, length);
- return 0;
-}
-
-
-/* Send the line CMDLINE with command for the SCDdaemon to it and send
- all status messages back. This command is used as a general quoting
- mechanism to pass everything verbatim to SCDAEMOPN. The PIN
- inquirey is handled inside gpg-agent. */
-int
-agent_card_scd (const char *cmdline,
- int (*getpin_cb)(void *, const char *, char*, size_t),
- void *getpin_cb_arg, void *assuan_context)
-{
- int rc;
- struct inq_needpin_s inqparm;
-
- rc = start_scd ();
- if (rc)
- return rc;
-
- inqparm.ctx = scd_ctx;
- inqparm.getpin_cb = getpin_cb;
- inqparm.getpin_cb_arg = getpin_cb_arg;
- rc = assuan_transact (scd_ctx, cmdline,
- pass_data_thru, assuan_context,
- inq_needpin, &inqparm,
- pass_status_thru, assuan_context);
- if (rc)
- {
- return unlock_scd (map_assuan_err (rc));
- }
-
- return unlock_scd (0);
-}
-
-
diff --git a/agent/command.c b/agent/command.c
deleted file mode 100644
index ed4ea6b02..000000000
--- a/agent/command.c
+++ /dev/null
@@ -1,782 +0,0 @@
-/* command.c - gpg-agent command handler
- * 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
- */
-
-/* FIXME: we should not use the default assuan buffering but setup
- some buffering in secure mempory to protect session keys etc. */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-
-#include <assuan.h>
-
-#include "agent.h"
-
-/* maximum allowed size of the inquired ciphertext */
-#define MAXLEN_CIPHERTEXT 4096
-/* maximum allowed size of the key parameters */
-#define MAXLEN_KEYPARAM 1024
-
-#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
-
-
-#if MAX_DIGEST_LEN < 20
-#error MAX_DIGEST_LEN shorter than keygrip
-#endif
-
-/* Data used to associate an Assuan context with local server data */
-struct server_local_s {
- ASSUAN_CONTEXT assuan_ctx;
- int message_fd;
- int use_cache_for_signing;
-};
-
-
-
-
-
-static void
-reset_notify (ASSUAN_CONTEXT ctx)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
-
- memset (ctrl->keygrip, 0, 20);
- ctrl->have_keygrip = 0;
- ctrl->digest.valuelen = 0;
-}
-
-
-/* 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)));
-}
-
-/* Parse a hex string. Return an Assuan error code or 0 on success and the
- length of the parsed string in LEN. */
-static int
-parse_hexstring (ASSUAN_CONTEXT ctx, const char *string, size_t *len)
-{
- const char *p;
- size_t n;
-
- /* parse the hash value */
- for (p=string, n=0; hexdigitp (p); p++, n++)
- ;
- if (*p)
- return set_error (Parameter_Error, "invalid hexstring");
- if ((n&1))
- return set_error (Parameter_Error, "odd number of digits");
- *len = n;
- return 0;
-}
-
-/* Parse the keygrip in STRING into the provided buffer BUF. BUF must
- provide space for 20 bytes. BUF is not changed if the fucntions
- returns an error. */
-static int
-parse_keygrip (ASSUAN_CONTEXT ctx, const char *string, unsigned char *buf)
-{
- int rc;
- size_t n;
- const unsigned char *p;
-
- rc = parse_hexstring (ctx, string, &n);
- if (rc)
- return rc;
- n /= 2;
- if (n != 20)
- return set_error (Parameter_Error, "invalid length of keygrip");
-
- for (p=string, n=0; n < 20; p += 2, n++)
- buf[n] = xtoi_2 (p);
-
- return 0;
-}
-
-
-
-
-/* ISTRUSTED <hexstring_with_fingerprint>
-
- Return OK when we have an entry with this fingerprint in our
- trustlist */
-static int
-cmd_istrusted (ASSUAN_CONTEXT ctx, char *line)
-{
- int rc, n, i;
- char *p;
- char fpr[41];
-
- /* parse the fingerprint value */
- for (p=line,n=0; hexdigitp (p); p++, n++)
- ;
- if (*p || !(n == 40 || n == 32))
- return set_error (Parameter_Error, "invalid fingerprint");
- i = 0;
- if (n==32)
- {
- strcpy (fpr, "00000000");
- i += 8;
- }
- for (p=line; i < 40; p++, i++)
- fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
- fpr[i] = 0;
- rc = agent_istrusted (fpr);
- if (!rc)
- return 0;
- else if (rc == -1)
- return ASSUAN_Not_Trusted;
- else
- {
- log_error ("command is_trusted failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
- }
-}
-
-/* LISTTRUSTED
-
- List all entries from the trustlist */
-static int
-cmd_listtrusted (ASSUAN_CONTEXT ctx, char *line)
-{
- int rc = agent_listtrusted (ctx);
- if (rc)
- log_error ("command listtrusted failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-
-/* MARKTRUSTED <hexstring_with_fingerprint> <flag> <display_name>
-
- Store a new key in into the trustlist*/
-static int
-cmd_marktrusted (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc, n, i;
- char *p;
- char fpr[41];
- int flag;
-
- /* parse the fingerprint value */
- for (p=line,n=0; hexdigitp (p); p++, n++)
- ;
- if (!spacep (p) || !(n == 40 || n == 32))
- return set_error (Parameter_Error, "invalid fingerprint");
- i = 0;
- if (n==32)
- {
- strcpy (fpr, "00000000");
- i += 8;
- }
- for (p=line; i < 40; p++, i++)
- fpr[i] = *p >= 'a'? (*p & 0xdf): *p;
- fpr[i] = 0;
-
- while (spacep (p))
- p++;
- flag = *p++;
- if ( (flag != 'S' && flag != 'P') || !spacep (p) )
- return set_error (Parameter_Error, "invalid flag - must be P or S");
- while (spacep (p))
- p++;
-
- rc = agent_marktrusted (ctrl, p, fpr, flag);
- if (rc)
- log_error ("command marktrusted failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-
-
-
-/* HAVEKEY <hexstring_with_keygrip>
-
- Return success when the secret key is available */
-static int
-cmd_havekey (ASSUAN_CONTEXT ctx, char *line)
-{
- int rc;
- unsigned char buf[20];
-
- rc = parse_keygrip (ctx, line, buf);
- if (rc)
- return rc;
-
- if (agent_key_available (buf))
- return ASSUAN_No_Secret_Key;
-
- return 0;
-}
-
-
-/* SIGKEY <hexstring_with_keygrip>
- SETKEY <hexstring_with_keygrip>
-
- Set the key used for a sign or decrypt operation */
-static int
-cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
-{
- int rc;
- CTRL ctrl = assuan_get_pointer (ctx);
-
- rc = parse_keygrip (ctx, line, ctrl->keygrip);
- if (rc)
- return rc;
- ctrl->have_keygrip = 1;
- return 0;
-}
-
-
-/* SETHASH <algonumber> <hexstring>
-
- The client can use this command to tell the server about the data
- (which usually is a hash) to be signed. */
-static int
-cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
-{
- int rc;
- size_t n;
- char *p;
- CTRL ctrl = assuan_get_pointer (ctx);
- unsigned char *buf;
- char *endp;
- int algo;
-
- /* parse the algo number and check it */
- algo = (int)strtoul (line, &endp, 10);
- for (line = endp; *line == ' ' || *line == '\t'; line++)
- ;
- if (!algo || gcry_md_test_algo (algo))
- return set_error (Unsupported_Algorithm, NULL);
- ctrl->digest.algo = algo;
-
- /* parse the hash value */
- rc = parse_hexstring (ctx, line, &n);
- if (rc)
- return rc;
- n /= 2;
- if (n != 16 && n != 20 && n != 24 && n != 32)
- return set_error (Parameter_Error, "unsupported length of hash");
- if (n > MAX_DIGEST_LEN)
- return set_error (Parameter_Error, "hash value to long");
-
- buf = ctrl->digest.value;
- ctrl->digest.valuelen = n;
- for (p=line, n=0; n < ctrl->digest.valuelen; p += 2, n++)
- buf[n] = xtoi_2 (p);
- for (; n < ctrl->digest.valuelen; n++)
- buf[n] = 0;
- return 0;
-}
-
-
-/* PKSIGN <options>
-
- Perform the actual sign operation. Neither input nor output are
- sensitive to eavesdropping */
-static int
-cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
-{
- int rc;
- int ignore_cache = 0;
- CTRL ctrl = assuan_get_pointer (ctx);
-
- if (opt.ignore_cache_for_signing)
- ignore_cache = 1;
- else if (!ctrl->server_local->use_cache_for_signing)
- ignore_cache = 1;
-
- rc = agent_pksign (ctrl, assuan_get_data_fp (ctx), ignore_cache);
- if (rc)
- log_error ("command pksign failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-/* PKDECRYPT <options>
-
- Perform the actual decrypt operation. Input is not
- sensitive to eavesdropping */
-static int
-cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
-{
- int rc;
- CTRL ctrl = assuan_get_pointer (ctx);
- char *value;
- size_t valuelen;
-
- /* First inquire the data to decrypt */
- rc = assuan_inquire (ctx, "CIPHERTEXT",
- &value, &valuelen, MAXLEN_CIPHERTEXT);
- if (rc)
- return rc;
-
- rc = agent_pkdecrypt (ctrl, value, valuelen, assuan_get_data_fp (ctx));
- xfree (value);
- if (rc)
- log_error ("command pkdecrypt failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-
-/* GENKEY
-
- Generate a new key, store the secret part and return the public
- part. Here is an example transaction:
-
- C: GENKEY
- S: INQUIRE KEYPARM
- C: D (genkey (rsa (nbits 1024)))
- C: END
- S: D (public-key
- S: D (rsa (n 326487324683264) (e 10001)))
- S OK key created
-*/
-
-static int
-cmd_genkey (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- char *value;
- size_t valuelen;
-
- /* First inquire the parameters */
- rc = assuan_inquire (ctx, "KEYPARAM", &value, &valuelen, MAXLEN_KEYPARAM);
- if (rc)
- return rc;
-
- rc = agent_genkey (ctrl, value, valuelen, assuan_get_data_fp (ctx));
- xfree (value);
- if (rc)
- log_error ("command genkey failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-
-static void
-plus_to_blank (char *s)
-{
- for (; *s; s++)
- {
- if (*s == '+')
- *s = ' ';
- }
-}
-
-/* GET_PASSPHRASE <cache_id> [<error_message> <prompt> <description>]
-
- This function is usually used to ask for a passphrase to be used
- for conventional encryption, but may also be used by programs which
- need specal handling of passphrases. This command uses a syntax
- which helps clients to use the agent with minimum effort. The
- agent either returns with an error or with a OK followed by the hex
- encoded passphrase. Note that the length of the strings is
- implicitly limited by the maximum length of a command.
-*/
-
-static int
-cmd_get_passphrase (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- const char *pw;
- char *response;
- char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
- char *p;
- void *cache_marker;
-
- /* parse the stuff */
- for (p=line; *p == ' '; p++)
- ;
- cacheid = p;
- p = strchr (cacheid, ' ');
- if (p)
- {
- *p++ = 0;
- while (*p == ' ')
- p++;
- errtext = p;
- p = strchr (errtext, ' ');
- if (p)
- {
- *p++ = 0;
- while (*p == ' ')
- p++;
- prompt = p;
- p = strchr (prompt, ' ');
- if (p)
- {
- *p++ = 0;
- while (*p == ' ')
- p++;
- desc = p;
- p = strchr (desc, ' ');
- if (p)
- *p = 0; /* ignore garbage */
- }
- }
- }
- if (!cacheid || !*cacheid || strlen (cacheid) > 50)
- return set_error (Parameter_Error, "invalid length of cacheID");
- if (!desc)
- return set_error (Parameter_Error, "no description given");
-
- if (!strcmp (cacheid, "X"))
- cacheid = NULL;
- if (!strcmp (errtext, "X"))
- errtext = NULL;
- if (!strcmp (prompt, "X"))
- prompt = NULL;
- if (!strcmp (desc, "X"))
- desc = NULL;
-
- /* Note: we store the hexified versions in the cache. */
- pw = cacheid ? agent_get_cache (cacheid, &cache_marker) : NULL;
- if (pw)
- {
- assuan_begin_confidential (ctx);
- rc = assuan_set_okay_line (ctx, pw);
- agent_unlock_cache_entry (&cache_marker);
- }
- else
- {
- /* Note, that we only need to replace the + characters and
- should leave the other escaping in place because the escaped
- string is send verbatim to the pinentry which does the
- unescaping (but not the + replacing) */
- if (errtext)
- plus_to_blank (errtext);
- if (prompt)
- plus_to_blank (prompt);
- if (desc)
- plus_to_blank (desc);
-
- rc = agent_get_passphrase (ctrl, &response, desc, prompt, errtext);
- if (!rc)
- {
- if (cacheid)
- agent_put_cache (cacheid, response, 0);
- assuan_begin_confidential (ctx);
- rc = assuan_set_okay_line (ctx, response);
- xfree (response);
- }
- }
-
- if (rc)
- log_error ("command get_passphrase failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-
-/* CLEAR_PASSPHRASE <cache_id>
-
- may be used to invalidate the cache entry for a passphrase. The
- function returns with OK even when there is no cached passphrase.
-*/
-
-static int
-cmd_clear_passphrase (ASSUAN_CONTEXT ctx, char *line)
-{
- char *cacheid = NULL;
- char *p;
-
- /* parse the stuff */
- for (p=line; *p == ' '; p++)
- ;
- cacheid = p;
- p = strchr (cacheid, ' ');
- if (p)
- *p = 0; /* ignore garbage */
- if (!cacheid || !*cacheid || strlen (cacheid) > 50)
- return set_error (Parameter_Error, "invalid length of cacheID");
-
- agent_put_cache (cacheid, NULL, 0);
- return 0;
-}
-
-
-/* LEARN [--send]
-
- Learn something about the currently inserted smartcard. With
- --send the new certificates are send back. */
-static int
-cmd_learn (ASSUAN_CONTEXT ctx, char *line)
-{
- int rc;
-
- rc = agent_handle_learn (has_option (line, "--send")? ctx : NULL);
- if (rc)
- log_error ("command learn failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-
-
-/* PASSWD <hexstring_with_keygrip>
-
- Change the passphrase/PID for the key identified by keygrip in LINE. */
-static int
-cmd_passwd (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
- unsigned char grip[20];
- gcry_sexp_t s_skey = NULL;
- unsigned char *shadow_info = NULL;
-
- rc = parse_keygrip (ctx, line, grip);
- if (rc)
- return rc; /* we can't jump to leave because this is already an
- Assuan error code. */
-
- s_skey = agent_key_from_file (ctrl, grip, &shadow_info, 1);
- if (!s_skey && !shadow_info)
- rc = gpg_error (GPG_ERR_NO_SECKEY);
- else if (!s_skey)
- {
- log_error ("changing a smartcard PIN is not yet supported\n");
- rc = gpg_error (GPG_ERR_NOT_IMPLEMENTED);
- }
- else
- rc = agent_protect_and_store (ctrl, s_skey);
-
- gcry_sexp_release (s_skey);
- xfree (shadow_info);
- if (rc)
- log_error ("command passwd failed: %s\n", gpg_strerror (rc));
- return map_to_assuan_status (rc);
-}
-
-
-/* SCD <commands to pass to the scdaemon>
-
- This is a general quote command to redirect everything to the
- SCDAEMON. */
-static int
-cmd_scd (ASSUAN_CONTEXT ctx, char *line)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
- int rc;
-
- rc = divert_generic_cmd (ctrl, line, ctx);
-
- return map_to_assuan_status (rc);
-}
-
-
-
-static int
-option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
-{
- CTRL ctrl = assuan_get_pointer (ctx);
-
- if (!strcmp (key, "display"))
- {
- if (ctrl->display)
- free (ctrl->display);
- ctrl->display = strdup (value);
- if (!ctrl->display)
- return ASSUAN_Out_Of_Core;
- }
- else if (!strcmp (key, "ttyname"))
- {
- if (!opt.keep_tty)
- {
- if (ctrl->ttyname)
- free (ctrl->ttyname);
- ctrl->ttyname = strdup (value);
- if (!ctrl->ttyname)
- return ASSUAN_Out_Of_Core;
- }
- }
- else if (!strcmp (key, "ttytype"))
- {
- if (!opt.keep_tty)
- {
- if (ctrl->ttytype)
- free (ctrl->ttytype);
- ctrl->ttytype = strdup (value);
- if (!ctrl->ttytype)
- return ASSUAN_Out_Of_Core;
- }
- }
- else if (!strcmp (key, "lc-ctype"))
- {
- if (ctrl->lc_ctype)
- free (ctrl->lc_ctype);
- ctrl->lc_ctype = strdup (value);
- if (!ctrl->lc_ctype)
- return ASSUAN_Out_Of_Core;
- }
- else if (!strcmp (key, "lc-messages"))
- {
- if (ctrl->lc_messages)
- free (ctrl->lc_messages);
- ctrl->lc_messages = strdup (value);
- if (!ctrl->lc_messages)
- return ASSUAN_Out_Of_Core;
- }
- else if (!strcmp (key, "use-cache-for-signing"))
- ctrl->server_local->use_cache_for_signing = *value? atoi (value) : 0;
- else
- return ASSUAN_Invalid_Option;
-
- return 0;
-}
-
-
-/* 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[] = {
- { "ISTRUSTED", cmd_istrusted },
- { "HAVEKEY", cmd_havekey },
- { "SIGKEY", cmd_sigkey },
- { "SETKEY", cmd_sigkey },
- { "SETHASH", cmd_sethash },
- { "PKSIGN", cmd_pksign },
- { "PKDECRYPT", cmd_pkdecrypt },
- { "GENKEY", cmd_genkey },
- { "GET_PASSPHRASE", cmd_get_passphrase },
- { "CLEAR_PASSPHRASE", cmd_clear_passphrase },
- { "LISTTRUSTED", cmd_listtrusted },
- { "MARKTRUSTED", cmd_marktrusted },
- { "LEARN", cmd_learn },
- { "PASSWD", cmd_passwd },
- { "INPUT", NULL },
- { "OUTPUT", NULL },
- { "SCD", cmd_scd },
- { 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_register_reset_notify (ctx, reset_notify);
- assuan_register_option_handler (ctx, option_handler);
- return 0;
-}
-
-
-/* Startup the server. If LISTEN_FD and FD is given as -1, this is a simple
- piper server, otherwise it is a regular server */
-void
-start_command_handler (int listen_fd, int fd)
-{
- int rc;
- ASSUAN_CONTEXT ctx;
- struct server_control_s ctrl;
-
- memset (&ctrl, 0, sizeof ctrl);
- agent_init_default_ctrl (&ctrl);
-
- if (listen_fd == -1 && fd == -1)
- {
- int filedes[2];
-
- filedes[0] = 0;
- filedes[1] = 1;
- rc = assuan_init_pipe_server (&ctx, filedes);
- }
- else if (listen_fd != -1)
- {
- rc = assuan_init_socket_server (&ctx, listen_fd);
- }
- else
- {
- rc = assuan_init_connected_socket_server (&ctx, fd);
- }
- if (rc)
- {
- log_error ("failed to initialize the server: %s\n",
- assuan_strerror(rc));
- agent_exit (2);
- }
- rc = register_commands (ctx);
- if (rc)
- {
- log_error ("failed to register commands with Assuan: %s\n",
- assuan_strerror(rc));
- agent_exit (2);
- }
-
- assuan_set_pointer (ctx, &ctrl);
- ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
- ctrl.server_local->assuan_ctx = ctx;
- ctrl.server_local->message_fd = -1;
- ctrl.server_local->use_cache_for_signing = 1;
-
- if (DBG_ASSUAN)
- assuan_set_log_stream (ctx, log_get_stream ());
-
- 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;
- }
- }
-
-
- assuan_deinit_server (ctx);
- if (ctrl.display)
- free (ctrl.display);
- if (ctrl.ttyname)
- free (ctrl.ttyname);
- if (ctrl.ttytype)
- free (ctrl.ttytype);
- if (ctrl.lc_ctype)
- free (ctrl.lc_ctype);
- if (ctrl.lc_messages)
- free (ctrl.lc_messages);
-}
-
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
deleted file mode 100644
index 69f184474..000000000
--- a/agent/divert-scd.c
+++ /dev/null
@@ -1,319 +0,0 @@
-/* divert-scd.c - divert operations to the scdaemon
- * 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
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "agent.h"
-#include "sexp-parse.h"
-#include "i18n.h"
-
-
-static int
-ask_for_card (CTRL ctrl, const unsigned char *shadow_info, char **r_kid)
-{
- int rc, i;
- const unsigned char *s;
- size_t n;
- char *serialno;
- int no_card = 0;
- char *desc;
- char *want_sn, *want_kid;
- int want_sn_displen;
-
- *r_kid = NULL;
- s = shadow_info;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- want_sn = xtrymalloc (n*2+1);
- if (!want_sn)
- return out_of_core ();
- for (i=0; i < n; i++)
- sprintf (want_sn+2*i, "%02X", s[i]);
- s += n;
- /* We assume that a 20 byte serial number is a standard one which
- seems to have the property to have a zero in the last nibble. We
- don't display this '0' because it may confuse the user */
- want_sn_displen = strlen (want_sn);
- if (want_sn_displen == 20 && want_sn[19] == '0')
- want_sn_displen--;
-
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- want_kid = xtrymalloc (n+1);
- if (!want_kid)
- {
- gpg_error_t tmperr = out_of_core ();
- xfree (want_sn);
- return tmperr;
- }
- memcpy (want_kid, s, n);
- want_kid[n] = 0;
-
- for (;;)
- {
- rc = agent_card_serialno (&serialno);
- if (!rc)
- {
- log_debug ("detected card with S/N %s\n", serialno);
- i = strcmp (serialno, want_sn);
- xfree (serialno);
- serialno = NULL;
- if (!i)
- {
- xfree (want_sn);
- *r_kid = want_kid;
- return 0; /* yes, we have the correct card */
- }
- }
- else if (gpg_err_code (rc) == GPG_ERR_CARD_NOT_PRESENT)
- {
- log_debug ("no card present\n");
- rc = 0;
- no_card = 1;
- }
- else
- {
- log_error ("error accesing card: %s\n", gpg_strerror (rc));
- }
-
- if (!rc)
- {
- if (asprintf (&desc,
- "%s:%%0A%%0A"
- " \"%.*s\"",
- no_card? "Please insert the card with serial number"
- : "Please remove the current card and "
- "insert the one with serial number",
- want_sn_displen, want_sn) < 0)
- {
- rc = out_of_core ();
- }
- else
- {
- rc = agent_get_confirmation (ctrl, desc, NULL, NULL);
- free (desc);
- }
- }
- if (rc)
- {
- xfree (want_sn);
- xfree (want_kid);
- return rc;
- }
- }
-}
-
-
-/* Put the DIGEST into an DER encoded comtainer and return it in R_VAL. */
-static int
-encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
- unsigned char **r_val, size_t *r_len)
-{
- byte *frame;
- byte asn[100];
- size_t asnlen;
-
- asnlen = DIM(asn);
- if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
- {
- log_error ("no object identifier for algo %d\n", algo);
- return gpg_error (GPG_ERR_INTERNAL);
- }
-
- frame = xtrymalloc (asnlen + digestlen);
- if (!frame)
- return out_of_core ();
- memcpy (frame, asn, asnlen);
- memcpy (frame+asnlen, digest, digestlen);
- if (DBG_CRYPTO)
- log_printhex ("encoded hash:", frame, asnlen+digestlen);
-
- *r_val = frame;
- *r_len = asnlen+digestlen;
- return 0;
-}
-
-
-/* Callback used to ask for the PIN which should be set into BUF. The
- buf has been allocated by the caller and is of size MAXBUF which
- includes the terminating null. The function should return an UTF-8
- string with the passphrase, the buffer may optionally be padded
- with arbitrary characters */
-static int
-getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
-{
- struct pin_entry_info_s *pi;
- int rc;
- char *desc;
- CTRL ctrl = opaque;
-
- if (maxbuf < 2)
- return gpg_error (GPG_ERR_INV_VALUE);
-
-
- /* FIXME: keep PI and TRIES in OPAQUE. Frankly this is a whole
- mess because we should call the card's verify function from the
- pinentry check pin CB. */
- pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
- pi->max_length = maxbuf-1;
- pi->min_digits = 0; /* we want a real passphrase */
- pi->max_digits = 8;
- pi->max_tries = 3;
-
- if ( asprintf (&desc, _("Please enter the PIN%s%s%s to unlock the card"),
- info? " (`":"",
- info? info:"",
- info? "')":"") < 0)
- desc = NULL;
- rc = agent_askpin (ctrl, desc?desc:info, pi);
- free (desc);
- if (!rc)
- {
- strncpy (buf, pi->pin, maxbuf-1);
- buf[maxbuf-1] = 0;
- }
- xfree (pi);
- return rc;
-}
-
-
-
-
-int
-divert_pksign (CTRL ctrl,
- const unsigned char *digest, size_t digestlen, int algo,
- const unsigned char *shadow_info, unsigned char **r_sig)
-{
- int rc;
- char *kid;
- size_t siglen;
- char *sigval;
- unsigned char *data;
- size_t ndata;
-
- rc = ask_for_card (ctrl, shadow_info, &kid);
- if (rc)
- return rc;
-
- rc = encode_md_for_card (digest, digestlen, algo,
- &data, &ndata);
- if (rc)
- return rc;
-
- rc = agent_card_pksign (kid, getpin_cb, ctrl,
- data, ndata, &sigval, &siglen);
- if (!rc)
- *r_sig = sigval;
- xfree (data);
- xfree (kid);
-
- return rc;
-}
-
-
-/* Decrypt the the value given asn an S-expression in CIPHER using the
- key identified by SHADOW_INFO and return the plaintext in an
- allocated buffer in R_BUF. */
-int
-divert_pkdecrypt (CTRL ctrl,
- const unsigned char *cipher,
- const unsigned char *shadow_info,
- char **r_buf, size_t *r_len)
-{
- int rc;
- char *kid;
- const unsigned char *s;
- size_t n;
- const unsigned char *ciphertext;
- size_t ciphertextlen;
- char *plaintext;
- size_t plaintextlen;
-
- s = cipher;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "enc-val"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "rsa"))
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "a"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- ciphertext = s;
- ciphertextlen = n;
-
- rc = ask_for_card (ctrl, shadow_info, &kid);
- if (rc)
- return rc;
-
- rc = agent_card_pkdecrypt (kid, getpin_cb, ctrl,
- ciphertext, ciphertextlen,
- &plaintext, &plaintextlen);
- if (!rc)
- {
- *r_buf = plaintext;
- *r_len = plaintextlen;
- }
- xfree (kid);
- return rc;
-}
-
-
-int
-divert_generic_cmd (CTRL ctrl, const char *cmdline, void *assuan_context)
-{
- return agent_card_scd (cmdline, getpin_cb, ctrl, assuan_context);
-}
-
-
-
-
-
diff --git a/agent/findkey.c b/agent/findkey.c
deleted file mode 100644
index db36cb1b9..000000000
--- a/agent/findkey.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/* findkey.c - locate the secret key
- * 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
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <fcntl.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <assert.h>
-
-#include "agent.h"
-
-/* Helper to pass data to the check callback of the unprotect function. */
-struct try_unprotect_arg_s {
- const unsigned char *protected_key;
- unsigned char *unprotected_key;
-};
-
-
-
-int
-agent_write_private_key (const unsigned char *grip,
- const void *buffer, size_t length, int force)
-{
- int i;
- char *fname;
- FILE *fp;
- char hexgrip[40+4+1];
-
- for (i=0; i < 20; i++)
- sprintf (hexgrip+2*i, "%02X", grip[i]);
- strcpy (hexgrip+40, ".key");
-
- fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
- if (force)
- fp = fopen (fname, "wb");
- else
- {
- int fd;
-
- if (!access (fname, F_OK))
- {
- log_error ("secret key file `%s' already exists\n", fname);
- xfree (fname);
- return gpg_error (GPG_ERR_GENERAL);
- }
-
- /* We would like to create FNAME but only if it does not already
- exist. We cannot make this guarantee just using POSIX (GNU
- provides the "x" opentype for fopen, however, this is not
- portable). Thus, we use the more flexible open function and
- then use fdopen to obtain a stream.
-
- The mode parameter to open is what fopen uses. It will be
- combined with the process' umask automatically. */
- fd = open (fname, O_CREAT | O_EXCL | O_RDWR,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
- if (fd < 0)
- fp = 0;
- else
- {
- fp = fdopen (fd, "wb");
- if (!fp)
- {
- int save_e = errno;
- close (fd);
- errno = save_e;
- }
- }
- }
-
- if (!fp)
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("can't create `%s': %s\n", fname, strerror (errno));
- xfree (fname);
- return tmperr;
- }
-
- if (fwrite (buffer, length, 1, fp) != 1)
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("error writing `%s': %s\n", fname, strerror (errno));
- fclose (fp);
- remove (fname);
- xfree (fname);
- return tmperr;
- }
- if ( fclose (fp) )
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("error closing `%s': %s\n", fname, strerror (errno));
- remove (fname);
- xfree (fname);
- return tmperr;
- }
-
- xfree (fname);
- return 0;
-}
-
-
-/* Callback function to try the unprotection from the passpharse query
- code. */
-static int
-try_unprotect_cb (struct pin_entry_info_s *pi)
-{
- struct try_unprotect_arg_s *arg = pi->check_cb_arg;
- size_t dummy;
-
- assert (!arg->unprotected_key);
- return agent_unprotect (arg->protected_key, pi->pin,
- &arg->unprotected_key, &dummy);
-}
-
-
-/* Unprotect the canconical encoded S-expression key in KEYBUF. GRIP
- should be the hex encoded keygrip of that key to be used with the
- caching mechanism. */
-static int
-unprotect (CTRL ctrl,
- unsigned char **keybuf, const unsigned char *grip, int ignore_cache)
-{
- struct pin_entry_info_s *pi;
- struct try_unprotect_arg_s arg;
- int rc, i;
- unsigned char *result;
- size_t resultlen;
- char hexgrip[40+1];
-
- for (i=0; i < 20; i++)
- sprintf (hexgrip+2*i, "%02X", grip[i]);
- hexgrip[40] = 0;
-
- /* first try to get it from the cache - if there is none or we can't
- unprotect it, we fall back to ask the user */
- if (!ignore_cache)
- {
- void *cache_marker;
- const char *pw = agent_get_cache (hexgrip, &cache_marker);
- if (pw)
- {
- rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
- agent_unlock_cache_entry (&cache_marker);
- if (!rc)
- {
- xfree (*keybuf);
- *keybuf = result;
- return 0;
- }
- rc = 0;
- }
- }
-
- pi = gcry_calloc_secure (1, sizeof (*pi) + 100);
- pi->max_length = 100;
- pi->min_digits = 0; /* we want a real passphrase */
- pi->max_digits = 8;
- pi->max_tries = 3;
- pi->check_cb = try_unprotect_cb;
- arg.protected_key = *keybuf;
- arg.unprotected_key = NULL;
- pi->check_cb_arg = &arg;
-
- rc = agent_askpin (ctrl, NULL, pi);
- if (!rc)
- {
- assert (arg.unprotected_key);
- agent_put_cache (hexgrip, pi->pin, 0);
- xfree (*keybuf);
- *keybuf = arg.unprotected_key;
- }
- xfree (pi);
- return rc;
-}
-
-
-
-/* Return the secret key as an S-Exp after locating it using the grip.
- Returns NULL if key is not available or the operation should be
- diverted to a token. In the latter case shadow_info will point to
- an allocated S-Expression with the shadow_info part from the file.
- With IGNORE_CACHE passed as true the passphrase is not taken from
- the cache.*/
-gcry_sexp_t
-agent_key_from_file (CTRL ctrl,
- const unsigned char *grip, unsigned char **shadow_info,
- int ignore_cache)
-{
- int i, rc;
- char *fname;
- FILE *fp;
- struct stat st;
- unsigned char *buf;
- size_t len, buflen, erroff;
- gcry_sexp_t s_skey;
- char hexgrip[40+4+1];
-
- if (shadow_info)
- *shadow_info = NULL;
-
- for (i=0; i < 20; i++)
- sprintf (hexgrip+2*i, "%02X", grip[i]);
- strcpy (hexgrip+40, ".key");
-
- fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
- fp = fopen (fname, "rb");
- if (!fp)
- {
- log_error ("can't open `%s': %s\n", fname, strerror (errno));
- xfree (fname);
- return NULL;
- }
-
- if (fstat (fileno(fp), &st))
- {
- log_error ("can't stat `%s': %s\n", fname, strerror (errno));
- xfree (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, strerror (errno));
- xfree (fname);
- fclose (fp);
- xfree (buf);
- return NULL;
- }
-
- rc = gcry_sexp_sscan (&s_skey, &erroff, buf, buflen);
- xfree (fname);
- fclose (fp);
- xfree (buf);
- if (rc)
- {
- log_error ("failed to build S-Exp (off=%u): %s\n",
- (unsigned int)erroff, gpg_strerror (rc));
- return NULL;
- }
- len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, NULL, 0);
- assert (len);
- buf = xtrymalloc (len);
- if (!buf)
- {
- gcry_sexp_release (s_skey);
- return NULL;
- }
- len = gcry_sexp_sprint (s_skey, GCRYSEXP_FMT_CANON, buf, len);
- assert (len);
- gcry_sexp_release (s_skey);
-
- switch (agent_private_key_type (buf))
- {
- case PRIVATE_KEY_CLEAR:
- break; /* no unprotection needed */
- case PRIVATE_KEY_PROTECTED:
- rc = unprotect (ctrl, &buf, grip, ignore_cache);
- if (rc)
- log_error ("failed to unprotect the secret key: %s\n",
- gpg_strerror (rc));
- break;
- case PRIVATE_KEY_SHADOWED:
- if (shadow_info)
- {
- const unsigned char *s;
- size_t n;
-
- rc = agent_get_shadow_info (buf, &s);
- if (!rc)
- {
- n = gcry_sexp_canon_len (s, 0, NULL,NULL);
- assert (n);
- *shadow_info = xtrymalloc (n);
- if (!*shadow_info)
- rc = out_of_core ();
- else
- {
- memcpy (*shadow_info, s, n);
- rc = 0;
- }
- }
- if (rc)
- log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
- }
- rc = -1; /* ugly interface: we return an error but keep a value
- in shadow_info. */
- break;
- default:
- log_error ("invalid private key format\n");
- rc = gpg_error (GPG_ERR_BAD_SECKEY);
- break;
- }
- if (rc)
- {
- xfree (buf);
- return NULL;
- }
-
- /* arggg FIXME: does scan support secure memory? */
- rc = gcry_sexp_sscan (&s_skey, &erroff,
- buf, gcry_sexp_canon_len (buf, 0, NULL, NULL));
- xfree (buf);
- if (rc)
- {
- log_error ("failed to build S-Exp (off=%u): %s\n",
- (unsigned int)erroff, gpg_strerror (rc));
- return NULL;
- }
-
- return s_skey;
-}
-
-/* Return the secret key as an S-Exp after locating it using the grip.
- Returns NULL if key is not available. 0 = key is available */
-int
-agent_key_available (const unsigned char *grip)
-{
- int i;
- char *fname;
- char hexgrip[40+4+1];
-
- for (i=0; i < 20; i++)
- sprintf (hexgrip+2*i, "%02X", grip[i]);
- strcpy (hexgrip+40, ".key");
-
- fname = make_filename (opt.homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
- i = !access (fname, R_OK)? 0 : -1;
- xfree (fname);
- return i;
-}
-
-
-
diff --git a/agent/genkey.c b/agent/genkey.c
deleted file mode 100644
index 0a0577f17..000000000
--- a/agent/genkey.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/* pksign.c - Generate a keypair
- * 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
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-
-#include "agent.h"
-#include "i18n.h"
-
-static int
-store_key (gcry_sexp_t private, const char *passphrase, int force)
-{
- int rc;
- char *buf;
- size_t len;
- unsigned char grip[20];
-
- if ( !gcry_pk_get_keygrip (private, grip) )
- {
- log_error ("can't calculate keygrip\n");
- return gpg_error (GPG_ERR_GENERAL);
- }
-
- len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
- assert (len);
- buf = gcry_malloc_secure (len);
- if (!buf)
- return out_of_core ();
- len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, buf, len);
- assert (len);
-
- if (passphrase)
- {
- unsigned char *p;
-
- rc = agent_protect (buf, passphrase, &p, &len);
- if (rc)
- {
- xfree (buf);
- return rc;
- }
- xfree (buf);
- buf = p;
- }
-
- rc = agent_write_private_key (grip, buf, len, force);
- xfree (buf);
- return rc;
-}
-
-/* Callback function to compare the first entered PIN with the one
- currently being entered. */
-static int
-reenter_compare_cb (struct pin_entry_info_s *pi)
-{
- const char *pin1 = pi->check_cb_arg;
-
- if (!strcmp (pin1, pi->pin))
- return 0; /* okay */
- pi->cb_errtext = _("does not match - try again");
- return -1;
-}
-
-
-
-/* Generate a new keypair according to the parameters given in
- KEYPARAM */
-int
-agent_genkey (CTRL ctrl, const char *keyparam, size_t keyparamlen,
- FILE *outfp)
-{
- gcry_sexp_t s_keyparam, s_key, s_private, s_public;
- struct pin_entry_info_s *pi, *pi2;
- int rc;
- size_t len;
- char *buf;
-
- rc = gcry_sexp_sscan (&s_keyparam, NULL, keyparam, keyparamlen);
- if (rc)
- {
- log_error ("failed to convert keyparam: %s\n", gpg_strerror (rc));
- return gpg_error (GPG_ERR_INV_DATA);
- }
-
- /* Get the passphrase now, cause key generation may take a while. */
- {
- const char *text1 = _("Please enter the passphrase to%0A"
- "to protect your new key");
- const char *text2 = _("Please re-enter this passphrase");
-
- pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
- pi2 = pi + (sizeof *pi + 100);
- pi->max_length = 100;
- pi->max_tries = 3;
- pi2->max_length = 100;
- pi2->max_tries = 3;
- pi2->check_cb = reenter_compare_cb;
- pi2->check_cb_arg = pi->pin;
-
- rc = agent_askpin (ctrl, text1, pi);
- if (!rc)
- rc = agent_askpin (ctrl, text2, pi2);
- if (rc)
- return rc;
- if (!*pi->pin)
- {
- xfree (pi);
- pi = NULL; /* User does not want a passphrase. */
- }
- }
-
- rc = gcry_pk_genkey (&s_key, s_keyparam );
- gcry_sexp_release (s_keyparam);
- if (rc)
- {
- log_error ("key generation failed: %s\n", gpg_strerror (rc));
- xfree (pi);
- return map_gcry_err (rc);
- }
-
- /* break out the parts */
- s_private = gcry_sexp_find_token (s_key, "private-key", 0);
- if (!s_private)
- {
- log_error ("key generation failed: invalid return value\n");
- gcry_sexp_release (s_key);
- xfree (pi);
- return gpg_error (GPG_ERR_INV_DATA);
- }
- s_public = gcry_sexp_find_token (s_key, "public-key", 0);
- if (!s_public)
- {
- log_error ("key generation failed: invalid return value\n");
- gcry_sexp_release (s_private);
- gcry_sexp_release (s_key);
- xfree (pi);
- return gpg_error (GPG_ERR_INV_DATA);
- }
- gcry_sexp_release (s_key); s_key = NULL;
-
- /* store the secret key */
- log_debug ("storing private key\n");
- rc = store_key (s_private, pi? pi->pin:NULL, 0);
- xfree (pi); pi = NULL;
- gcry_sexp_release (s_private);
- if (rc)
- {
- gcry_sexp_release (s_public);
- return rc;
- }
-
- /* return the public key */
- log_debug ("returning public key\n");
- len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, NULL, 0);
- assert (len);
- buf = xtrymalloc (len);
- if (!buf)
- {
- gpg_error_t tmperr = out_of_core ();
- gcry_sexp_release (s_private);
- gcry_sexp_release (s_public);
- return tmperr;
- }
- len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
- assert (len);
- if (fwrite (buf, len, 1, outfp) != 1)
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("error writing public key: %s\n", strerror (errno));
- gcry_sexp_release (s_private);
- gcry_sexp_release (s_public);
- xfree (buf);
- return tmperr;
- }
- gcry_sexp_release (s_public);
- xfree (buf);
-
- return 0;
-}
-
-
-
-/* Apply a new passpahrse to the key S_SKEY and store it. */
-int
-agent_protect_and_store (CTRL ctrl, gcry_sexp_t s_skey)
-{
- struct pin_entry_info_s *pi, *pi2;
- int rc;
-
- {
- const char *text1 = _("Please enter the new passphrase");
- const char *text2 = _("Please re-enter this passphrase");
-
- pi = gcry_calloc_secure (2, sizeof (*pi) + 100);
- pi2 = pi + (sizeof *pi + 100);
- pi->max_length = 100;
- pi->max_tries = 3;
- pi2->max_length = 100;
- pi2->max_tries = 3;
- pi2->check_cb = reenter_compare_cb;
- pi2->check_cb_arg = pi->pin;
-
- rc = agent_askpin (ctrl, text1, pi);
- if (!rc)
- rc = agent_askpin (ctrl, text2, pi2);
- if (rc)
- return rc;
- if (!*pi->pin)
- {
- xfree (pi);
- pi = NULL; /* User does not want a passphrase. */
- }
- }
-
- rc = store_key (s_skey, pi? pi->pin:NULL, 1);
- xfree (pi);
- return 0;
-}
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
deleted file mode 100644
index 675f2be3f..000000000
--- a/agent/gpg-agent.c
+++ /dev/null
@@ -1,1063 +0,0 @@
-/* gpg-agent.c - The GnuPG Agent
- * Copyright (C) 2000, 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
- */
-
-#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 "agent.h"
-#include <assuan.h> /* malloc hooks */
-
-#include "i18n.h"
-#include "sysutils.h"
-
-
-enum cmd_and_opt_values
-{ aNull = 0,
- oCsh = 'c',
- oQuiet = 'q',
- oSh = 's',
- oVerbose = 'v',
-
- oNoVerbose = 500,
- oOptions,
- oDebug,
- oDebugAll,
- oDebugWait,
- oNoGreeting,
- oNoOptions,
- oHomedir,
- oNoDetach,
- oNoGrab,
- oLogFile,
- oServer,
- oDaemon,
- oBatch,
-
- oPinentryProgram,
- oDisplay,
- oTTYname,
- oTTYtype,
- oLCctype,
- oLCmessages,
- oScdaemonProgram,
- oDefCacheTTL,
- oDisablePth,
-
- oIgnoreCacheForSigning,
- oKeepTTY,
- oKeepDISPLAY,
-
-aTest };
-
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 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, N_("set debugging flags")},
- { oDebugAll, "debug-all" ,0, N_("enable full debugging")},
- { oDebugWait,"debug-wait",1, "@"},
- { oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
- { oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")},
- { oLogFile, "log-file" ,2, N_("use a log file for the server")},
- { oDisablePth, "disable-pth", 0, N_("do not allow multiple connections")},
-
- { oPinentryProgram, "pinentry-program", 2 , "path to PIN Entry program" },
- { oDisplay, "display", 2, "set the display" },
- { oTTYname, "ttyname", 2, "set the tty terminal node name" },
- { oTTYtype, "ttytype", 2, "set the tty terminal type" },
- { oLCctype, "lc-ctype", 2, "set the tty LC_CTYPE value" },
- { oLCmessages, "lc-messages", 2, "set the tty LC_MESSAGES value" },
-
- { oScdaemonProgram, "scdaemon-program", 2 , "path to SCdaemon program" },
- { oDefCacheTTL, "default-cache-ttl", 4,
- "|N|expire cached PINs after N seconds"},
- { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
- "do not use the PIN cache when signing"},
- { oKeepTTY, "keep-tty", 0, N_("ignore requests to change the TTY")},
- { oKeepDISPLAY, "keep-display",
- 0, N_("ignore requests to change the X display")},
- {0}
-};
-
-
-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];
-
-/* Default values for options passed to the pinentry. */
-static char *default_display;
-static char *default_ttyname;
-static char *default_ttytype;
-static char *default_lc_ctype;
-static char *default_lc_messages;
-
-/* Name of a config file, which will be reread on a HUP if it is not NULL. */
-static char *config_filename;
-
-
-/* Local prototypes. */
-static void create_directories (void);
-#ifdef USE_GNU_PTH
-static void handle_connections (int listen_fd);
-#endif
-
-
-
-static const char *
-my_strusage (int level)
-{
- const char *p;
- switch (level)
- {
- case 11: p = "gpg-agent (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: gpg-agent [options] (-h for help)");
- break;
- case 41: p = _("Syntax: gpg-agent [options] [command [args]]\n"
- "Secret key management for GnuPG\n");
- break;
-
- default: p = NULL;
- }
- return p;
-}
-
-
-
-static void
-i18n_init (void)
-{
-#ifdef USE_SIMPLE_GETTEXT
- set_gettext_file( PACKAGE );
-#else
-#ifdef ENABLE_NLS
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
-#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);
-}
-
-
-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 );
-}
-
-
-/* Handle options which are allowed to be reset after program start.
- Return true when the current option in PARGS could be handled and
- false if not. As a special feature, passing a value of NULL for
- PARGS, resets the options to the default. */
-static int
-parse_rereadable_options (ARGPARSE_ARGS *pargs)
-{
- if (!pargs)
- { /* reset mode */
- opt.quiet = 0;
- opt.verbose = 0;
- opt.debug = 0;
- opt.no_grab = 0;
- opt.pinentry_program = NULL;
- opt.scdaemon_program = NULL;
- opt.def_cache_ttl = 10*60; /* default to 10 minutes */
- opt.ignore_cache_for_signing = 0;
- return 1;
- }
-
- switch (pargs->r_opt)
- {
- case oQuiet: opt.quiet = 1; break;
- case oVerbose: opt.verbose++; break;
-
- case oDebug: opt.debug |= pargs->r.ret_ulong; break;
- case oDebugAll: opt.debug = ~0; break;
-
- case oNoGrab: opt.no_grab = 1; break;
-
- case oPinentryProgram: opt.pinentry_program = pargs->r.ret_str; break;
- case oScdaemonProgram: opt.scdaemon_program = pargs->r.ret_str; break;
-
- case oDefCacheTTL: opt.def_cache_ttl = pargs->r.ret_ulong; break;
-
- case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
-
- default:
- return 0; /* not handled */
- }
- return 1; /* handled */
-}
-
-
-int
-main (int argc, char **argv )
-{
- ARGPARSE_ARGS pargs;
- int orig_argc;
- int may_coredump;
- char **orig_argv;
- FILE *configfp = NULL;
- char *configname = NULL;
- const char *shell;
- unsigned configlineno;
- int parse_debug = 0;
- 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 disable_pth = 0;
-
- 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 ("gpg-agent", 1|4);
- i18n_init ();
-
- /* We need to initialize Pth before libgcrypt, because the libgcrypt
- initialization done by gcry_check_version internally sets up its
- mutex system. Note that one must not link against pth if
- USE_GNU_PTH is not defined. */
-#ifdef USE_GNU_PTH
- if (!pth_init ())
- {
- log_error ("failed to initialize the Pth library\n");
- exit (1);
- }
-#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) );
- }
-
- assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
-
- gcry_set_log_handler (my_gcry_logger, NULL);
- gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
-
- may_coredump = disable_core_dumps ();
-
- parse_rereadable_options (NULL); /* Reset them to default values. */
-
- shell = getenv ("SHELL");
- if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
- csh_style = 1;
-
- 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 now working under our real uid
- */
-
-
- if (default_config)
- configname = make_filename (opt.homedir, "gpg-agent.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) )
- {
- if (parse_rereadable_options (&pargs))
- continue; /* Already handled */
- switch (pargs.r_opt)
- {
- case oBatch: opt.batch=1; break;
-
- case oDebugWait: debug_wait = 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 oDisablePth: disable_pth = 1; break;
-
- case oDisplay: default_display = xstrdup (pargs.r.ret_str); break;
- case oTTYname: default_ttyname = xstrdup (pargs.r.ret_str); break;
- case oTTYtype: default_ttytype = xstrdup (pargs.r.ret_str); break;
- case oLCctype: default_lc_ctype = xstrdup (pargs.r.ret_str); break;
- case oLCmessages: default_lc_messages = xstrdup (pargs.r.ret_str); break;
-
- case oKeepTTY: opt.keep_tty = 1; break;
- case oKeepDISPLAY: opt.keep_display = 1; break;
-
- default : pargs.err = configfp? 1:2; break;
- }
- }
- if (configfp)
- {
- fclose( configfp );
- configfp = NULL;
- /* Keep a copy of the name so that it can be read on SIGHUP. */
- 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);
- }
-
- create_directories ();
-
- 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 (!pipe_server && !is_daemon)
- log_info (_("please use the option `--daemon'"
- " to run the program in the background\n"));
-
-#ifdef ENABLE_NLS
- /* gpg-agent usdually does not ooutput any messages becuase it runs
- in the background. For log files it is acceptable to have
- messages always encoded in utf-8. We switch here to utf-8, so
- that commands like --help still give native messages. It is far
- easier to swicthnonly once instead of for every message and it
- actually helps when more then one thread is active (avoids
- required an extra copy step). */
- bind_textdomain_codeset (PACKAGE, "UTF-8");
-#endif
-
- /* now start with logging to a file if this is desired */
- if (logfile)
- {
- log_set_file (logfile);
- log_set_prefix (NULL, 1|2|4);
- }
-
- /* Make sure that we have a default ttyname. */
- if (!default_ttyname && ttyname (1))
- default_ttyname = xstrdup (ttyname (1));
- if (!default_ttytype && getenv ("TERM"))
- default_ttytype = xstrdup (getenv ("TERM"));
-
- if (pipe_server)
- { /* this is the simple pipe based server */
- start_command_handler (-1, -1);
- }
- else if (!is_daemon)
- ;
- else
- { /* regular server mode */
- int fd;
- pid_t pid;
- int len;
- struct sockaddr_un serv_addr;
- char *p;
-
- /* Remove the DISPLAY variable so that a pinentry does not
- default to a specific display. There is still a default
- display when gpg-agent weas started using --display or a
- client requested this using an OPTION command. */
- if (!opt.keep_display)
- unsetenv ("DISPLAY");
-
- *socket_name = 0;
- snprintf (socket_name, DIM(socket_name)-1,
- "/tmp/gpg-XXXXXX/S.gpg-agent");
- 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 too 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, "GPG_AGENT_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 GPG_AGENT_INFO;\n", infostr);
- }
- free (infostr);
- exit (0);
- }
- /*NEVER REACHED*/
- } /* end parent */
-
-
- /* this is the child */
-
- /* detach from tty and put process into a new session */
- if (!nodetach )
- {
- int i;
-
- /* 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);
- }
- opt.running_detached = 1;
- }
-
- if (chdir("/"))
- {
- log_error ("chdir to / failed: %s\n", strerror (errno));
- exit (1);
- }
-
-
-#ifdef USE_GNU_PTH
- if (!disable_pth)
- {
- struct sigaction sa;
-
- sa.sa_handler = SIG_IGN;
- sigemptyset (&sa.sa_mask);
- sa.sa_flags = 0;
- sigaction (SIGPIPE, &sa, NULL);
- handle_connections (fd);
- }
- else
-#endif /*!USE_GNU_PTH*/
- /* 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);
-
- start_command_handler (fd, -1);
- }
- close (fd);
- }
-
- return 0;
-}
-
-void
-agent_exit (int rc)
-{
- /*FIXME: update_random_seed_file();*/
-#if 1
- /* 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
-agent_init_default_ctrl (struct server_control_s *ctrl)
-{
- /* Note we ignore malloc errors because we can't do much about it
- and the request will fail anyway shortly after this
- initialization. */
- if (ctrl->display)
- free (ctrl->display);
- ctrl->display = default_display? strdup (default_display) : NULL;
-
- if (ctrl->ttyname)
- free (ctrl->ttyname);
- ctrl->ttyname = default_ttyname? strdup (default_ttyname) : NULL;
-
- if (ctrl->ttytype)
- free (ctrl->ttytype);
- ctrl->ttytype = default_ttytype? strdup (default_ttytype) : NULL;
-
- if (ctrl->lc_ctype)
- free (ctrl->lc_ctype);
- ctrl->lc_ctype = default_lc_ctype? strdup (default_lc_ctype) : NULL;
-
- if (ctrl->lc_messages)
- free (ctrl->lc_messages);
- ctrl->lc_messages = default_lc_messages? strdup (default_lc_messages) : NULL;
-}
-
-
-/* Reread parts of the configuration. Note, that this function is
- obviously not thread-safe and should only be called from the PTH
- signal handler.
-
- Fixme: Due to the way the argument parsing works, we create a
- memory leak here for all string type arguments. There is currently
- no clean way to tell whether the memory for the argument has been
- allocated or points into the process' original arguments. Unless
- we have a mechanism to tell this, we need to live on with this. */
-static void
-reread_configuration (void)
-{
- ARGPARSE_ARGS pargs;
- FILE *fp;
- unsigned int configlineno = 0;
- int dummy;
-
- if (!config_filename)
- return; /* No config file. */
-
- fp = fopen (config_filename, "r");
- if (!fp)
- {
- log_error (_("option file `%s': %s\n"),
- config_filename, strerror(errno) );
- return;
- }
-
- parse_rereadable_options (NULL); /* Start from the default values. */
-
- memset (&pargs, 0, sizeof pargs);
- dummy = 0;
- pargs.argc = &dummy;
- pargs.flags = 1; /* do not remove the args */
- while (optfile_parse (fp, config_filename, &configlineno, &pargs, opts) )
- {
- if (pargs.r_opt < -1)
- pargs.err = 1; /* Print a warning. */
- else /* Try to parse this option - ignore unchangeable ones. */
- parse_rereadable_options (&pargs);
- }
- fclose (fp);
-}
-
-
-static void
-create_private_keys_directory (const char *home)
-{
- char *fname;
- struct stat statbuf;
-
- fname = make_filename (home, GNUPG_PRIVATE_KEYS_DIR, NULL);
- if (stat (fname, &statbuf) && errno == ENOENT)
- {
- if (mkdir (fname, S_IRUSR|S_IWUSR|S_IXUSR ))
- log_error (_("can't create directory `%s': %s\n"),
- fname, strerror(errno) );
- else if (!opt.quiet)
- log_info (_("directory `%s' created\n"), fname);
- }
- xfree (fname);
-}
-
-/* Create the directory only if the supplied directory name is the
- same as the default one. This way we avoid to create arbitrary
- directories when a non-default home directory is used. To cope
- with HOME, we compare only the suffix if we see that the default
- homedir does start with a tilde. We don't stop here in case of
- problems because other functions will throw an error anyway.*/
-static void
-create_directories (void)
-{
- struct stat statbuf;
- const char *defhome = GNUPG_DEFAULT_HOMEDIR;
- char *home;
-
- home = make_filename (opt.homedir, NULL);
- if ( stat (home, &statbuf) )
- {
- if (errno == ENOENT)
- {
- if ( (*defhome == '~'
- && (strlen (home) >= strlen (defhome+1)
- && !strcmp (home + strlen(home)
- - strlen (defhome+1), defhome+1)))
- || (*defhome != '~' && !strcmp (home, defhome) )
- )
- {
- if (mkdir (home, S_IRUSR|S_IWUSR|S_IXUSR ))
- log_error (_("can't create directory `%s': %s\n"),
- home, strerror(errno) );
- else
- {
- if (!opt.quiet)
- log_info (_("directory `%s' created\n"), home);
- create_private_keys_directory (home);
- }
- }
- }
- else
- log_error ("error stat-ing `%s': %s\n", home, strerror (errno));
- }
- else if ( !S_ISDIR(statbuf.st_mode))
- {
- log_error ("can't use `%s' as home directory\n", home);
- }
- else /* exists and is a directory. */
- {
- create_private_keys_directory (home);
- }
- xfree (home);
-}
-
-
-
-#ifdef USE_GNU_PTH
-static void
-handle_signal (int signo)
-{
- switch (signo)
- {
- case SIGHUP:
- log_info ("SIGHUP received - "
- "re-reading configuration and flushing cache\n");
- agent_flush_cache ();
- reread_configuration ();
- break;
-
- case SIGUSR1:
- if (opt.verbose < 5)
- opt.verbose++;
- log_info ("SIGUSR1 received - verbosity set to %d\n", opt.verbose);
- break;
-
- case SIGUSR2:
- if (opt.verbose)
- opt.verbose--;
- log_info ("SIGUSR2 received - verbosity set to %d\n", opt.verbose );
- 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 ();
- agent_exit (0);
- }
- break;
-
- case SIGINT:
- log_info ("SIGINT received - immediate shutdown\n");
- log_info( "%s %s stopped\n", strusage(11), strusage(13));
- cleanup ();
- agent_exit (0);
- break;
-
- default:
- log_info ("signal %d received - no action defined\n", signo);
- }
-}
-
-
-static void *
-start_connection_thread (void *arg)
-{
- int fd = (int)arg;
-
- if (opt.verbose)
- log_info ("handler for fd %d started\n", fd);
- start_command_handler (-1, fd);
- if (opt.verbose)
- log_info ("handler for fd %d terminated\n", fd);
-
- return NULL;
-}
-
-
-static void
-handle_connections (int listen_fd)
-{
- pth_attr_t tattr;
- pth_event_t ev;
- sigset_t sigs;
- int signo;
- struct sockaddr_un paddr;
- socklen_t plen = sizeof( paddr );
- int fd;
-
- tattr = pth_attr_new();
- pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0);
- pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024);
- pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent");
-
- sigemptyset (&sigs );
- sigaddset (&sigs, SIGHUP);
- sigaddset (&sigs, SIGUSR1);
- sigaddset (&sigs, SIGUSR2);
- sigaddset (&sigs, SIGINT);
- sigaddset (&sigs, SIGTERM);
- ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo);
-
- for (;;)
- {
- if (shutdown_pending)
- {
- if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1)
- break; /* ready */
-
- /* Do not accept anymore connections and wait for existing
- connections to terminate */
- signo = 0;
- pth_wait (ev);
- if (pth_event_occurred (ev) && signo)
- handle_signal (signo);
- continue;
- }
-
- fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev);
- if (fd == -1)
- {
-#ifdef PTH_STATUS_OCCURRED /* This is Pth 2 */
- if (pth_event_status (ev) == PTH_STATUS_OCCURRED)
-#else
- if (pth_event_occurred (ev))
-#endif
- {
- handle_signal (signo);
- continue;
- }
- log_error ("accept failed: %s - waiting 1s\n", strerror (errno));
- pth_sleep(1);
- continue;
- }
-
- if (!pth_spawn (tattr, start_connection_thread, (void*)fd))
- {
- log_error ("error spawning connection handler: %s\n",
- strerror (errno) );
- close (fd);
- }
- }
-
- pth_event_free (ev, PTH_FREE_ALL);
- cleanup ();
- log_info ("%s %s stopped\n", strusage(11), strusage(13));
-}
-#endif /*USE_GNU_PTH*/
diff --git a/agent/keyformat.txt b/agent/keyformat.txt
deleted file mode 100644
index 6c0bd8b83..000000000
--- a/agent/keyformat.txt
+++ /dev/null
@@ -1,163 +0,0 @@
-keyformat.txt (wk 2001-12-18)
------------------------------
-
-
-Some notes on the format of the secret keys used with gpg-agent.
-
-Location of keys
-================
-The secret keys[1] are stored on a per file basis in a directory below
-the ~/.gnupg home directory. This directory is named
-
- private-keys-v1.d
-
-and should have permissions 700.
-
-The secret keys are stored in files with a name matching the
-hexadecimal representation of the keygrip[2].
-
-Unprotected Private Key Format
-==============================
-The content of the file is an S-Expression like the ones used with
-Libgcrypt. Here is an example of an unprotected file:
-
-(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)
-)
-
-Actually this form should not be used for regular purposes and only
-accepted by gpg-agent with the configuration option:
---allow-non-canonical-key-format. The regular way to represent the
-keys is in canonical representation[3]:
-
-(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)
-)
-
-
-Protected Private Key Format
-==============================
-A protected key is like this:
-
-(protected-private-key
- (rsa
- (n #00e0ce9..[some bytes not shown]..51#)
- (e #010001#)
- (protected mode (parms) encrypted_octet_string)
- )
- (uri http://foo.bar x-foo:whatever_you_want)
-)
-
-
-In this scheme the encrypted_octet_string is encrypted according to
-the algorithm described after the keyword protected; most protection
-algorithms need some parameters, which are given in a list before the
-encrypted_octet_string. The result of the decryption process is a
-list of the secret key parameters.
-
-The only available protection mode for now is
-
- openpgp-s2k3-sha1-aes-cbc
-
-which describes an algorithm using using AES in CBC mode for
-encryption, SHA-1 for integrity protection and the String to Key
-algorithm 3 from OpenPGP (rfc2440).
-
-Example:
-
-(protected openpgp-s2k3-sha1-aes-cbc
- ((sha1 16byte_salt no_of_iterations) 16byte_iv)
- encrypted_octet_string
-)
-
-The encrypted_octet string should yield this S-Exp (in canonical
-representation) after decryption:
-
-(
- (
- (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#)
- )
- (hash sha1 #...[hashvalue]...#)
-)
-
-For padding reasons, random bytes are appended to this list - they can
-easily be stripped by looking for the end of the list.
-
-The hash is calculated on the concatenation of the public key and
-secret key parameter lists: i.e it is required to hash the
-concatenation of these 6 canonical encoded lists for RSA, including
-the parenthesis and the algorithm keyword.
-
-(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#)
-)
-
-After decryption the hash must be recalculated and compared against
-the stored one - If they don't match the integrity of the key is not
-given.
-
-
-Shadowed Private Key Format
-============================
-To keep track of keys stored on IC cards we use a third format for
-private kyes which are called shadow keys as they are only a reference
-to keys stored on a token:
-
-(shadowed-private-key
- (rsa
- (n #00e0ce9..[some bytes not shown]..51#)
- (e #010001#)
- (shadowed protocol (info))
- )
- (uri http://foo.bar x-foo:whatever_you_want)
-)
-
-The currently used protocol is "ti-v1" (token info version 1). The
-second list with the information has this layout:
-
-(card_serial_number id_string_of_key)
-
-More items may be added to the list.
-
-
-
-
-
-
-Notes:
-======
-[1] I usually use the terms private and secret key exchangeable but prefer the
-term secret key because it can be visually be better distinguished
-from the term public key.
-
-[2] The keygrip is a unique identifier for a key pair, it is
-independent of any protocol, so that the same key can be ised with
-different protocols. PKCS-15 calls this a subjectKeyHash; it can be
-calculate using Libgcrypt's gcry_pk_get_keygrip().
-
-[3] Even when canonical representation are required we will show the
-S-expression here in a more readable representation.
diff --git a/agent/learncard.c b/agent/learncard.c
deleted file mode 100644
index 28a74f972..000000000
--- a/agent/learncard.c
+++ /dev/null
@@ -1,448 +0,0 @@
-/* learncard.c - Handle the LEARN command
- * 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
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "agent.h"
-#include <assuan.h>
-
-struct keypair_info_s {
- struct keypair_info_s *next;
- int no_cert;
- char *id; /* points into grip */
- char hexgrip[1];
-};
-typedef struct keypair_info_s *KEYPAIR_INFO;
-
-struct kpinfo_cb_parm_s {
- int error;
- KEYPAIR_INFO info;
-};
-
-
-struct certinfo_s {
- struct certinfo_s *next;
- int type;
- int done;
- char id[1];
-};
-typedef struct certinfo_s *CERTINFO;
-
-struct certinfo_cb_parm_s {
- int error;
- CERTINFO info;
-};
-
-
-struct sinfo_s {
- struct sinfo_s *next;
- char *data; /* Points into keyword. */
- char keyword[1];
-};
-typedef struct sinfo_s *SINFO;
-
-struct sinfo_cb_parm_s {
- int error;;
- SINFO info;
-};
-
-
-
-static void
-release_keypair_info (KEYPAIR_INFO info)
-{
- while (info)
- {
- KEYPAIR_INFO tmp = info->next;
- xfree (info);
- info = tmp;
- }
-}
-
-static void
-release_certinfo (CERTINFO info)
-{
- while (info)
- {
- CERTINFO tmp = info->next;
- xfree (info);
- info = tmp;
- }
-}
-
-static void
-release_sinfo (SINFO info)
-{
- while (info)
- {
- SINFO tmp = info->next;
- xfree (info);
- info = tmp;
- }
-}
-
-
-
-/* This callback is used by agent_card_learn and passed the content of
- all KEYPAIRINFO lines. It merely stores this data away */
-static void
-kpinfo_cb (void *opaque, const char *line)
-{
- struct kpinfo_cb_parm_s *parm = opaque;
- KEYPAIR_INFO item;
- char *p;
-
- if (parm->error)
- return; /* no need to gather data after an error coccured */
- item = xtrycalloc (1, sizeof *item + strlen (line));
- if (!item)
- {
- parm->error = out_of_core ();
- return;
- }
- strcpy (item->hexgrip, line);
- for (p = item->hexgrip; hexdigitp (p); p++)
- ;
- if (p == item->hexgrip && *p == 'X' && spacep (p+1))
- {
- item->no_cert = 1;
- p++;
- }
- else if ((p - item->hexgrip) != 40 || !spacep (p))
- { /* not a 20 byte hex keygrip or not followed by a space */
- parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
- xfree (item);
- return;
- }
- *p++ = 0;
- while (spacep (p))
- p++;
- item->id = p;
- while (*p && !spacep (p))
- p++;
- if (p == item->id)
- { /* invalid ID string */
- parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
- xfree (item);
- return;
- }
- *p = 0; /* ignore trailing stuff */
-
- /* store it */
- item->next = parm->info;
- parm->info = item;
-}
-
-
-/* This callback is used by agent_card_learn and passed the content of
- all CERTINFO lines. It merely stores this data away */
-static void
-certinfo_cb (void *opaque, const char *line)
-{
- struct certinfo_cb_parm_s *parm = opaque;
- CERTINFO item;
- int type;
- char *p, *pend;
-
- if (parm->error)
- return; /* no need to gather data after an error coccured */
-
- type = strtol (line, &p, 10);
- while (spacep (p))
- p++;
- for (pend = p; *pend && !spacep (pend); pend++)
- ;
- if (p == pend || !*p)
- {
- parm->error = gpg_error (GPG_ERR_INV_RESPONSE);
- return;
- }
- *pend = 0; /* ignore trailing stuff */
-
- item = xtrycalloc (1, sizeof *item + strlen (p));
- if (!item)
- {
- parm->error = out_of_core ();
- return;
- }
- item->type = type;
- strcpy (item->id, p);
- /* store it */
- item->next = parm->info;
- parm->info = item;
-}
-
-
-/* This callback is used by agent_card_learn and passed the content of
- all SINFO lines. It merely stores this data away */
-static void
-sinfo_cb (void *opaque, const char *keyword, size_t keywordlen,
- const char *data)
-{
- struct sinfo_cb_parm_s *sparm = opaque;
- SINFO item;
-
- if (sparm->error)
- return; /* no need to gather data after an error coccured */
-
- item = xtrycalloc (1, sizeof *item + keywordlen + 1 + strlen (data));
- if (!item)
- {
- sparm->error = out_of_core ();
- return;
- }
- memcpy (item->keyword, keyword, keywordlen);
- item->data = item->keyword + keywordlen;
- *item->data = 0;
- item->data++;
- strcpy (item->data, data);
- /* store it */
- item->next = sparm->info;
- sparm->info = item;
-}
-
-
-/* Create an S-expression with the shadow info. */
-static unsigned char *
-make_shadow_info (const char *serialno, const char *idstring)
-{
- const char *s;
- unsigned char *info, *p;
- char numbuf[21];
- int n;
-
- for (s=serialno, n=0; *s && s[1]; s += 2)
- n++;
-
- info = p = xtrymalloc (1 + 21 + n
- + 21 + strlen (idstring) + 1 + 1);
- *p++ = '(';
- sprintf (numbuf, "%d:", n);
- p = stpcpy (p, numbuf);
- for (s=serialno; *s && s[1]; s += 2)
- *p++ = xtoi_2 (s);
- sprintf (numbuf, "%d:", strlen (idstring));
- p = stpcpy (p, numbuf);
- p = stpcpy (p, idstring);
- *p++ = ')';
- *p = 0;
- return info;
-}
-
-static int
-send_cert_back (const char *id, void *assuan_context)
-{
- int rc;
- char *derbuf;
- size_t derbuflen;
-
- rc = agent_card_readcert (id, &derbuf, &derbuflen);
- if (rc)
- {
- log_error ("error reading certificate: %s\n",
- gpg_strerror (rc));
- return rc;
- }
-
- rc = assuan_send_data (assuan_context, derbuf, derbuflen);
- xfree (derbuf);
- if (!rc)
- rc = assuan_send_data (assuan_context, NULL, 0);
- if (!rc)
- rc = assuan_write_line (assuan_context, "END");
- if (rc)
- {
- log_error ("sending certificate failed: %s\n",
- assuan_strerror (rc));
- return map_assuan_err (rc);
- }
- return 0;
-}
-
-/* Perform the learn operation. If ASSUAN_CONTEXT is not NULL all new
- certificates are send via Assuan */
-int
-agent_handle_learn (void *assuan_context)
-{
- int rc;
- struct kpinfo_cb_parm_s parm;
- struct certinfo_cb_parm_s cparm;
- struct sinfo_cb_parm_s sparm;
- char *serialno = NULL;
- KEYPAIR_INFO item;
- SINFO sitem;
- unsigned char grip[20];
- char *p;
- int i;
- static int certtype_list[] = {
- 101, /* trusted */
- 102, /* useful */
- 100, /* regular */
- -1 /* end of list */
- };
-
-
- memset (&parm, 0, sizeof parm);
- memset (&cparm, 0, sizeof cparm);
- memset (&sparm, 0, sizeof sparm);
-
- /* Check whether a card is present and get the serial number */
- rc = agent_card_serialno (&serialno);
- if (rc)
- goto leave;
-
- /* now gather all the available info */
- rc = agent_card_learn (kpinfo_cb, &parm, certinfo_cb, &cparm,
- sinfo_cb, &sparm);
- if (!rc && (parm.error || cparm.error || sparm.error))
- rc = parm.error? parm.error : cparm.error? cparm.error : sparm.error;
- if (rc)
- {
- log_debug ("agent_card_learn failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- log_info ("card has S/N: %s\n", serialno);
-
- /* Pass on all the collected status information. */
- if (assuan_context)
- {
- for (sitem = sparm.info; sitem; sitem = sitem->next)
- {
- assuan_write_status (assuan_context, sitem->keyword, sitem->data);
- }
- }
-
- /* Write out the certificates in a standard order. */
- for (i=0; certtype_list[i] != -1; i++)
- {
- CERTINFO citem;
- for (citem = cparm.info; citem; citem = citem->next)
- {
- if (certtype_list[i] != citem->type)
- continue;
-
- if (opt.verbose)
- log_info (" id: %s (type=%d)\n",
- citem->id, citem->type);
-
- if (assuan_context)
- {
- rc = send_cert_back (citem->id, assuan_context);
- if (rc)
- goto leave;
- citem->done = 1;
- }
- }
- }
-
- for (item = parm.info; item; item = item->next)
- {
- unsigned char *pubkey, *shdkey;
- size_t n;
-
- if (opt.verbose)
- log_info (" id: %s (grip=%s)\n", item->id, item->hexgrip);
-
- if (item->no_cert)
- continue; /* no public key yet available */
-
- for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
- grip[i] = xtoi_2 (p);
-
- if (!agent_key_available (grip))
- continue;
-
- /* unknown - store it */
- rc = agent_card_readkey (item->id, &pubkey);
- if (rc)
- {
- log_debug ("agent_card_readkey failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- {
- unsigned char *shadow_info = make_shadow_info (serialno, item->id);
- if (!shadow_info)
- {
- rc = gpg_error (GPG_ERR_ENOMEM);
- xfree (pubkey);
- goto leave;
- }
- rc = agent_shadow_key (pubkey, shadow_info, &shdkey);
- xfree (shadow_info);
- }
- xfree (pubkey);
- if (rc)
- {
- log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
- n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
- assert (n);
-
- rc = agent_write_private_key (grip, shdkey, n, 0);
- xfree (shdkey);
- if (rc)
- {
- log_error ("error writing key: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
- if (opt.verbose)
- log_info ("stored\n");
-
- if (assuan_context)
- {
- CERTINFO citem;
-
- /* only send the certificate if we have not done so before */
- for (citem = cparm.info; citem; citem = citem->next)
- {
- if (!strcmp (citem->id, item->id))
- break;
- }
- if (!citem)
- {
- rc = send_cert_back (item->id, assuan_context);
- if (rc)
- goto leave;
- }
- }
- }
-
-
- leave:
- xfree (serialno);
- release_keypair_info (parm.info);
- release_certinfo (cparm.info);
- release_sinfo (sparm.info);
- return rc;
-}
-
-
diff --git a/agent/minip12.c b/agent/minip12.c
deleted file mode 100644
index 255fef096..000000000
--- a/agent/minip12.c
+++ /dev/null
@@ -1,1140 +0,0 @@
-/* minip12.c - A minimal pkcs-12 implementation.
- * 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
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <gcrypt.h>
-
-#undef TEST
-
-#ifdef TEST
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#endif
-
-#include "../jnlib/logging.h"
-#include "minip12.h"
-
-#ifndef DIM
-#define DIM(v) (sizeof(v)/sizeof((v)[0]))
-#endif
-
-enum
-{
- UNIVERSAL = 0,
- APPLICATION = 1,
- CONTEXT = 2,
- PRIVATE = 3
-};
-
-
-enum
-{
- 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
-};
-
-
-static unsigned char const oid_data[9] = {
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01 };
-static unsigned char const oid_encryptedData[9] = {
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x07, 0x06 };
-static unsigned char const oid_pkcs_12_pkcs_8ShroudedKeyBag[11] = {
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x0A, 0x01, 0x02 };
-static unsigned char const oid_pbeWithSHAAnd3_KeyTripleDES_CBC[10] = {
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03 };
-
-static unsigned char const oid_rsaEncryption[9] = {
- 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01 };
-
-
-static unsigned char const data_3desiter1024[30] = {
- 0x30, 0x1C, 0x06, 0x0A, 0x2A, 0x86, 0x48, 0x86,
- 0xF7, 0x0D, 0x01, 0x0C, 0x01, 0x03, 0x30, 0x0E,
- 0x04, 0x08, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0x02, 0x02, 0x04, 0x00 };
-#define DATA_3DESITER1024_SALT_OFF 18
-
-
-struct buffer_s
-{
- unsigned char *buffer;
- size_t length;
-};
-
-
-struct tag_info
-{
- int class;
- int is_constructed;
- unsigned long tag;
- unsigned long length; /* length part of the TLV */
- int nhdr;
- int ndef; /* It is an indefinite length */
-};
-
-
-/* Parse the buffer at the address BUFFER which is of SIZE and return
- the tag and the length part from the TLV triplet. Update BUFFER
- and SIZE on success. */
-static int
-parse_tag (unsigned char const **buffer, size_t *size, struct tag_info *ti)
-{
- int c;
- unsigned long tag;
- const unsigned char *buf = *buffer;
- size_t length = *size;
-
- ti->length = 0;
- ti->ndef = 0;
- ti->nhdr = 0;
-
- /* Get the tag */
- if (!length)
- return -1; /* premature eof */
- c = *buf++; length--;
- ti->nhdr++;
-
- ti->class = (c & 0xc0) >> 6;
- ti->is_constructed = !!(c & 0x20);
- tag = c & 0x1f;
-
- if (tag == 0x1f)
- {
- tag = 0;
- do
- {
- tag <<= 7;
- if (!length)
- return -1; /* premature eof */
- c = *buf++; length--;
- ti->nhdr++;
- tag |= c & 0x7f;
- }
- while (c & 0x80);
- }
- ti->tag = tag;
-
- /* Get the length */
- if (!length)
- return -1; /* prematureeof */
- c = *buf++; length--;
- ti->nhdr++;
-
- if ( !(c & 0x80) )
- ti->length = c;
- else if (c == 0x80)
- ti->ndef = 1;
- else if (c == 0xff)
- return -1; /* forbidden length value */
- else
- {
- unsigned long len = 0;
- int count = c & 0x7f;
-
- for (; count; count--)
- {
- len <<= 8;
- if (!length)
- return -1; /* premature_eof */
- c = *buf++; length--;
- ti->nhdr++;
- len |= c & 0xff;
- }
- ti->length = len;
- }
-
- if (ti->class == UNIVERSAL && !ti->tag)
- ti->length = 0;
-
- if (ti->length > length)
- return -1; /* data larger than buffer. */
-
- *buffer = buf;
- *size = length;
- return 0;
-}
-
-
-static int
-string_to_key (int id, char *salt, int iter, const char *pw,
- int req_keylen, unsigned char *keybuf)
-{
- int rc, i, j;
- gcry_md_hd_t md;
- gcry_mpi_t num_b1 = NULL;
- int pwlen;
- unsigned char hash[20], buf_b[64], buf_i[128], *p;
- size_t cur_keylen;
- size_t n;
-
- cur_keylen = 0;
- pwlen = strlen (pw);
- if (pwlen > 63/2)
- {
- log_error ("password too long\n");
- return -1;
- }
-
- /* Store salt and password in BUF_I */
- p = buf_i;
- for(i=0; i < 64; i++)
- *p++ = salt [i%8];
- for(i=j=0; i < 64; i += 2)
- {
- *p++ = 0;
- *p++ = pw[j];
- if (++j > pwlen) /* Note, that we include the trailing zero */
- j = 0;
- }
-
- for (;;)
- {
- rc = gcry_md_open (&md, GCRY_MD_SHA1, 0);
- if (rc)
- {
- log_error ( "gcry_md_open failed: %s\n", gpg_strerror (rc));
- return rc;
- }
- for(i=0; i < 64; i++)
- gcry_md_putc (md, id);
- gcry_md_write (md, buf_i, 128);
- memcpy (hash, gcry_md_read (md, 0), 20);
- gcry_md_close (md);
- for (i=1; i < iter; i++)
- gcry_md_hash_buffer (GCRY_MD_SHA1, hash, hash, 20);
-
- for (i=0; i < 20 && cur_keylen < req_keylen; i++)
- keybuf[cur_keylen++] = hash[i];
- if (cur_keylen == req_keylen)
- {
- gcry_mpi_release (num_b1);
- return 0; /* ready */
- }
-
- /* need more bytes. */
- for(i=0; i < 64; i++)
- buf_b[i] = hash[i % 20];
- rc = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, 64, &n);
- if (rc)
- {
- log_error ( "gcry_mpi_scan failed: %s\n", gpg_strerror (rc));
- return -1;
- }
- gcry_mpi_add_ui (num_b1, num_b1, 1);
- for (i=0; i < 128; i += 64)
- {
- gcry_mpi_t num_ij;
-
- rc = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, 64, &n);
- if (rc)
- {
- log_error ( "gcry_mpi_scan failed: %s\n",
- gpg_strerror (rc));
- return -1;
- }
- gcry_mpi_add (num_ij, num_ij, num_b1);
- gcry_mpi_clear_highbit (num_ij, 64*8);
- rc = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, 64, &n, num_ij);
- if (rc)
- {
- log_error ( "gcry_mpi_print failed: %s\n",
- gpg_strerror (rc));
- return -1;
- }
- gcry_mpi_release (num_ij);
- }
- }
-}
-
-
-static int
-set_key_iv (gcry_cipher_hd_t chd, char *salt, int iter, const char *pw)
-{
- unsigned char keybuf[24];
- int rc;
-
- if (string_to_key (1, salt, iter, pw, 24, keybuf))
- return -1;
- rc = gcry_cipher_setkey (chd, keybuf, 24);
- if (rc)
- {
- log_error ( "gcry_cipher_setkey failed: %s\n", gpg_strerror (rc));
- return -1;
- }
-
- if (string_to_key (2, salt, iter, pw, 8, keybuf))
- return -1;
- rc = gcry_cipher_setiv (chd, keybuf, 8);
- if (rc)
- {
- log_error ("gcry_cipher_setiv failed: %s\n", gpg_strerror (rc));
- return -1;
- }
- return 0;
-}
-
-
-static void
-crypt_block (unsigned char *buffer, size_t length, char *salt, int iter,
- const char *pw, int encrypt)
-{
- gcry_cipher_hd_t chd;
- int rc;
-
- rc = gcry_cipher_open (&chd, GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 0);
- if (rc)
- {
- log_error ( "gcry_cipher_open failed: %s\n", gpg_strerror(-1));
- return;
- }
- if (set_key_iv (chd, salt, iter, pw))
- goto leave;
-
- rc = encrypt? gcry_cipher_encrypt (chd, buffer, length, NULL, 0)
- : gcry_cipher_decrypt (chd, buffer, length, NULL, 0);
-
- if (rc)
- {
- log_error ( "en/de-crytion failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
-
-/* { */
-/* FILE *fp = fopen("inner.der", "wb"); */
-/* fwrite (buffer, 1, length, fp); */
-/* fclose (fp); */
-/* } */
-
- leave:
- gcry_cipher_close (chd);
-}
-
-
-
-
-static int
-parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
- int startoffset)
-{
- struct tag_info ti;
- const unsigned char *p = buffer;
- size_t n = length;
- const char *where;
-
- where = "start";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class != CONTEXT || ti.tag)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.tag != TAG_SEQUENCE)
- goto bailout;
-
- where = "bag.encryptedData.version";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 0)
- goto bailout;
- p++; n--;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.tag != TAG_SEQUENCE)
- goto bailout;
-
- where = "bag.encryptedData.data";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
- || memcmp (p, oid_data, DIM(oid_data)))
- goto bailout;
- p += DIM(oid_data);
- n -= DIM(oid_data);
-
- /* fixme: continue parsing */
-
- return 0;
- bailout:
- log_error ("encrptedData error at \"%s\", offset %u\n",
- where, (p - buffer)+startoffset);
- return -1;
-}
-
-static gcry_mpi_t *
-parse_bag_data (const unsigned char *buffer, size_t length, int startoffset,
- const char *pw)
-{
- int rc;
- struct tag_info ti;
- const unsigned char *p = buffer;
- size_t n = length;
- const char *where;
- char salt[8];
- unsigned int iter;
- int len;
- unsigned char *plain = NULL;
- gcry_mpi_t *result = NULL;
- int result_count, i;
-
- where = "start";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class != CONTEXT || ti.tag)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_OCTET_STRING)
- goto bailout;
-
- where = "data.outerseqs";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_SEQUENCE)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_SEQUENCE)
- goto bailout;
-
- where = "data.objectidentifier";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_OBJECT_ID
- || ti.length != DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)
- || memcmp (p, oid_pkcs_12_pkcs_8ShroudedKeyBag,
- DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag)))
- goto bailout;
- p += DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
- n -= DIM(oid_pkcs_12_pkcs_8ShroudedKeyBag);
-
- where = "shrouded,outerseqs";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class != CONTEXT || ti.tag)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_SEQUENCE)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_SEQUENCE)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_OBJECT_ID
- || ti.length != DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)
- || memcmp (p, oid_pbeWithSHAAnd3_KeyTripleDES_CBC,
- DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC)))
- goto bailout;
- p += DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
- n -= DIM(oid_pbeWithSHAAnd3_KeyTripleDES_CBC);
-
- where = "3des-params";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_SEQUENCE)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_OCTET_STRING || ti.length != 8 )
- goto bailout;
- memcpy (salt, p, 8);
- p += 8;
- n -= 8;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_INTEGER || !ti.length )
- goto bailout;
- for (iter=0; ti.length; ti.length--)
- {
- iter <<= 8;
- iter |= (*p++) & 0xff;
- n--;
- }
-
- where = "3des-ciphertext";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class || ti.tag != TAG_OCTET_STRING || !ti.length )
- goto bailout;
-
- log_info ("%lu bytes of 3DES encrypted text\n", ti.length);
-
- plain = gcry_malloc_secure (ti.length);
- if (!plain)
- {
- log_error ("error allocating decryption buffer\n");
- goto bailout;
- }
- memcpy (plain, p, ti.length);
- crypt_block (plain, ti.length, salt, iter, pw, 0);
- n = ti.length;
- startoffset = 0;
- buffer = p = plain;
-
- where = "decrypted-text";
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
- goto bailout;
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER
- || ti.length != 1 || *p)
- goto bailout;
- p++; n--;
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
- goto bailout;
- len = ti.length;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (len < ti.nhdr)
- goto bailout;
- len -= ti.nhdr;
- if (ti.class || ti.tag != TAG_OBJECT_ID
- || ti.length != DIM(oid_rsaEncryption)
- || memcmp (p, oid_rsaEncryption,
- DIM(oid_rsaEncryption)))
- goto bailout;
- p += DIM (oid_rsaEncryption);
- n -= DIM (oid_rsaEncryption);
- if (len < ti.length)
- goto bailout;
- len -= ti.length;
- if (n < len)
- goto bailout;
- p += len;
- n -= len;
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_OCTET_STRING)
- goto bailout;
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_SEQUENCE)
- goto bailout;
- len = ti.length;
-
- result = gcry_calloc (10, sizeof *result);
- if (!result)
- {
- log_error ( "error allocating result array\n");
- goto bailout;
- }
- result_count = 0;
-
- where = "reading.key-parameters";
- for (result_count=0; len && result_count < 9;)
- {
- if (parse_tag (&p, &n, &ti) || ti.class || ti.tag != TAG_INTEGER)
- goto bailout;
- if (len < ti.nhdr)
- goto bailout;
- len -= ti.nhdr;
- if (len < ti.length)
- goto bailout;
- len -= ti.length;
- if (!result_count && ti.length == 1 && !*p)
- ; /* ignore the very first one if it is a 0 */
- else
- {
- rc = gcry_mpi_scan (result+result_count, GCRYMPI_FMT_USG, p,
- ti.length, NULL);
- if (rc)
- {
- log_error ("error parsing key parameter: %s\n",
- gpg_strerror (rc));
- goto bailout;
- }
- result_count++;
- }
- p += ti.length;
- n -= ti.length;
- }
- if (len)
- goto bailout;
-
- return result;
-
- bailout:
- gcry_free (plain);
- if (result)
- {
- for (i=0; result[i]; i++)
- gcry_mpi_release (result[i]);
- gcry_free (result);
- }
- log_error ( "data error at \"%s\", offset %u\n",
- where, (p - buffer) + startoffset);
- return NULL;
-}
-
-
-/* Parse a PKCS12 object and return an array of MPI representing the
- secret key parameters. This is a very limited inplementation in
- that it is only able to look for 3DES encoded enctyptedData and
- tries to extract the first private key object it finds. In case of
- an error NULL is returned. */
-gcry_mpi_t *
-p12_parse (const unsigned char *buffer, size_t length, const char *pw)
-{
- struct tag_info ti;
- const unsigned char *p = buffer;
- size_t n = length;
- const char *where;
- int bagseqlength, len;
-
- where = "pfx";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.tag != TAG_SEQUENCE)
- goto bailout;
-
- where = "pfxVersion";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.tag != TAG_INTEGER || ti.length != 1 || *p != 3)
- goto bailout;
- p++; n--;
-
- where = "authSave";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.tag != TAG_SEQUENCE)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.tag != TAG_OBJECT_ID || ti.length != DIM(oid_data)
- || memcmp (p, oid_data, DIM(oid_data)))
- goto bailout;
- p += DIM(oid_data);
- n -= DIM(oid_data);
-
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class != CONTEXT || ti.tag)
- goto bailout;
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class != UNIVERSAL || ti.tag != TAG_OCTET_STRING)
- goto bailout;
-
- where = "bags";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
- goto bailout;
- bagseqlength = ti.length;
- while (bagseqlength)
- {
- /*log_debug ( "at offset %u\n", (p - buffer));*/
- where = "bag-sequence";
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- if (ti.class != UNIVERSAL || ti.tag != TAG_SEQUENCE)
- goto bailout;
-
- if (bagseqlength < ti.nhdr)
- goto bailout;
- bagseqlength -= ti.nhdr;
- if (bagseqlength < ti.length)
- goto bailout;
- bagseqlength -= ti.length;
- len = ti.length;
-
- if (parse_tag (&p, &n, &ti))
- goto bailout;
- len -= ti.nhdr;
- if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_encryptedData)
- && !memcmp (p, oid_encryptedData, DIM(oid_encryptedData)))
- {
- p += DIM(oid_encryptedData);
- n -= DIM(oid_encryptedData);
- len -= DIM(oid_encryptedData);
- where = "bag.encryptedData";
- if (parse_bag_encrypted_data (p, n, (p - buffer)))
- goto bailout;
- }
- else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
- && !memcmp (p, oid_data, DIM(oid_data)))
- {
- p += DIM(oid_data);
- n -= DIM(oid_data);
- len -= DIM(oid_data);
- return parse_bag_data (p, n, (p-buffer), pw);
- }
- else
- log_info ( "unknown bag type - skipped\n");
-
- if (len < 0 || len > n)
- goto bailout;
- p += len;
- n -= len;
- }
-
- return NULL;
- bailout:
- log_error ("error at \"%s\", offset %u\n", where, (p - buffer));
- return NULL;
-}
-
-
-
-static size_t
-compute_tag_length (size_t n)
-{
- int needed = 0;
-
- if (n < 128)
- needed += 2; /* tag and one length byte */
- else if (n < 256)
- needed += 3; /* tag, number of length bytes, 1 length byte */
- else if (n < 65536)
- needed += 4; /* tag, number of length bytes, 2 length bytes */
- else
- {
- log_error ("object too larger to encode\n");
- return 0;
- }
- return needed;
-}
-
-static unsigned char *
-store_tag_length (unsigned char *p, int tag, size_t n)
-{
- if (tag == TAG_SEQUENCE)
- tag |= 0x20; /* constructed */
-
- *p++ = tag;
- if (n < 128)
- *p++ = n;
- else if (n < 256)
- {
- *p++ = 0x81;
- *p++ = n;
- }
- else if (n < 65536)
- {
- *p++ = 0x82;
- *p++ = n >> 8;
- *p++ = n;
- }
-
- return p;
-}
-
-
-/* Create the final PKCS-12 object from the sequences contained in
- SEQLIST. That array is terminated with an NULL object */
-static unsigned char *
-create_final (struct buffer_s *sequences, size_t *r_length)
-{
- int i;
- size_t needed = 0;
- size_t n, outseqlen, notsooutseqlen, out0taglen, octstrlen, inseqlen;
- unsigned char *result, *p;
- size_t resultlen;
-
- for (i=0; sequences[i].buffer; i++)
- needed += sequences[i].length;
- /* This goes into a sequences. */
- inseqlen = needed;
- n = compute_tag_length (needed);
- needed += n;
- /* And encapsulate all in an octet string. */
- octstrlen = needed;
- n = compute_tag_length (needed);
- needed += n;
- /* And tag it with [0]. */
- out0taglen = needed;
- n = compute_tag_length (needed);
- needed += n;
- /* Prepend an data OID. */
- needed += 2 + DIM (oid_data);
- /* This all into a sequences. */
- notsooutseqlen = needed;
- n = compute_tag_length (needed);
- needed += n;
- /* Prepend the version integer 3. */
- needed += 3;
- /* And the final sequence. */
- outseqlen = needed;
- n = compute_tag_length (needed);
- needed += n;
-
- result = gcry_malloc (needed);
- if (!result)
- {
- log_error ("error allocating buffer\n");
- return NULL;
- }
- p = result;
-
- /* Store the very outer sequence. */
- p = store_tag_length (p, TAG_SEQUENCE, outseqlen);
- /* Store the version integer 3. */
- *p++ = TAG_INTEGER;
- *p++ = 1;
- *p++ = 3;
- /* Store another sequence. */
- p = store_tag_length (p, TAG_SEQUENCE, notsooutseqlen);
- /* Store the data OID. */
- p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data));
- memcpy (p, oid_data, DIM (oid_data));
- p += DIM (oid_data);
- /* Next comes a context tag. */
- p = store_tag_length (p, 0xa0, out0taglen);
- /* And an octet string. */
- p = store_tag_length (p, TAG_OCTET_STRING, octstrlen);
- /* And the inner sequence. */
- p = store_tag_length (p, TAG_SEQUENCE, inseqlen);
- /* And append all the buffers. */
- for (i=0; sequences[i].buffer; i++)
- {
- memcpy (p, sequences[i].buffer, sequences[i].length);
- p += sequences[i].length;
- }
-
- /* Ready. */
- resultlen = p - result;
- if (needed != resultlen)
- log_debug ("length mismatch: %u, %u\n", needed, resultlen);
-
- *r_length = resultlen;
- return result;
-}
-
-
-/* Expect the RSA key parameters in KPARMS and a password in
- PW. Create a PKCS structure from it and return it as well as the
- length in R_LENGTH; return NULL in case of an error. */
-unsigned char *
-p12_build (gcry_mpi_t *kparms, const char *pw, size_t *r_length)
-{
- int rc, i;
- size_t needed, n;
- unsigned char *plain, *p, *cipher;
- size_t plainlen, cipherlen;
- size_t outseqlen, oidseqlen, octstrlen, inseqlen;
- size_t out0taglen, in0taglen, outoctstrlen;
- size_t aseq1len, aseq2len, aseq3len;
- char salt[8];
-
- needed = 3; /* The version(?) integer of value 0. */
- for (i=0; kparms[i]; i++)
- {
- n = 0;
- rc = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, kparms[i]);
- if (rc)
- {
- log_error ("error formatting parameter: %s\n", gpg_strerror (rc));
- return NULL;
- }
- needed += n;
- n = compute_tag_length (n);
- if (!n)
- return NULL;
- needed += n;
- }
- if (i != 8)
- {
- log_error ("invalid paramters for p12_build\n");
- return NULL;
- }
- /* Now this all goes into a sequence. */
- inseqlen = needed;
- n = compute_tag_length (needed);
- if (!n)
- return NULL;
- needed += n;
- /* Encapsulate all into an octet string. */
- octstrlen = needed;
- n = compute_tag_length (needed);
- if (!n)
- return NULL;
- needed += n;
- /* Prepend the object identifier sequence. */
- oidseqlen = 2 + DIM (oid_rsaEncryption) + 2;
- needed += 2 + oidseqlen;
- /* The version number. */
- needed += 3;
- /* And finally put the whole thing into a sequence. */
- outseqlen = needed;
- n = compute_tag_length (needed);
- if (!n)
- return NULL;
- needed += n;
-
- /* allocate 8 extra bytes for padding */
- plain = gcry_malloc_secure (needed+8);
- if (!plain)
- {
- log_error ("error allocating encryption buffer\n");
- return NULL;
- }
-
- /* And now fill the plaintext buffer. */
- p = plain;
- p = store_tag_length (p, TAG_SEQUENCE, outseqlen);
- /* Store version. */
- *p++ = TAG_INTEGER;
- *p++ = 1;
- *p++ = 0;
- /* Store object identifier sequence. */
- p = store_tag_length (p, TAG_SEQUENCE, oidseqlen);
- p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_rsaEncryption));
- memcpy (p, oid_rsaEncryption, DIM (oid_rsaEncryption));
- p += DIM (oid_rsaEncryption);
- *p++ = TAG_NULL;
- *p++ = 0;
- /* Start with the octet string. */
- p = store_tag_length (p, TAG_OCTET_STRING, octstrlen);
- p = store_tag_length (p, TAG_SEQUENCE, inseqlen);
- /* Store the key parameters. */
- *p++ = TAG_INTEGER;
- *p++ = 1;
- *p++ = 0;
- for (i=0; kparms[i]; i++)
- {
- n = 0;
- rc = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &n, kparms[i]);
- if (rc)
- {
- log_error ("oops: error formatting parameter: %s\n",
- gpg_strerror (rc));
- gcry_free (plain);
- return NULL;
- }
- p = store_tag_length (p, TAG_INTEGER, n);
-
- n = plain + needed - p;
- rc = gcry_mpi_print (GCRYMPI_FMT_STD, p, n, &n, kparms[i]);
- if (rc)
- {
- log_error ("oops: error storing parameter: %s\n",
- gpg_strerror (rc));
- gcry_free (plain);
- return NULL;
- }
- p += n;
- }
-
- plainlen = p - plain;
- assert (needed == plainlen);
- /* Append some pad characters; we already allocated extra space. */
- n = 8 - plainlen % 8;
- for (;(plainlen % 8); plainlen++)
- *p++ = n;
-
- {
- FILE *fp = fopen("inner-out.der", "wb");
- fwrite (plain, 1, plainlen, fp);
- fclose (fp);
- }
-
-
- /* Encrypt it and prepend a lot of stupid things. */
- gcry_randomize (salt, 8, GCRY_STRONG_RANDOM);
- crypt_block (plain, plainlen, salt, 1024, pw, 1);
- /* the data goes into an octet string. */
- needed = compute_tag_length (plainlen);
- needed += plainlen;
- /* we prepend the the algorithm identifier (we use a pre-encoded one)*/
- needed += DIM (data_3desiter1024);
- /* we put a sequence around. */
- aseq3len = needed;
- needed += compute_tag_length (needed);
- /* Prepend it with a [0] tag. */
- in0taglen = needed;
- needed += compute_tag_length (needed);
- /* Prepend that shroudedKeyBag OID. */
- needed += 2 + DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag);
- /* Put it all into two sequence. */
- aseq2len = needed;
- needed += compute_tag_length ( needed);
- aseq1len = needed;
- needed += compute_tag_length (needed);
- /* This all goes into an octet string. */
- outoctstrlen = needed;
- needed += compute_tag_length (needed);
- /* Prepend it with a [0] tag. */
- out0taglen = needed;
- needed += compute_tag_length (needed);
- /* Prepend the data OID. */
- needed += 2 + DIM (oid_data);
- /* And a sequence. */
- outseqlen = needed;
- needed += compute_tag_length (needed);
-
- cipher = gcry_malloc (needed);
- if (!cipher)
- {
- log_error ("error allocating buffer\n");
- gcry_free (plain);
- return NULL;
- }
- p = cipher;
- /* Store the first sequence. */
- p = store_tag_length (p, TAG_SEQUENCE, outseqlen);
- /* Store the data OID. */
- p = store_tag_length (p, TAG_OBJECT_ID, DIM (oid_data));
- memcpy (p, oid_data, DIM (oid_data));
- p += DIM (oid_data);
- /* Next comes a context tag. */
- p = store_tag_length (p, 0xa0, out0taglen);
- /* And an octet string. */
- p = store_tag_length (p, TAG_OCTET_STRING, outoctstrlen);
- /* Two sequences. */
- p = store_tag_length (p, TAG_SEQUENCE, aseq1len);
- p = store_tag_length (p, TAG_SEQUENCE, aseq2len);
- /* Store the shroudedKeyBag OID. */
- p = store_tag_length (p, TAG_OBJECT_ID,
- DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag));
- memcpy (p, oid_pkcs_12_pkcs_8ShroudedKeyBag,
- DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag));
- p += DIM (oid_pkcs_12_pkcs_8ShroudedKeyBag);
- /* Next comes a context tag. */
- p = store_tag_length (p, 0xa0, in0taglen);
- /* And a sequence. */
- p = store_tag_length (p, TAG_SEQUENCE, aseq3len);
- /* Now for the pre-encoded algorithm indentifier and the salt. */
- memcpy (p, data_3desiter1024, DIM (data_3desiter1024));
- memcpy (p + DATA_3DESITER1024_SALT_OFF, salt, 8);
- p += DIM (data_3desiter1024);
- /* And finally the octet string with the encrypted data. */
- p = store_tag_length (p, TAG_OCTET_STRING, plainlen);
- memcpy (p, plain, plainlen);
- p += plainlen;
- cipherlen = p - cipher;
-
- if (needed != cipherlen)
- log_debug ("length mismatch: %u, %u\n", needed, cipherlen);
- gcry_free (plain);
-
- {
- struct buffer_s seqlist[2];
-
- seqlist[0].buffer = cipher;
- seqlist[0].length = cipherlen;
- seqlist[1].buffer = NULL;
- seqlist[1].length = 0;
-
- cipher = create_final (seqlist, &cipherlen);
- gcry_free (seqlist[0].buffer);
- }
-
- *r_length = cipherlen;
- return cipher;
-}
-
-
-#ifdef TEST
-int
-main (int argc, char **argv)
-{
- FILE *fp;
- struct stat st;
- char *buf;
- size_t buflen;
- GcryMPI *result;
-
- if (argc != 3)
- {
- fprintf (stderr, "usage: testp12 file passphrase\n");
- return 1;
- }
-
- gcry_control (GCRYCTL_DISABLE_SECMEM, NULL);
- gcry_control (GCRYCTL_INITIALIZATION_FINISHED, NULL);
-
- fp = fopen (argv[1], "rb");
- if (!fp)
- {
- fprintf (stderr, "can't open `%s': %s\n", argv[1], strerror (errno));
- return 1;
- }
-
- if (fstat (fileno(fp), &st))
- {
- fprintf (stderr, "can't stat `%s': %s\n", argv[1], strerror (errno));
- return 1;
- }
-
- buflen = st.st_size;
- buf = gcry_malloc (buflen+1);
- if (!buf || fread (buf, buflen, 1, fp) != 1)
- {
- fprintf (stderr, "error reading `%s': %s\n", argv[1], strerror (errno));
- return 1;
- }
- fclose (fp);
-
- result = p12_parse (buf, buflen, argv[2]);
- if (result)
- {
- int i, rc;
- char *buf;
-
- for (i=0; result[i]; i++)
- {
- rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, (void**)&buf,
- NULL, result[i]);
- if (rc)
- printf ("%d: [error printing number: %s]\n",
- i, gpg_strerror (rc));
- else
- {
- printf ("%d: %s\n", i, buf);
- gcry_free (buf);
- }
- }
- }
-
- return 0;
-
-}
-#endif /* TEST */
diff --git a/agent/minip12.h b/agent/minip12.h
deleted file mode 100644
index 122215549..000000000
--- a/agent/minip12.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* minip12.h - Global definitions for the minimal pkcs-12 implementation.
- * 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
- */
-
-#ifndef MINIP12_H
-#define MINIP12_H
-
-#include <gcrypt.h>
-
-gcry_mpi_t *p12_parse (const unsigned char *buffer, size_t length,
- const char *pw);
-
-unsigned char *p12_build (gcry_mpi_t *kparms, const char *pw,
- size_t *r_length);
-
-
-#endif /*MINIP12_H*/
diff --git a/agent/pkdecrypt.c b/agent/pkdecrypt.c
deleted file mode 100644
index 543a82737..000000000
--- a/agent/pkdecrypt.c
+++ /dev/null
@@ -1,138 +0,0 @@
-/* pkdecrypt.c - public key decryption (well, acually using a secret key)
- * Copyright (C) 2001, 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 <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "agent.h"
-
-
-/* DECRYPT the stuff in ciphertext which is expected to be a S-Exp.
- Try to get the key from CTRL and write the decoded stuff back to
- OUTFP. */
-int
-agent_pkdecrypt (CTRL ctrl, const char *ciphertext, size_t ciphertextlen,
- FILE *outfp)
-{
- gcry_sexp_t s_skey = NULL, s_cipher = NULL, s_plain = NULL;
- unsigned char *shadow_info = NULL;
- int rc;
- char *buf = NULL;
- size_t len;
-
- if (!ctrl->have_keygrip)
- {
- log_error ("speculative decryption not yet supported\n");
- rc = gpg_error (GPG_ERR_NO_SECKEY);
- goto leave;
- }
-
- rc = gcry_sexp_sscan (&s_cipher, NULL, ciphertext, ciphertextlen);
- if (rc)
- {
- log_error ("failed to convert ciphertext: %s\n", gpg_strerror (rc));
- rc = gpg_error (GPG_ERR_INV_DATA);
- goto leave;
- }
-
- if (DBG_CRYPTO)
- {
- log_printhex ("keygrip:", ctrl->keygrip, 20);
- log_printhex ("cipher: ", ciphertext, ciphertextlen);
- }
- s_skey = agent_key_from_file (ctrl, ctrl->keygrip, &shadow_info, 0);
- if (!s_skey && !shadow_info)
- {
- log_error ("failed to read the secret key\n");
- rc = gpg_error (GPG_ERR_NO_SECKEY);
- goto leave;
- }
-
- if (!s_skey)
- { /* divert operation to the smartcard */
-
- if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
- {
- rc = gpg_error (GPG_ERR_INV_SEXP);
- goto leave;
- }
-
- rc = divert_pkdecrypt (ctrl, ciphertext, shadow_info, &buf, &len );
- if (rc)
- {
- log_error ("smartcard decryption failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
- /* FIXME: don't use buffering and change the protocol to return
- a complete S-expression and not just a part. */
- fprintf (outfp, "%u:", (unsigned int)len);
- fwrite (buf, 1, len, outfp);
- putc (0, outfp);
- }
- else
- { /* no smartcard, but a private key */
- if (DBG_CRYPTO)
- {
- log_debug ("skey: ");
- gcry_sexp_dump (s_skey);
- }
-
- rc = gcry_pk_decrypt (&s_plain, s_cipher, s_skey);
- if (rc)
- {
- log_error ("decryption failed: %s\n", gpg_strerror (rc));
- rc = map_gcry_err (rc);
- goto leave;
- }
-
- if (DBG_CRYPTO)
- {
- log_debug ("plain: ");
- gcry_sexp_dump (s_plain);
- }
- len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, NULL, 0);
- assert (len);
- buf = xmalloc (len);
- len = gcry_sexp_sprint (s_plain, GCRYSEXP_FMT_CANON, buf, len);
- assert (len);
- /* FIXME: we must make sure that no buffering takes place or we are
- in full control of the buffer memory (easy to do) - should go
- into assuan. */
- fwrite (buf, 1, len, outfp);
- }
-
-
- leave:
- gcry_sexp_release (s_skey);
- gcry_sexp_release (s_plain);
- gcry_sexp_release (s_cipher);
- xfree (buf);
- xfree (shadow_info);
- return rc;
-}
-
-
diff --git a/agent/pksign.c b/agent/pksign.c
deleted file mode 100644
index fba2c652c..000000000
--- a/agent/pksign.c
+++ /dev/null
@@ -1,185 +0,0 @@
-/* pksign.c - public key signing (well, acually using a secret key)
- * 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
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "agent.h"
-
-
-static int
-do_encode_md (const unsigned char *digest, size_t digestlen, int algo,
- unsigned int nbits, gcry_mpi_t *r_val)
-{
- int nframe = (nbits+7) / 8;
- byte *frame;
- int i, n;
- byte asn[100];
- size_t asnlen;
-
- asnlen = DIM(asn);
- if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen))
- {
- log_error ("no object identifier for algo %d\n", algo);
- return gpg_error (GPG_ERR_INTERNAL);
- }
-
- if (digestlen + asnlen + 4 > nframe )
- {
- log_error ("can't encode a %d bit MD into a %d bits frame\n",
- (int)(digestlen*8), (int)nbits);
- return gpg_error (GPG_ERR_INTERNAL);
- }
-
- /* We encode the MD in this way:
- *
- * 0 1 PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
- *
- * PAD consists of FF bytes.
- */
- frame = xtrymalloc (nframe);
- if (!frame)
- return out_of_core ();
- n = 0;
- frame[n++] = 0;
- frame[n++] = 1; /* block type */
- i = nframe - digestlen - asnlen -3 ;
- assert ( i > 1 );
- memset ( frame+n, 0xff, i ); n += i;
- frame[n++] = 0;
- memcpy ( frame+n, asn, asnlen ); n += asnlen;
- memcpy ( frame+n, digest, digestlen ); n += digestlen;
- assert ( n == nframe );
- if (DBG_CRYPTO)
- log_printhex ("encoded hash:", frame, nframe);
-
- gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, n, &nframe);
- xfree (frame);
- return 0;
-}
-
-
-/* SIGN whatever information we have accumulated in CTRL and write it
- back to OUTFP. */
-int
-agent_pksign (CTRL ctrl, FILE *outfp, int ignore_cache)
-{
- gcry_sexp_t s_skey = NULL, s_hash = NULL, s_sig = NULL;
- gcry_mpi_t frame = NULL;
- unsigned char *shadow_info = NULL;
- int rc;
- char *buf = NULL;
- size_t len;
-
- if (!ctrl->have_keygrip)
- return gpg_error (GPG_ERR_NO_SECKEY);
-
- s_skey = agent_key_from_file (ctrl,
- ctrl->keygrip, &shadow_info, ignore_cache);
- if (!s_skey && !shadow_info)
- {
- log_error ("failed to read the secret key\n");
- rc = gpg_error (GPG_ERR_NO_SECKEY);
- goto leave;
- }
-
- if (!s_skey)
- { /* divert operation to the smartcard */
- unsigned char *sigbuf;
-
- rc = divert_pksign (ctrl,
- ctrl->digest.value,
- ctrl->digest.valuelen,
- ctrl->digest.algo,
- shadow_info, &sigbuf);
- if (rc)
- {
- log_error ("smartcard signing failed: %s\n", gpg_strerror (rc));
- goto leave;
- }
- len = gcry_sexp_canon_len (sigbuf, 0, NULL, NULL);
- assert (len);
- buf = sigbuf;
- }
- else
- { /* no smartcard, but a private key */
-
- /* put the hash into a sexp */
- rc = do_encode_md (ctrl->digest.value,
- ctrl->digest.valuelen,
- ctrl->digest.algo,
- gcry_pk_get_nbits (s_skey),
- &frame);
- if (rc)
- goto leave;
- if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
- BUG ();
-
- if (DBG_CRYPTO)
- {
- log_debug ("skey: ");
- gcry_sexp_dump (s_skey);
- }
-
- /* sign */
- rc = gcry_pk_sign (&s_sig, s_hash, s_skey);
- if (rc)
- {
- log_error ("signing failed: %s\n", gpg_strerror (rc));
- rc = map_gcry_err (rc);
- goto leave;
- }
-
- if (DBG_CRYPTO)
- {
- log_debug ("result: ");
- gcry_sexp_dump (s_sig);
- }
-
- len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, NULL, 0);
- assert (len);
- buf = xmalloc (len);
- len = gcry_sexp_sprint (s_sig, GCRYSEXP_FMT_CANON, buf, len);
- assert (len);
- }
-
- /* FIXME: we must make sure that no buffering takes place or we are
- in full control of the buffer memory (easy to do) - should go
- into assuan. */
- fwrite (buf, 1, len, outfp);
-
- leave:
- gcry_sexp_release (s_skey);
- gcry_sexp_release (s_hash);
- gcry_sexp_release (s_sig);
- gcry_mpi_release (frame);
- xfree (buf);
- xfree (shadow_info);
- return rc;
-}
-
-
diff --git a/agent/protect-tool.c b/agent/protect-tool.c
deleted file mode 100644
index e518c5672..000000000
--- a/agent/protect-tool.c
+++ /dev/null
@@ -1,977 +0,0 @@
-/* protect-tool.c - A tool to test the secret key protection
- * 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
- */
-
-#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 <sys/stat.h>
-#include <unistd.h>
-
-#define JNLIB_NEED_LOG_LOGV
-#include "agent.h"
-#include "minip12.h"
-#include "simple-pwquery.h"
-#include "i18n.h"
-
-enum cmd_and_opt_values
-{ aNull = 0,
- oVerbose = 'v',
- oArmor = 'a',
- oPassphrase = 'P',
-
- oProtect = 'p',
- oUnprotect = 'u',
-
- oNoVerbose = 500,
- oShadow,
- oShowShadowInfo,
- oShowKeygrip,
-
- oP12Import,
- oP12Export,
- oStore,
- oForce,
-
-aTest };
-
-struct rsa_secret_key_s
- {
- gcry_mpi_t n; /* public modulus */
- gcry_mpi_t e; /* public exponent */
- gcry_mpi_t d; /* exponent */
- gcry_mpi_t p; /* prime p. */
- gcry_mpi_t q; /* prime q. */
- gcry_mpi_t u; /* inverse of p mod q. */
- };
-
-
-static int opt_armor;
-static int opt_store;
-static int opt_force;
-static const char *passphrase;
-
-static const char *get_passphrase (void);
-static int store_private_key (const unsigned char *grip,
- const void *buffer, size_t length, int force);
-
-
-static ARGPARSE_OPTS opts[] = {
-
- { 301, NULL, 0, N_("@Options:\n ") },
-
- { oVerbose, "verbose", 0, "verbose" },
- { oArmor, "armor", 0, "write output in advanced format" },
- { oPassphrase, "passphrase", 2, "|STRING|use passphrase STRING" },
- { oProtect, "protect", 256, "protect a private key"},
- { oUnprotect, "unprotect", 256, "unprotect a private key"},
- { oShadow, "shadow", 256, "create a shadow entry for a priblic key"},
- { oShowShadowInfo, "show-shadow-info", 256, "return the shadow info"},
- { oShowKeygrip, "show-keygrip", 256, "show the \"keygrip\""},
-
- { oP12Import, "p12-import", 256, "import a PKCS-12 encoded private key"},
- { oP12Export, "p12-export", 256, "export a private key PKCS-12 encoded"},
- { oStore, "store", 0, "store the created key in the appropriate place"},
- { oForce, "force", 0, "force overwriting"},
- {0}
-};
-
-static const char *
-my_strusage (int level)
-{
- const char *p;
- switch (level)
- {
- case 11: p = "gpg-protect-tool (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: gpg-protect-tool [options] (-h for help)\n");
- break;
- case 41: p = _("Syntax: gpg-protect-tool [options] [args]]\n"
- "Secret key maintenance tool\n");
- break;
-
- default: p = NULL;
- }
- return p;
-}
-
-
-
-static void
-i18n_init (void)
-{
-#ifdef USE_SIMPLE_GETTEXT
- set_gettext_file( PACKAGE );
-#else
-#ifdef ENABLE_NLS
- setlocale (LC_ALL, "");
- bindtextdomain (PACKAGE, LOCALEDIR);
- textdomain (PACKAGE);
-#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);
-}
-
-
-/* static void */
-/* print_mpi (const char *text, gcry_mpi_t a) */
-/* { */
-/* char *buf; */
-/* void *bufaddr = &buf; */
-/* int rc; */
-
-/* rc = gcry_mpi_aprint (GCRYMPI_FMT_HEX, bufaddr, NULL, a); */
-/* if (rc) */
-/* log_info ("%s: [error printing number: %s]\n", text, gpg_strerror (rc)); */
-/* else */
-/* { */
-/* log_info ("%s: %s\n", text, buf); */
-/* gcry_free (buf); */
-/* } */
-/* } */
-
-
-
-static unsigned char *
-make_canonical (const char *fname, const char *buf, size_t buflen)
-{
- int rc;
- size_t erroff, len;
- gcry_sexp_t sexp;
- unsigned char *result;
-
- rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
- if (rc)
- {
- log_error ("invalid S-Expression in `%s' (off=%u): %s\n",
- fname, (unsigned int)erroff, gpg_strerror (rc));
- return NULL;
- }
- len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
- assert (len);
- result = xmalloc (len);
- len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, result, len);
- assert (len);
- gcry_sexp_release (sexp);
- return result;
-}
-
-static char *
-make_advanced (const unsigned char *buf, size_t buflen)
-{
- int rc;
- size_t erroff, len;
- gcry_sexp_t sexp;
- unsigned char *result;
-
- rc = gcry_sexp_sscan (&sexp, &erroff, buf, buflen);
- if (rc)
- {
- log_error ("invalid canonical S-Expression (off=%u): %s\n",
- (unsigned int)erroff, gpg_strerror (rc));
- return NULL;
- }
- len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
- assert (len);
- result = xmalloc (len);
- len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_ADVANCED, result, len);
- assert (len);
- gcry_sexp_release (sexp);
- return result;
-}
-
-
-static char *
-read_file (const char *fname, size_t *r_length)
-{
- FILE *fp;
- struct stat st;
- char *buf;
- size_t buflen;
-
- fp = fopen (fname, "rb");
- if (!fp)
- {
- log_error ("can't open `%s': %s\n", fname, strerror (errno));
- return NULL;
- }
-
- if (fstat (fileno(fp), &st))
- {
- log_error ("can't stat `%s': %s\n", fname, strerror (errno));
- 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, strerror (errno));
- fclose (fp);
- xfree (buf);
- return NULL;
- }
- fclose (fp);
-
- *r_length = buflen;
- return buf;
-}
-
-
-static unsigned char *
-read_key (const char *fname)
-{
- char *buf;
- size_t buflen;
- unsigned char *key;
-
- buf = read_file (fname, &buflen);
- if (!buf)
- return NULL;
- key = make_canonical (fname, buf, buflen);
- xfree (buf);
- return key;
-}
-
-
-
-static void
-read_and_protect (const char *fname)
-{
- int rc;
- unsigned char *key;
- unsigned char *result;
- size_t resultlen;
-
- key = read_key (fname);
- if (!key)
- return;
-
- rc = agent_protect (key, get_passphrase (), &result, &resultlen);
- xfree (key);
- if (rc)
- {
- log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
- return;
- }
-
- if (opt_armor)
- {
- char *p = make_advanced (result, resultlen);
- xfree (result);
- if (!p)
- return;
- result = p;
- resultlen = strlen (p);
- }
-
- fwrite (result, resultlen, 1, stdout);
- xfree (result);
-}
-
-
-static void
-read_and_unprotect (const char *fname)
-{
- int rc;
- unsigned char *key;
- unsigned char *result;
- size_t resultlen;
-
- key = read_key (fname);
- if (!key)
- return;
-
- rc = agent_unprotect (key, get_passphrase (), &result, &resultlen);
- xfree (key);
- if (rc)
- {
- log_error ("unprotecting the key failed: %s\n", gpg_strerror (rc));
- return;
- }
-
- if (opt_armor)
- {
- char *p = make_advanced (result, resultlen);
- xfree (result);
- if (!p)
- return;
- result = p;
- resultlen = strlen (p);
- }
-
- fwrite (result, resultlen, 1, stdout);
- xfree (result);
-}
-
-
-
-static void
-read_and_shadow (const char *fname)
-{
- int rc;
- unsigned char *key;
- unsigned char *result;
- size_t resultlen;
-
- key = read_key (fname);
- if (!key)
- return;
-
- rc = agent_shadow_key (key, "(8:313233342:43)", &result);
- xfree (key);
- if (rc)
- {
- log_error ("shadowing the key failed: %s\n", gpg_strerror (rc));
- return;
- }
- resultlen = gcry_sexp_canon_len (result, 0, NULL,NULL);
- assert (resultlen);
-
- if (opt_armor)
- {
- char *p = make_advanced (result, resultlen);
- xfree (result);
- if (!p)
- return;
- result = p;
- resultlen = strlen (p);
- }
-
- fwrite (result, resultlen, 1, stdout);
- xfree (result);
-}
-
-static void
-show_shadow_info (const char *fname)
-{
- int rc;
- unsigned char *key;
- const unsigned char *info;
- size_t infolen;
-
- key = read_key (fname);
- if (!key)
- return;
-
- rc = agent_get_shadow_info (key, &info);
- xfree (key);
- if (rc)
- {
- log_error ("get_shadow_info failed: %s\n", gpg_strerror (rc));
- return;
- }
- infolen = gcry_sexp_canon_len (info, 0, NULL,NULL);
- assert (infolen);
-
- if (opt_armor)
- {
- char *p = make_advanced (info, infolen);
- if (!p)
- return;
- fwrite (p, strlen (p), 1, stdout);
- xfree (p);
- }
- else
- fwrite (info, infolen, 1, stdout);
-}
-
-
-static void
-show_file (const char *fname)
-{
- unsigned char *key;
- size_t keylen;
- char *p;
-
- key = read_key (fname);
- if (!key)
- return;
-
- keylen = gcry_sexp_canon_len (key, 0, NULL,NULL);
- assert (keylen);
-
- p = make_advanced (key, keylen);
- xfree (key);
- if (p)
- {
- fwrite (p, strlen (p), 1, stdout);
- xfree (p);
- }
-}
-
-static void
-show_keygrip (const char *fname)
-{
- unsigned char *key;
- gcry_sexp_t private;
- unsigned char grip[20];
- int i;
-
- key = read_key (fname);
- if (!key)
- return;
-
- if (gcry_sexp_new (&private, key, 0, 0))
- {
- log_error ("gcry_sexp_new failed\n");
- return;
- }
- xfree (key);
-
- if (!gcry_pk_get_keygrip (private, grip))
- {
- log_error ("can't calculate keygrip\n");
- return;
- }
- gcry_sexp_release (private);
-
- for (i=0; i < 20; i++)
- printf ("%02X", grip[i]);
- putchar ('\n');
-}
-
-
-static int
-rsa_key_check (struct rsa_secret_key_s *skey)
-{
- int err = 0;
- gcry_mpi_t t = gcry_mpi_snew (0);
- gcry_mpi_t t1 = gcry_mpi_snew (0);
- gcry_mpi_t t2 = gcry_mpi_snew (0);
- gcry_mpi_t phi = gcry_mpi_snew (0);
-
- /* check that n == p * q */
- gcry_mpi_mul (t, skey->p, skey->q);
- if (gcry_mpi_cmp( t, skey->n) )
- {
- log_error ("RSA oops: n != p * q\n");
- err++;
- }
-
- /* check that p is less than q */
- if (gcry_mpi_cmp (skey->p, skey->q) > 0)
- {
- gcry_mpi_t tmp;
-
- log_info ("swapping secret primes\n");
- tmp = gcry_mpi_copy (skey->p);
- gcry_mpi_set (skey->p, skey->q);
- gcry_mpi_set (skey->q, tmp);
- gcry_mpi_release (tmp);
- /* and must recompute u of course */
- gcry_mpi_invm (skey->u, skey->p, skey->q);
- }
-
- /* check that e divides neither p-1 nor q-1 */
- gcry_mpi_sub_ui (t, skey->p, 1 );
- gcry_mpi_div (NULL, t, t, skey->e, 0);
- if (!gcry_mpi_cmp_ui( t, 0) )
- {
- log_error ("RSA oops: e divides p-1\n");
- err++;
- }
- gcry_mpi_sub_ui (t, skey->q, 1);
- gcry_mpi_div (NULL, t, t, skey->e, 0);
- if (!gcry_mpi_cmp_ui( t, 0))
- {
- log_info ( "RSA oops: e divides q-1\n" );
- err++;
- }
-
- /* check that d is correct. */
- gcry_mpi_sub_ui (t1, skey->p, 1);
- gcry_mpi_sub_ui (t2, skey->q, 1);
- gcry_mpi_mul (phi, t1, t2);
- gcry_mpi_invm (t, skey->e, phi);
- if (gcry_mpi_cmp (t, skey->d))
- { /* no: try universal exponent. */
- gcry_mpi_gcd (t, t1, t2);
- gcry_mpi_div (t, NULL, phi, t, 0);
- gcry_mpi_invm (t, skey->e, t);
- if (gcry_mpi_cmp (t, skey->d))
- {
- log_error ("RSA oops: bad secret exponent\n");
- err++;
- }
- }
-
- /* check for correctness of u */
- gcry_mpi_invm (t, skey->p, skey->q);
- if (gcry_mpi_cmp (t, skey->u))
- {
- log_info ( "RSA oops: bad u parameter\n");
- err++;
- }
-
- if (err)
- log_info ("RSA secret key check failed\n");
-
- gcry_mpi_release (t);
- gcry_mpi_release (t1);
- gcry_mpi_release (t2);
- gcry_mpi_release (phi);
-
- return err? -1:0;
-}
-
-
-static void
-import_p12_file (const char *fname)
-{
- char *buf;
- unsigned char *result;
- size_t buflen, resultlen;
- int i;
- int rc;
- gcry_mpi_t *kparms;
- struct rsa_secret_key_s sk;
- gcry_sexp_t s_key;
- unsigned char *key;
- unsigned char grip[20];
-
- /* fixme: we should release some stuff on error */
-
- buf = read_file (fname, &buflen);
- if (!buf)
- return;
-
- kparms = p12_parse (buf, buflen, get_passphrase ());
- xfree (buf);
- if (!kparms)
- {
- log_error ("error parsing or decrypting the PKCS-1 file\n");
- return;
- }
- for (i=0; kparms[i]; i++)
- ;
- if (i != 8)
- {
- log_error ("invalid structure of private key\n");
- return;
- }
-
-
-/* print_mpi (" n", kparms[0]); */
-/* print_mpi (" e", kparms[1]); */
-/* print_mpi (" d", kparms[2]); */
-/* print_mpi (" p", kparms[3]); */
-/* print_mpi (" q", kparms[4]); */
-/* print_mpi ("dmp1", kparms[5]); */
-/* print_mpi ("dmq1", kparms[6]); */
-/* print_mpi (" u", kparms[7]); */
-
- sk.n = kparms[0];
- sk.e = kparms[1];
- sk.d = kparms[2];
- sk.q = kparms[3];
- sk.p = kparms[4];
- sk.u = kparms[7];
- if (rsa_key_check (&sk))
- return;
-/* print_mpi (" n", sk.n); */
-/* print_mpi (" e", sk.e); */
-/* print_mpi (" d", sk.d); */
-/* print_mpi (" p", sk.p); */
-/* print_mpi (" q", sk.q); */
-/* print_mpi (" u", sk.u); */
-
- /* Create an S-expresion from the parameters. */
- rc = gcry_sexp_build (&s_key, NULL,
- "(private-key(rsa(n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
- sk.n, sk.e, sk.d, sk.p, sk.q, sk.u, NULL);
- for (i=0; i < 8; i++)
- gcry_mpi_release (kparms[i]);
- gcry_free (kparms);
- if (rc)
- {
- log_error ("failed to created S-expression from key: %s\n",
- gpg_strerror (rc));
- return;
- }
-
- /* Compute the keygrip. */
- if (!gcry_pk_get_keygrip (s_key, grip))
- {
- log_error ("can't calculate keygrip\n");
- return;
- }
- log_info ("keygrip: ");
- for (i=0; i < 20; i++)
- log_printf ("%02X", grip[i]);
- log_printf ("\n");
-
- /* convert to canonical encoding */
- buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, NULL, 0);
- assert (buflen);
- key = gcry_xmalloc_secure (buflen);
- buflen = gcry_sexp_sprint (s_key, GCRYSEXP_FMT_CANON, key, buflen);
- assert (buflen);
- gcry_sexp_release (s_key);
-
-
- rc = agent_protect (key, get_passphrase (), &result, &resultlen);
- xfree (key);
- if (rc)
- {
- log_error ("protecting the key failed: %s\n", gpg_strerror (rc));
- return;
- }
-
- if (opt_armor)
- {
- char *p = make_advanced (result, resultlen);
- xfree (result);
- if (!p)
- return;
- result = p;
- resultlen = strlen (p);
- }
-
- if (opt_store)
- store_private_key (grip, result, resultlen, opt_force);
- else
- fwrite (result, resultlen, 1, stdout);
-
- xfree (result);
-}
-
-
-
-static gcry_mpi_t *
-sexp_to_kparms (gcry_sexp_t sexp)
-{
- gcry_sexp_t list, l2;
- const char *name;
- const char *s;
- size_t n;
- int i, idx;
- const char *elems;
- gcry_mpi_t *array;
-
- list = gcry_sexp_find_token (sexp, "private-key", 0 );
- if(!list)
- return NULL;
- 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;
-}
-
-
-
-
-static void
-export_p12_file (const char *fname)
-{
- gcry_mpi_t kparms[9], *kp;
- unsigned char *key;
- size_t keylen;
- gcry_sexp_t private;
- struct rsa_secret_key_s sk;
- int i;
-
- key = read_key (fname);
- if (!key)
- return;
-
- if (gcry_sexp_new (&private, key, 0, 0))
- {
- log_error ("gcry_sexp_new failed\n");
- return;
- }
- xfree (key);
-
- kp = sexp_to_kparms (private);
- gcry_sexp_release (private);
- if (!kp)
- {
- log_error ("error converting key parameters\n");
- return;
- }
- sk.n = kp[0];
- sk.e = kp[1];
- sk.d = kp[2];
- sk.p = kp[3];
- sk.q = kp[4];
- sk.u = kp[5];
- xfree (kp);
-
-
- kparms[0] = sk.n;
- kparms[1] = sk.e;
- kparms[2] = sk.d;
- kparms[3] = sk.q;
- kparms[4] = sk.p;
- kparms[5] = gcry_mpi_snew (0); /* compute d mod (p-1) */
- gcry_mpi_sub_ui (kparms[5], kparms[3], 1);
- gcry_mpi_mod (kparms[5], sk.d, kparms[5]);
- kparms[6] = gcry_mpi_snew (0); /* compute d mod (q-1) */
- gcry_mpi_sub_ui (kparms[6], kparms[4], 1);
- gcry_mpi_mod (kparms[6], sk.d, kparms[6]);
- kparms[7] = sk.u;
- kparms[8] = NULL;
-
- key = p12_build (kparms, get_passphrase (), &keylen);
- for (i=0; i < 8; i++)
- gcry_mpi_release (kparms[i]);
- if (!key)
- return;
-
- fwrite (key, keylen, 1, stdout);
- xfree (key);
-}
-
-
-int
-main (int argc, char **argv )
-{
- ARGPARSE_ARGS pargs;
- int cmd = 0;
-
- set_strusage (my_strusage);
- gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
- log_set_prefix ("gpg-protect-tool", 1);
- i18n_init ();
-
- 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_INIT_SECMEM, 16384, 0);
-
- 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 oArmor: opt_armor=1; break;
-
- case oProtect: cmd = oProtect; break;
- case oUnprotect: cmd = oUnprotect; break;
- case oShadow: cmd = oShadow; break;
- case oShowShadowInfo: cmd = oShowShadowInfo; break;
- case oShowKeygrip: cmd = oShowKeygrip; break;
- case oP12Import: cmd = oP12Import; break;
- case oP12Export: cmd = oP12Export; break;
-
- case oPassphrase: passphrase = pargs.r.ret_str; break;
- case oStore: opt_store = 1; break;
- case oForce: opt_force = 1; break;
-
- default : pargs.err = 2; break;
- }
- }
- if (log_get_errorcount(0))
- exit(2);
-
- if (argc != 1)
- usage (1);
-
- if (cmd == oProtect)
- read_and_protect (*argv);
- else if (cmd == oUnprotect)
- read_and_unprotect (*argv);
- else if (cmd == oShadow)
- read_and_shadow (*argv);
- else if (cmd == oShowShadowInfo)
- show_shadow_info (*argv);
- else if (cmd == oShowKeygrip)
- show_keygrip (*argv);
- else if (cmd == oP12Import)
- import_p12_file (*argv);
- else if (cmd == oP12Export)
- export_p12_file (*argv);
- else
- show_file (*argv);
-
- agent_exit (0);
- return 8; /*NOTREACHED*/
-}
-
-void
-agent_exit (int rc)
-{
- rc = rc? rc : log_get_errorcount(0)? 2 : 0;
- exit (rc);
-}
-
-
-/* Return the passphrase string and ask the agent if it has not been
- set from the command line. */
-static const char *
-get_passphrase (void)
-{
- char *pw;
- int err;
-
- if (passphrase)
- return passphrase;
-
- pw = simple_pwquery (NULL,NULL,
- _("Enter passphrase:"),
- _("Please enter the passphrase or the PIN\n"
- "needed to complete this operation."),
- &err);
- if (!pw)
- {
- if (err)
- log_error ("error while asking for the passphrase\n");
- else
- log_info ("cancelled\n");
- agent_exit (0);
- }
- passphrase = pw;
- return passphrase;
-}
-
-
-static int
-store_private_key (const unsigned char *grip,
- const void *buffer, size_t length, int force)
-{
- int i;
- const char *homedir;
- char *fname;
- FILE *fp;
- char hexgrip[40+4+1];
-
- for (i=0; i < 20; i++)
- sprintf (hexgrip+2*i, "%02X", grip[i]);
- strcpy (hexgrip+40, ".key");
-
- homedir = getenv("GNUPGHOME");
- if (!homedir || !*homedir)
- homedir = GNUPG_DEFAULT_HOMEDIR;
-
- fname = make_filename (homedir, GNUPG_PRIVATE_KEYS_DIR, hexgrip, NULL);
- if (force)
- fp = fopen (fname, "wb");
- else
- {
- if (!access (fname, F_OK))
- {
- log_error ("secret key file `%s' already exists\n", fname);
- xfree (fname);
- return -1;
- }
- fp = fopen (fname, "wbx"); /* FIXME: the x is a GNU extension - let
- configure check whether this actually
- works */
- }
-
- if (!fp)
- {
- log_error ("can't create `%s': %s\n", fname, strerror (errno));
- xfree (fname);
- return -1;
- }
-
- if (fwrite (buffer, length, 1, fp) != 1)
- {
- log_error ("error writing `%s': %s\n", fname, strerror (errno));
- fclose (fp);
- remove (fname);
- xfree (fname);
- return -1;
- }
- if ( fclose (fp) )
- {
- log_error ("error closing `%s': %s\n", fname, strerror (errno));
- remove (fname);
- xfree (fname);
- return -1;
- }
- log_info ("secret key stored as `%s'\n", fname);
-
- xfree (fname);
- return 0;
-}
diff --git a/agent/protect.c b/agent/protect.c
deleted file mode 100644
index e438d53b4..000000000
--- a/agent/protect.c
+++ /dev/null
@@ -1,971 +0,0 @@
-/* protect.c - Un/Protect a secret key
- * Copyright (C) 1998, 1999, 2000, 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
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "agent.h"
-
-#include "sexp-parse.h"
-
-#define PROT_CIPHER GCRY_CIPHER_AES
-#define PROT_CIPHER_STRING "aes"
-#define PROT_CIPHER_KEYLEN (128/8)
-
-
-/* A table containing the information needed to create a protected
- private key */
-static struct {
- const char *algo;
- const char *parmlist;
- int prot_from, prot_to;
-} protect_info[] = {
- { "rsa", "nedpqu", 2, 5 },
- { NULL }
-};
-
-
-static int
-hash_passphrase (const char *passphrase, int hashalgo,
- int s2kmode,
- const unsigned char *s2ksalt, unsigned long s2kcount,
- unsigned char *key, size_t keylen);
-
-
-
-/* Calculate the MIC for a private key S-Exp. SHA1HASH should pint to
- a 20 byte buffer. This function is suitable for any algorithms. */
-static int
-calculate_mic (const unsigned char *plainkey, unsigned char *sha1hash)
-{
- const unsigned char *hash_begin, *hash_end;
- const unsigned char *s;
- size_t n;
-
- s = plainkey;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "private-key"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- hash_begin = s;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n; /* skip over the algorithm name */
-
- while (*s == '(')
- {
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n;
- if ( *s != ')' )
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- }
- if (*s != ')')
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- hash_end = s;
-
- gcry_md_hash_buffer (GCRY_MD_SHA1, sha1hash,
- hash_begin, hash_end - hash_begin);
-
- return 0;
-}
-
-
-
-/* Encrypt the parameter block starting at PROTBEGIN with length
- PROTLEN using the utf8 encoded key PASSPHRASE and return the entire
- encrypted block in RESULT or ereturn with an error code. SHA1HASH
- is the 20 byte SHA-1 hash required for the integrity code.
-
- The parameter block is expected to be an incomplete S-Expression of
- the form (example in advanced format):
-
- (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#)
-
- the returned block is the S-Expression:
-
- (protected mode (parms) encrypted_octet_string)
-
-*/
-static int
-do_encryption (const char *protbegin, size_t protlen,
- const char *passphrase, const unsigned char *sha1hash,
- unsigned char **result, size_t *resultlen)
-{
- gcry_cipher_hd_t hd;
- const char *modestr = "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc";
- int blklen, enclen, outlen;
- char *iv = NULL;
- int rc;
- char *outbuf = NULL;
- char *p;
- int saltpos, ivpos, encpos;
-
- rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
- GCRY_CIPHER_SECURE);
- if (rc)
- return rc;
-
-
- /* We need to work on a copy of the data because this makes it
- easier to add the trailer and the padding and more important we
- have to prefix the text with 2 parenthesis, so we have to
- allocate enough space for:
-
- ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
-
- We always append a full block of random bytes as padding but
- encrypt only what is needed for a full blocksize */
- blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
- outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
- enclen = outlen/blklen * blklen;
- outbuf = gcry_malloc_secure (outlen);
- if (!outbuf)
- rc = out_of_core ();
- if (!rc)
- {
- /* allocate random bytes to be used as IV, padding and s2k salt*/
- iv = gcry_random_bytes (blklen*2+8, GCRY_WEAK_RANDOM);
- if (!iv)
- rc = gpg_error (GPG_ERR_ENOMEM);
- else
- rc = gcry_cipher_setiv (hd, iv, blklen);
- }
- if (!rc)
- {
- unsigned char *key;
- size_t keylen = PROT_CIPHER_KEYLEN;
-
- key = gcry_malloc_secure (keylen);
- if (!key)
- rc = out_of_core ();
- else
- {
- rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
- 3, iv+2*blklen, 96, key, keylen);
- if (!rc)
- rc = gcry_cipher_setkey (hd, key, keylen);
- xfree (key);
- }
- }
- if (!rc)
- {
- p = outbuf;
- *p++ = '(';
- *p++ = '(';
- memcpy (p, protbegin, protlen);
- p += protlen;
- memcpy (p, ")(4:hash4:sha120:", 17);
- p += 17;
- memcpy (p, sha1hash, 20);
- p += 20;
- *p++ = ')';
- *p++ = ')';
- memcpy (p, iv+blklen, blklen);
- p += blklen;
- assert ( p - outbuf == outlen);
- rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
- }
- gcry_cipher_close (hd);
- if (rc)
- {
- xfree (iv);
- xfree (outbuf);
- return rc;
- }
-
- /* Now allocate the buffer we want to return. This is
-
- (protected openpgp-s2k3-sha1-aes-cbc
- ((sha1 salt no_of_iterations) 16byte_iv)
- encrypted_octet_string)
-
- in canoncical format of course. We use asprintf and %n modifier
- and spaces as palceholders. */
- asprintf (&p,
- "(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
- (int)strlen (modestr), modestr,
- &saltpos,
- blklen, &ivpos, blklen, "",
- enclen, &encpos, enclen, "");
- if (p)
- { /* asprintf does not use our malloc system */
- char *psave = p;
- p = xtrymalloc (strlen (psave)+1);
- if (p)
- strcpy (p, psave);
- free (psave);
- }
- if (!p)
- {
- gpg_error_t tmperr = out_of_core ();
- xfree (iv);
- xfree (outbuf);
- return tmperr;
- }
- *resultlen = strlen (p);
- *result = p;
- memcpy (p+saltpos, iv+2*blklen, 8);
- memcpy (p+ivpos, iv, blklen);
- memcpy (p+encpos, outbuf, enclen);
- xfree (iv);
- xfree (outbuf);
- return 0;
-}
-
-
-
-/* Protect the key encoded in canonical format in plainkey. We assume
- a valid S-Exp here. */
-int
-agent_protect (const unsigned char *plainkey, const char *passphrase,
- unsigned char **result, size_t *resultlen)
-{
- int rc;
- const unsigned char *s;
- const unsigned char *hash_begin, *hash_end;
- const unsigned char *prot_begin, *prot_end, *real_end;
- size_t n;
- int c, infidx, i;
- unsigned char hashvalue[20];
- unsigned char *protected;
- size_t protectedlen;
- int depth = 0;
- unsigned char *p;
-
- s = plainkey;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth++;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "private-key"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- depth++;
- hash_begin = s;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
-
- for (infidx=0; protect_info[infidx].algo
- && !smatch (&s, n, protect_info[infidx].algo); infidx++)
- ;
- if (!protect_info[infidx].algo)
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
-
- prot_begin = prot_end = NULL;
- for (i=0; (c=protect_info[infidx].parmlist[i]); i++)
- {
- if (i == protect_info[infidx].prot_from)
- prot_begin = s;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth++;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (n != 1 || c != *s)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s +=n; /* skip value */
- if (*s != ')')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth--;
- if (i == protect_info[infidx].prot_to)
- prot_end = s;
- s++;
- }
- if (*s != ')' || !prot_begin || !prot_end )
- return gpg_error (GPG_ERR_INV_SEXP);
- depth--;
- hash_end = s;
- s++;
- /* skip to the end of the S-exp */
- assert (depth == 1);
- rc = sskip (&s, &depth);
- if (rc)
- return rc;
- assert (!depth);
- real_end = s-1;
-
- gcry_md_hash_buffer (GCRY_MD_SHA1, hashvalue,
- hash_begin, hash_end - hash_begin + 1);
-
- rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
- passphrase, hashvalue,
- &protected, &protectedlen);
- if (rc)
- return rc;
-
- /* Now create the protected version of the key. Note that the 10
- extra bytes are for for the inserted "protected-" string (the
- beginning of the plaintext reads: "((11:private-key(" ). */
- *resultlen = (10
- + (prot_begin-plainkey)
- + protectedlen
- + (real_end-prot_end));
- *result = p = xtrymalloc (*resultlen);
- if (!p)
- {
- gpg_error_t tmperr = out_of_core ();
- xfree (protected);
- return tmperr;
- }
- memcpy (p, "(21:protected-", 14);
- p += 14;
- memcpy (p, plainkey+4, prot_begin - plainkey - 4);
- p += prot_begin - plainkey - 4;
- memcpy (p, protected, protectedlen);
- p += protectedlen;
- memcpy (p, prot_end+1, real_end - prot_end);
- p += real_end - prot_end;
- assert ( p - *result == *resultlen);
- xfree (protected);
- return 0;
-}
-
-
-/* Do the actual decryption and check the return list for consistency. */
-static int
-do_decryption (const unsigned char *protected, size_t protectedlen,
- const char *passphrase,
- const unsigned char *s2ksalt, unsigned long s2kcount,
- const unsigned char *iv, size_t ivlen,
- unsigned char **result)
-{
- int rc = 0;
- int blklen;
- gcry_cipher_hd_t hd;
- unsigned char *outbuf;
- size_t reallen;
-
- blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
- if (protectedlen < 4 || (protectedlen%blklen))
- return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
-
- rc = gcry_cipher_open (&hd, PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
- GCRY_CIPHER_SECURE);
- if (rc)
- return rc;
-
- outbuf = gcry_malloc_secure (protectedlen);
- if (!outbuf)
- rc = out_of_core ();
- if (!rc)
- rc = gcry_cipher_setiv (hd, iv, ivlen);
- if (!rc)
- {
- unsigned char *key;
- size_t keylen = PROT_CIPHER_KEYLEN;
-
- key = gcry_malloc_secure (keylen);
- if (!key)
- rc = out_of_core ();
- else
- {
- rc = hash_passphrase (passphrase, GCRY_MD_SHA1,
- 3, s2ksalt, s2kcount, key, keylen);
- if (!rc)
- rc = gcry_cipher_setkey (hd, key, keylen);
- xfree (key);
- }
- }
- if (!rc)
- rc = gcry_cipher_decrypt (hd, outbuf, protectedlen,
- protected, protectedlen);
- gcry_cipher_close (hd);
- if (rc)
- {
- xfree (outbuf);
- return rc;
- }
- /* do a quick check first */
- if (*outbuf != '(' && outbuf[1] != '(')
- {
- xfree (outbuf);
- return gpg_error (GPG_ERR_BAD_PASSPHRASE);
- }
- /* check that we have a consistent S-Exp */
- reallen = gcry_sexp_canon_len (outbuf, protectedlen, NULL, NULL);
- if (!reallen || (reallen + blklen < protectedlen) )
- {
- xfree (outbuf);
- return gpg_error (GPG_ERR_BAD_PASSPHRASE);
- }
- *result = outbuf;
- return 0;
-}
-
-
-/* Merge the parameter list contained in CLEARTEXT with the original
- protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
- Return the new list in RESULT and the MIC value in the 20 byte
- buffer SHA1HASH. */
-static int
-merge_lists (const unsigned char *protectedkey,
- size_t replacepos,
- const unsigned char *cleartext,
- unsigned char *sha1hash, unsigned char **result)
-{
- size_t n, newlistlen;
- unsigned char *newlist, *p;
- const unsigned char *s;
- const unsigned char *startpos, *endpos;
- int i, rc;
-
- if (replacepos < 26)
- return gpg_error (GPG_ERR_BUG);
-
- /* Estimate the required size of the resulting list. We have a large
- safety margin of >20 bytes (MIC hash from CLEARTEXT and the
- removed "protected-" */
- newlistlen = gcry_sexp_canon_len (protectedkey, 0, NULL, NULL);
- if (!newlistlen)
- return gpg_error (GPG_ERR_BUG);
- n = gcry_sexp_canon_len (cleartext, 0, NULL, NULL);
- if (!n)
- return gpg_error (GPG_ERR_BUG);
- newlistlen += n;
- newlist = gcry_malloc_secure (newlistlen);
- if (!newlist)
- return out_of_core ();
-
- /* Copy the initial segment */
- strcpy (newlist, "(11:private-key");
- p = newlist + 15;
- memcpy (p, protectedkey+15+10, replacepos-15-10);
- p += replacepos-15-10;
-
- /* copy the cleartext */
- s = cleartext;
- if (*s != '(' && s[1] != '(')
- return gpg_error (GPG_ERR_BUG); /*we already checked this */
- s += 2;
- startpos = s;
- while ( *s == '(' )
- {
- s++;
- n = snext (&s);
- if (!n)
- goto invalid_sexp;
- s += n;
- n = snext (&s);
- if (!n)
- goto invalid_sexp;
- s += n;
- if ( *s != ')' )
- goto invalid_sexp;
- s++;
- }
- if ( *s != ')' )
- goto invalid_sexp;
- endpos = s;
- s++;
- /* short intermezzo: Get the MIC */
- if (*s != '(')
- goto invalid_sexp;
- s++;
- n = snext (&s);
- if (!smatch (&s, n, "hash"))
- goto invalid_sexp;
- n = snext (&s);
- if (!smatch (&s, n, "sha1"))
- goto invalid_sexp;
- n = snext (&s);
- if (n != 20)
- goto invalid_sexp;
- memcpy (sha1hash, s, 20);
- s += n;
- if (*s != ')')
- goto invalid_sexp;
- /* end intermezzo */
-
- /* append the parameter list */
- memcpy (p, startpos, endpos - startpos);
- p += endpos - startpos;
-
- /* skip overt the protected list element in the original list */
- s = protectedkey + replacepos;
- assert (*s == '(');
- s++;
- i = 1;
- rc = sskip (&s, &i);
- if (rc)
- goto failure;
- startpos = s;
- i = 2; /* we are inside this level */
- rc = sskip (&s, &i);
- if (rc)
- goto failure;
- assert (s[-1] == ')');
- endpos = s; /* one behind the end of the list */
-
- /* append the rest */
- memcpy (p, startpos, endpos - startpos);
- p += endpos - startpos;
-
- /* ready */
- *result = newlist;
- return 0;
-
- failure:
- xfree (newlist);
- return rc;
-
- invalid_sexp:
- xfree (newlist);
- return gpg_error (GPG_ERR_INV_SEXP);
-}
-
-
-
-/* Unprotect the key encoded in canonical format. We assume a valid
- S-Exp here. */
-int
-agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
- unsigned char **result, size_t *resultlen)
-{
- int rc;
- const unsigned char *s;
- size_t n;
- int infidx, i;
- unsigned char sha1hash[20], sha1hash2[20];
- const unsigned char *s2ksalt;
- unsigned long s2kcount;
- const unsigned char *iv;
- const unsigned char *prot_begin;
- unsigned char *cleartext;
- unsigned char *final;
-
- s = protectedkey;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "protected-private-key"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
-
- for (infidx=0; protect_info[infidx].algo
- && !smatch (&s, n, protect_info[infidx].algo); infidx++)
- ;
- if (!protect_info[infidx].algo)
- return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
-
- /* now find the list with the protected information. Here is an
- example for such a list:
- (protected openpgp-s2k3-sha1-aes-cbc
- ((sha1 <salt> <count>) <Initialization_Vector>)
- <encrypted_data>)
- */
- for (;;)
- {
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- prot_begin = s;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (smatch (&s, n, "protected"))
- break;
- s += n;
- i = 1;
- rc = sskip (&s, &i);
- if (rc)
- return rc;
- }
- /* found */
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc"))
- return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
- if (*s != '(' || s[1] != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- s += 2;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "sha1"))
- return gpg_error (GPG_ERR_UNSUPPORTED_PROTECTION);
- n = snext (&s);
- if (n != 8)
- return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
- s2ksalt = s;
- s += n;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
- /* We expect a list close as next, so we can simply use strtoul()
- here. We might want to check that we only have digits - but this
- is nothing we should worry about */
- if (s[n] != ')' )
- return gpg_error (GPG_ERR_INV_SEXP);
- s2kcount = strtoul (s, NULL, 10);
- if (!s2kcount)
- return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
- s += n;
- s++; /* skip list end */
-
- n = snext (&s);
- if (n != 16) /* Wrong blocksize for IV (we support ony aes-128) */
- return gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
- iv = s;
- s += n;
- if (*s != ')' )
- return gpg_error (GPG_ERR_INV_SEXP);
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
-
- rc = do_decryption (s, n,
- passphrase, s2ksalt, s2kcount,
- iv, 16,
- &cleartext);
- if (rc)
- return rc;
-
- rc = merge_lists (protectedkey, prot_begin-protectedkey, cleartext,
- sha1hash, &final);
- xfree (cleartext);
- if (rc)
- return rc;
-
- rc = calculate_mic (final, sha1hash2);
- if (!rc && memcmp (sha1hash, sha1hash2, 20))
- rc = gpg_error (GPG_ERR_CORRUPTED_PROTECTION);
- if (rc)
- {
- xfree (final);
- return rc;
- }
-
- *result = final;
- *resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
- return 0;
-}
-
-/* Check the type of the private key, this is one of the constants:
- PRIVATE_KEY_UNKNOWN if we can't figure out the type (this is the
- value 0), PRIVATE_KEY_CLEAR for an unprotected private key.
- PRIVATE_KEY_PROTECTED for an protected private key or
- PRIVATE_KEY_SHADOWED for a sub key where the secret parts are stored
- elsewhere. */
-int
-agent_private_key_type (const unsigned char *privatekey)
-{
- const unsigned char *s;
- size_t n;
-
- s = privatekey;
- if (*s != '(')
- return PRIVATE_KEY_UNKNOWN;
- s++;
- n = snext (&s);
- if (!n)
- return PRIVATE_KEY_UNKNOWN;
- if (smatch (&s, n, "protected-private-key"))
- return PRIVATE_KEY_PROTECTED;
- if (smatch (&s, n, "shadowed-private-key"))
- return PRIVATE_KEY_SHADOWED;
- if (smatch (&s, n, "private-key"))
- return PRIVATE_KEY_CLEAR;
- return PRIVATE_KEY_UNKNOWN;
-}
-
-
-
-/* Transform a passphrase into a suitable key of length KEYLEN and
- store this key in the caller provided buffer KEY. The caller must
- provide an HASHALGO, a valid S2KMODE (see rfc-2440) and depending on
- that mode an S2KSALT of 8 random bytes and an S2KCOUNT (a suitable
- value is 96).
-
- Returns an error code on failure. */
-static int
-hash_passphrase (const char *passphrase, int hashalgo,
- int s2kmode,
- const unsigned char *s2ksalt,
- unsigned long s2kcount,
- unsigned char *key, size_t keylen)
-{
- int rc;
- gcry_md_hd_t md;
- int pass, i;
- int used = 0;
- int pwlen = strlen (passphrase);
-
- if ( (s2kmode != 0 && s2kmode != 1 && s2kmode != 3)
- || !hashalgo || !keylen || !key || !passphrase)
- return gpg_error (GPG_ERR_INV_VALUE);
- if ((s2kmode == 1 ||s2kmode == 3) && !s2ksalt)
- return gpg_error (GPG_ERR_INV_VALUE);
-
- rc = gcry_md_open (&md, hashalgo, GCRY_MD_FLAG_SECURE);
- if (rc)
- return rc;
-
- for (pass=0; used < keylen; pass++)
- {
- if (pass)
- {
- gcry_md_reset (md);
- for (i=0; i < pass; i++) /* preset the hash context */
- gcry_md_putc (md, 0);
- }
-
- if (s2kmode == 1 || s2kmode == 3)
- {
- int len2 = pwlen + 8;
- unsigned long count = len2;
-
- if (s2kmode == 3)
- {
- count = (16ul + (s2kcount & 15)) << ((s2kcount >> 4) + 6);
- if (count < len2)
- count = len2;
- }
-
- while (count > len2)
- {
- gcry_md_write (md, s2ksalt, 8);
- gcry_md_write (md, passphrase, pwlen);
- count -= len2;
- }
- if (count < 8)
- gcry_md_write (md, s2ksalt, count);
- else
- {
- gcry_md_write (md, s2ksalt, 8);
- count -= 8;
- gcry_md_write (md, passphrase, count);
- }
- }
- else
- gcry_md_write (md, passphrase, pwlen);
-
- gcry_md_final (md);
- i = gcry_md_get_algo_dlen (hashalgo);
- if (i > keylen - used)
- i = keylen - used;
- memcpy (key+used, gcry_md_read (md, hashalgo), i);
- used += i;
- }
- gcry_md_close(md);
- return 0;
-}
-
-
-
-/* Create a shadow key from a public key. We use the shadow protocol
- "ti-v1" and insert the S-expressionn SHADOW_INFO. The resulting
- S-expression is returned in an allocated buffer RESULT will point
- to. The input parameters are expected to be valid canonilized
- S-expressions */
-int
-agent_shadow_key (const unsigned char *pubkey,
- const unsigned char *shadow_info,
- unsigned char **result)
-{
- const unsigned char *s;
- const unsigned char *point;
- size_t n;
- int depth = 0;
- unsigned char *p;
- size_t pubkey_len = gcry_sexp_canon_len (pubkey, 0, NULL,NULL);
- size_t shadow_info_len = gcry_sexp_canon_len (shadow_info, 0, NULL,NULL);
-
- if (!pubkey_len || !shadow_info_len)
- return gpg_error (GPG_ERR_INV_VALUE);
- s = pubkey;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth++;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "public-key"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- depth++;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n; /* skip over the algorithm name */
-
- while (*s != ')')
- {
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth++;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s +=n; /* skip value */
- if (*s != ')')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth--;
- s++;
- }
- point = s; /* insert right before the point */
- depth--;
- s++;
- assert (depth == 1);
-
- /* calculate required length by taking in account: the "shadowed-"
- prefix, the "shadowed", "t1-v1" as well as some parenthesis */
- n = 12 + pubkey_len + 1 + 3+8 + 2+5 + shadow_info_len + 1;
- *result = p = xtrymalloc (n);
- if (!p)
- return out_of_core ();
- p = stpcpy (p, "(20:shadowed-private-key");
- /* (10:public-key ...)*/
- memcpy (p, pubkey+14, point - (pubkey+14));
- p += point - (pubkey+14);
- p = stpcpy (p, "(8:shadowed5:t1-v1");
- memcpy (p, shadow_info, shadow_info_len);
- p += shadow_info_len;
- *p++ = ')';
- memcpy (p, point, pubkey_len - (point - pubkey));
- p += pubkey_len - (point - pubkey);
-
- return 0;
-}
-
-/* Parse a canonical encoded shadowed key and return a pointer to the
- inner list with the shadow_info */
-int
-agent_get_shadow_info (const unsigned char *shadowkey,
- unsigned char const **shadow_info)
-{
- const unsigned char *s;
- size_t n;
- int depth = 0;
-
- s = shadowkey;
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth++;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (!smatch (&s, n, "shadowed-private-key"))
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- if (*s != '(')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- depth++;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n; /* skip over the algorithm name */
-
- for (;;)
- {
- if (*s == ')')
- return gpg_error (GPG_ERR_UNKNOWN_SEXP);
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth++;
- s++;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (smatch (&s, n, "shadowed"))
- break;
- s += n;
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s +=n; /* skip value */
- if (*s != ')')
- return gpg_error (GPG_ERR_INV_SEXP);
- depth--;
- s++;
- }
- /* found the shadowed list, s points to the protocol */
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- if (smatch (&s, n, "t1-v1"))
- {
- if (*s != '(')
- return gpg_error (GPG_ERR_INV_SEXP);
- *shadow_info = s;
- }
- else
- return gpg_error (GPG_ERR_UNSUPPORTED_PROTOCOL);
- return 0;
-}
-
diff --git a/agent/query.c b/agent/query.c
deleted file mode 100644
index 4a051965d..000000000
--- a/agent/query.c
+++ /dev/null
@@ -1,473 +0,0 @@
-/* query.c - fork of the pinentry to query stuff from the user
- * 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
- */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#ifdef USE_GNU_PTH
-# include <pth.h>
-#endif
-
-#include "agent.h"
-#include "i18n.h"
-#include <assuan.h>
-
-#ifdef _POSIX_OPEN_MAX
-#define MAX_OPEN_FDS _POSIX_OPEN_MAX
-#else
-#define MAX_OPEN_FDS 20
-#endif
-
-static ASSUAN_CONTEXT entry_ctx = NULL;
-#ifdef USE_GNU_PTH
-static pth_mutex_t entry_lock = PTH_MUTEX_INIT;
-#endif
-
-/* data to be passed to our callbacks */
-struct entry_parm_s {
- int lines;
- size_t size;
- char *buffer;
-};
-
-
-
-
-/* Unlock the pinentry so that another thread can start one and
- disconnect that pinentry - we do this after the unlock so that a
- stalled pinentry does not block other threads. Fixme: We should
- have a timeout in Assuan for the disconnetc operation. */
-static int
-unlock_pinentry (int rc)
-{
- ASSUAN_CONTEXT ctx = entry_ctx;
-
-#ifdef USE_GNU_PTH
- if (!pth_mutex_release (&entry_lock))
- {
- log_error ("failed to release the entry lock\n");
- if (!rc)
- rc = gpg_error (GPG_ERR_INTERNAL);
- }
-#endif
- entry_ctx = NULL;
- assuan_disconnect (ctx);
- return rc;
-}
-
-/* Fork off the pin entry if this has not already been done. Note,
- that this function must always be used to aquire the lock for the
- pinentry - we will serialize _all_ pinentry calls.
- */
-static int
-start_pinentry (CTRL ctrl)
-{
- int rc;
- const char *pgmname;
- ASSUAN_CONTEXT ctx;
- const char *argv[5];
- int no_close_list[3];
- int i;
-
-#ifdef USE_GNU_PTH
- if (!pth_mutex_acquire (&entry_lock, 0, NULL))
- {
- log_error ("failed to acquire the entry lock\n");
- return gpg_error (GPG_ERR_INTERNAL);
- }
-#endif
-
- if (entry_ctx)
- return 0;
-
- if (opt.verbose)
- log_info ("starting a new PIN Entry\n");
-
- if (fflush (NULL))
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("error flushing pending output: %s\n", strerror (errno));
- return unlock_pinentry (tmperr);
- }
-
- if (!opt.pinentry_program || !*opt.pinentry_program)
- opt.pinentry_program = GNUPG_DEFAULT_PINENTRY;
- if ( !(pgmname = strrchr (opt.pinentry_program, '/')))
- pgmname = opt.pinentry_program;
- else
- pgmname++;
-
- argv[0] = pgmname;
- if (ctrl->display && !opt.keep_display)
- {
- argv[1] = "--display";
- argv[2] = ctrl->display;
- argv[3] = NULL;
- }
- else
- argv[1] = NULL;
-
- i=0;
- if (!opt.running_detached)
- {
- if (log_get_fd () != -1)
- no_close_list[i++] = log_get_fd ();
- no_close_list[i++] = fileno (stderr);
- }
- no_close_list[i] = -1;
-
- /* connect to the pinentry and perform initial handshaking */
- rc = assuan_pipe_connect (&ctx, opt.pinentry_program, (char**)argv,
- no_close_list);
- if (rc)
- {
- log_error ("can't connect to the PIN entry module: %s\n",
- assuan_strerror (rc));
- return unlock_pinentry (gpg_error (GPG_ERR_NO_PIN_ENTRY));
- }
- entry_ctx = ctx;
-
- if (DBG_ASSUAN)
- log_debug ("connection to PIN entry established\n");
-
- rc = assuan_transact (entry_ctx,
- opt.no_grab? "OPTION no-grab":"OPTION grab",
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- if (ctrl->ttyname)
- {
- char *optstr;
- if (asprintf (&optstr, "OPTION ttyname=%s", ctrl->ttyname) < 0 )
- return unlock_pinentry (out_of_core ());
- rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
- NULL);
- free (optstr);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- }
- if (ctrl->ttytype)
- {
- char *optstr;
- if (asprintf (&optstr, "OPTION ttytype=%s", ctrl->ttytype) < 0 )
- return unlock_pinentry (out_of_core ());
- rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
- NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- }
- if (ctrl->lc_ctype)
- {
- char *optstr;
- if (asprintf (&optstr, "OPTION lc-ctype=%s", ctrl->lc_ctype) < 0 )
- return unlock_pinentry (out_of_core ());
- rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
- NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- }
- if (ctrl->lc_messages)
- {
- char *optstr;
- if (asprintf (&optstr, "OPTION lc-messages=%s", ctrl->lc_messages) < 0 )
- return unlock_pinentry (out_of_core ());
- rc = assuan_transact (entry_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
- NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- }
- return 0;
-}
-
-
-static AssuanError
-getpin_cb (void *opaque, const void *buffer, size_t length)
-{
- struct entry_parm_s *parm = opaque;
-
- if (!buffer)
- return 0;
-
- /* we expect the pin to fit on one line */
- if (parm->lines || length >= parm->size)
- return ASSUAN_Too_Much_Data;
-
- /* fixme: we should make sure that the assuan buffer is allocated in
- secure memory or read the response byte by byte */
- memcpy (parm->buffer, buffer, length);
- parm->buffer[length] = 0;
- parm->lines++;
- return 0;
-}
-
-
-static int
-all_digitsp( const char *s)
-{
- for (; *s && *s >= '0' && *s <= '9'; s++)
- ;
- return !*s;
-}
-
-
-
-/* Call the Entry and ask for the PIN. We do check for a valid PIN
- number here and repeat it as long as we have invalid formed
- numbers. */
-int
-agent_askpin (CTRL ctrl,
- const char *desc_text, struct pin_entry_info_s *pininfo)
-{
- int rc;
- char line[ASSUAN_LINELENGTH];
- struct entry_parm_s parm;
- const char *errtext = NULL;
- int is_pin = 0;
-
- if (opt.batch)
- return 0; /* fixme: we should return BAD PIN */
-
- if (!pininfo || pininfo->max_length < 1)
- return gpg_error (GPG_ERR_INV_VALUE);
- if (!desc_text && pininfo->min_digits)
- desc_text = _("Please enter your PIN, so that the secret key "
- "can be unlocked for this session");
- else if (!desc_text)
- desc_text = _("Please enter your passphrase, so that the secret key "
- "can be unlocked for this session");
-
- is_pin = desc_text && strstr (desc_text, "PIN");
-
- rc = start_pinentry (ctrl);
- if (rc)
- return rc;
-
- snprintf (line, DIM(line)-1, "SETDESC %s", desc_text);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
-
- rc = assuan_transact (entry_ctx,
- is_pin? "SETPROMPT PIN:"
- : "SETPROMPT Passphrase:",
- NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
-
- for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
- {
- memset (&parm, 0, sizeof parm);
- parm.size = pininfo->max_length;
- parm.buffer = pininfo->pin;
-
- if (errtext)
- {
- /* fixme: should we show the try count? It must be translated */
- snprintf (line, DIM(line)-1, "SETERROR %s (try %d of %d)",
- errtext, pininfo->failed_tries+1, pininfo->max_tries);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- errtext = NULL;
- }
-
- rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
- NULL, NULL, NULL, NULL);
- if (rc == ASSUAN_Too_Much_Data)
- errtext = is_pin? _("PIN too long")
- : _("Passphrase too long");
- else if (rc)
- return unlock_pinentry (map_assuan_err (rc));
-
- if (!errtext && pininfo->min_digits)
- {
- /* do some basic checks on the entered PIN. */
- if (!all_digitsp (pininfo->pin))
- errtext = _("Invalid characters in PIN");
- else if (pininfo->max_digits
- && strlen (pininfo->pin) > pininfo->max_digits)
- errtext = _("PIN too long");
- else if (strlen (pininfo->pin) < pininfo->min_digits)
- errtext = _("PIN too short");
- }
-
- if (!errtext && pininfo->check_cb)
- {
- /* More checks by utilizing the optional callback. */
- pininfo->cb_errtext = NULL;
- rc = pininfo->check_cb (pininfo);
- if (rc == -1 && pininfo->cb_errtext)
- errtext = pininfo->cb_errtext;
- else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
- || gpg_err_code (rc) == GPG_ERR_BAD_PIN)
- errtext = (is_pin? _("Bad PIN")
- : _("Bad Passphrase"));
- else if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- }
-
- if (!errtext)
- return unlock_pinentry (0); /* okay, got a PIN or passphrase */
- }
-
- return unlock_pinentry (gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
- : GPG_ERR_BAD_PASSPHRASE));
-}
-
-
-
-/* Ask for the passphrase using the supplied arguments. The
- passphrase is returned in RETPASS as an hex encoded string to be
- freed by the caller */
-int
-agent_get_passphrase (CTRL ctrl,
- char **retpass, const char *desc, const char *prompt,
- const char *errtext)
-{
-
- int rc;
- char line[ASSUAN_LINELENGTH];
- struct entry_parm_s parm;
- unsigned char *p, *hexstring;
- int i;
-
- *retpass = NULL;
- if (opt.batch)
- return gpg_error (GPG_ERR_BAD_PASSPHRASE);
-
- rc = start_pinentry (ctrl);
- if (rc)
- return rc;
-
- if (!prompt)
- prompt = desc && strstr (desc, "PIN")? "PIN": _("Passphrase");
-
-
- if (desc)
- snprintf (line, DIM(line)-1, "SETDESC %s", desc);
- else
- snprintf (line, DIM(line)-1, "RESET");
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
-
- snprintf (line, DIM(line)-1, "SETPROMPT %s", prompt);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
-
- if (errtext)
- {
- snprintf (line, DIM(line)-1, "SETERROR %s", errtext);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- }
-
- memset (&parm, 0, sizeof parm);
- parm.size = ASSUAN_LINELENGTH/2 - 5;
- parm.buffer = gcry_malloc_secure (parm.size+10);
- if (!parm.buffer)
- return unlock_pinentry (out_of_core ());
-
- assuan_begin_confidential (entry_ctx);
- rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, NULL, NULL, NULL, NULL);
- if (rc)
- {
- xfree (parm.buffer);
- return unlock_pinentry (map_assuan_err (rc));
- }
-
- hexstring = gcry_malloc_secure (strlen (parm.buffer)*2+1);
- if (!hexstring)
- {
- gpg_error_t tmperr = out_of_core ();
- xfree (parm.buffer);
- return unlock_pinentry (tmperr);
- }
-
- for (i=0, p=parm.buffer; *p; p++, i += 2)
- sprintf (hexstring+i, "%02X", *p);
-
- xfree (parm.buffer);
- *retpass = hexstring;
- return unlock_pinentry (0);
-}
-
-
-
-/* Pop up the PIN-entry, display the text and the prompt and ask the
- user to confirm this. We return 0 for success, ie. the used
- confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
- other error. */
-int
-agent_get_confirmation (CTRL ctrl,
- const char *desc, const char *ok, const char *cancel)
-{
- int rc;
- char line[ASSUAN_LINELENGTH];
-
- rc = start_pinentry (ctrl);
- if (rc)
- return rc;
-
- if (desc)
- snprintf (line, DIM(line)-1, "SETDESC %s", desc);
- else
- snprintf (line, DIM(line)-1, "RESET");
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
-
- if (ok)
- {
- snprintf (line, DIM(line)-1, "SETOK %s", ok);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- }
- if (cancel)
- {
- snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel);
- line[DIM(line)-1] = 0;
- rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
- if (rc)
- return unlock_pinentry (map_assuan_err (rc));
- }
-
- rc = assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
- return unlock_pinentry (map_assuan_err (rc));
-}
-
-
-
diff --git a/agent/sexp-parse.h b/agent/sexp-parse.h
deleted file mode 100644
index 338321f48..000000000
--- a/agent/sexp-parse.h
+++ /dev/null
@@ -1,98 +0,0 @@
-/* sexp-parse.h - S-Exp helper 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
- */
-
-#ifndef SEXP_PARSE_H
-#define SEXP_PARSE_H
-
-#include "../common/util.h"
-
-/* Return the length of the next S-Exp part and update the pointer to
- the first data byte. 0 is return on error */
-static inline size_t
-snext (unsigned char const **buf)
-{
- const unsigned char *s;
- int n;
-
- s = *buf;
- for (n=0; *s && *s != ':' && digitp (s); s++)
- n = n*10 + atoi_1 (s);
- if (!n || *s != ':')
- return 0; /* we don't allow empty lengths */
- *buf = s+1;
- return n;
-}
-
-/* Skip over the S-Expression BUF points to and update BUF to point to
- the chacter right behind. DEPTH gives the initial number of open
- lists and may be passed as a positive number to skip over the
- remainder of an S-Expression if the current position is somewhere
- in an S-Expression. The function may return an error code if it
- encounters an impossible conditions */
-static inline int
-sskip (unsigned char const **buf, int *depth)
-{
- const unsigned char *s = *buf;
- size_t n;
- int d = *depth;
-
- while (d > 0)
- {
- if (*s == '(')
- {
- d++;
- s++;
- }
- else if (*s == ')')
- {
- d--;
- s++;
- }
- else
- {
- if (!d)
- return gpg_error (GPG_ERR_INV_SEXP);
- n = snext (&s);
- if (!n)
- return gpg_error (GPG_ERR_INV_SEXP);
- s += n;
- }
- }
- *buf = s;
- *depth = d;
- return 0;
-}
-
-
-/* Check whether the the string at the address BUF points to matches
- the token. Return true on match and update BUF to point behind the
- token. */
-static inline int
-smatch (unsigned char const **buf, size_t buflen, const char *token)
-{
- size_t toklen = strlen (token);
-
- if (buflen != toklen || memcmp (*buf, token, toklen))
- return 0;
- *buf += toklen;
- return 1;
-}
-
-#endif /*SEXP_PARSE_H*/
diff --git a/agent/simple-pwquery.c b/agent/simple-pwquery.c
deleted file mode 100644
index e870122cb..000000000
--- a/agent/simple-pwquery.c
+++ /dev/null
@@ -1,486 +0,0 @@
-/* simple-pwquery.c - A simple password query client for gpg-agent
- * 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
- */
-
-/* This module is intended as a standalone client implementation to
- gpg-agent's GET_PASSPHRASE command. In particular it does not use
- the Assuan library and can only cope with an already running
- gpg-agent. Some stuff is configurable in the header file. */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdlib.h>
-#include <stddef.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#endif
-
-#define SIMPLE_PWQUERY_IMPLEMENTATION 1
-#include "simple-pwquery.h"
-
-#if defined(SPWQ_USE_LOGGING) && !defined(HAVE_JNLIB_LOGGING)
-# undef SPWQ_USE_LOGGING
-#endif
-
-#ifndef _
-#define _(a) (a)
-#endif
-
-#if !defined (hexdigitp) && !defined (xtoi_2)
-#define digitp(p) (*(p) >= '0' && *(p) <= '9')
-#define hexdigitp(a) (digitp (a) \
- || (*(a) >= 'A' && *(a) <= 'F') \
- || (*(a) >= 'a' && *(a) <= 'f'))
-#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
- *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
-#define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
-#endif
-
-
-/* Write NBYTES of BUF to file descriptor FD. */
-static int
-writen (int fd, const void *buf, size_t nbytes)
-{
- size_t nleft = nbytes;
- int nwritten;
-
- while (nleft > 0)
- {
- nwritten = write( fd, buf, nleft );
- if (nwritten < 0)
- {
- if (errno == EINTR)
- nwritten = 0;
- else {
-#ifdef SPWQ_USE_LOGGING
- log_error ("write failed: %s\n", strerror (errno));
-#endif
- return SPWQ_IO_ERROR;
- }
- }
- nleft -= nwritten;
- buf = (const char*)buf + nwritten;
- }
-
- return 0;
-}
-
-
-/* Read an entire line and return number of bytes read. */
-static int
-readline (int fd, char *buf, size_t buflen)
-{
- size_t nleft = buflen;
- char *p;
- int nread = 0;
-
- while (nleft > 0)
- {
- int n = read (fd, buf, nleft);
- if (n < 0)
- {
- if (errno == EINTR)
- continue;
- return -(SPWQ_IO_ERROR);
- }
- else if (!n)
- {
- return -(SPWQ_PROTOCOL_ERROR); /* incomplete line */
- }
- p = buf;
- nleft -= n;
- buf += n;
- nread += n;
-
- for (; n && *p != '\n'; n--, p++)
- ;
- if (n)
- {
- break; /* at least one full line available - that's enough.
- This function is just a simple implementation, so
- it is okay to forget about pending bytes */
- }
- }
-
- return nread;
-}
-
-
-/* Send an option to the agent */
-static int
-agent_send_option (int fd, const char *name, const char *value)
-{
- char buf[200];
- int nread;
- char *line;
- int i;
-
- line = spwq_malloc (7 + strlen (name) + 1 + strlen (value) + 2);
- if (!line)
- return SPWQ_OUT_OF_CORE;
- strcpy (stpcpy (stpcpy (stpcpy (
- stpcpy (line, "OPTION "), name), "="), value), "\n");
- i = writen (fd, line, strlen (line));
- spwq_free (line);
- if (i)
- return i;
-
- /* get response */
- nread = readline (fd, buf, DIM(buf)-1);
- if (nread < 0)
- return -nread;
- if (nread < 3)
- return SPWQ_PROTOCOL_ERROR;
-
- if (buf[0] == 'O' && buf[1] == 'K' && (buf[2] == ' ' || buf[2] == '\n'))
- return 0; /* okay */
-
- return SPWQ_ERR_RESPONSE;
-}
-
-
-/* Send all available options to the agent. */
-static int
-agent_send_all_options (int fd)
-{
- char *dft_display = NULL;
- char *dft_ttyname = NULL;
- char *dft_ttytype = NULL;
- int rc = 0;
-
- dft_display = getenv ("DISPLAY");
- if (dft_display)
- {
- if ((rc = agent_send_option (fd, "display", dft_display)))
- return rc;
- }
-
- dft_ttyname = getenv ("GPG_TTY");
- if ((!dft_ttyname || !*dft_ttyname) && ttyname (0))
- dft_ttyname = ttyname (0);
- if (dft_ttyname && *dft_ttyname)
- {
- if ((rc=agent_send_option (fd, "ttyname", dft_ttyname)))
- return rc;
- }
-
- dft_ttytype = getenv ("TERM");
- if (dft_ttyname && dft_ttytype)
- {
- if ((rc = agent_send_option (fd, "ttytype", dft_ttytype)))
- return rc;
- }
-
-#if defined(HAVE_SETLOCALE)
- {
- char *old_lc = NULL;
- char *dft_lc = NULL;
-
-#if defined(LC_CTYPE)
- old_lc = setlocale (LC_CTYPE, NULL);
- if (old_lc)
- {
- char *p = spwq_malloc (strlen (old_lc)+1);
- if (!p)
- return SPWQ_OUT_OF_CORE;
- strcpy (p, old_lc);
- old_lc = p;
- }
- dft_lc = setlocale (LC_CTYPE, "");
- if (dft_ttyname && dft_lc)
- rc = agent_send_option (fd, "lc-ctype", dft_lc);
- if (old_lc)
- {
- setlocale (LC_CTYPE, old_lc);
- spwq_free (old_lc);
- }
- if (rc)
- return rc;
-#endif
-
-#if defined(LC_MESSAGES)
- old_lc = setlocale (LC_MESSAGES, NULL);
- if (old_lc)
- {
- char *p = spwq_malloc (strlen (old_lc)+1);
- if (!p)
- return SPWQ_OUT_OF_CORE;
- strcpy (p, old_lc);
- old_lc = p;
- }
- dft_lc = setlocale (LC_MESSAGES, "");
- if (dft_ttyname && dft_lc)
- rc = agent_send_option (fd, "lc-messages", dft_lc);
- if (old_lc)
- {
- setlocale (LC_MESSAGES, old_lc);
- spwq_free (old_lc);
- }
- if (rc)
- return rc;
-#endif
- }
-#endif /*HAVE_SETLOCALE*/
-
- return 0;
-}
-
-
-
-/* Try to open a connection to the agent, send all options and return
- the file descriptor for the connection. Return -1 in case of
- error. */
-static int
-agent_open (int *rfd)
-{
- int rc;
- int fd;
- char *infostr, *p;
- struct sockaddr_un client_addr;
- size_t len;
- int prot;
- char line[200];
- int nread;
-
- *rfd = -1;
- infostr = getenv ( "GPG_AGENT_INFO" );
- if ( !infostr )
- {
-#ifdef SPWQ_USE_LOGGING
- log_error (_("gpg-agent is not available in this session\n"));
-#endif
- return SPWQ_NO_AGENT;
- }
-
- if ( !(p = strchr ( infostr, ':')) || p == infostr
- || (p-infostr)+1 >= sizeof client_addr.sun_path )
- {
-#ifdef SPWQ_USE_LOGGING
- log_error ( _("malformed GPG_AGENT_INFO environment variable\n"));
-#endif
- return SPWQ_NO_AGENT;
- }
- *p++ = 0;
-
- while (*p && *p != ':')
- p++;
- prot = *p? atoi (p+1) : 0;
- if ( prot != 1)
- {
-#ifdef SPWQ_USE_LOGGING
- log_error (_("gpg-agent protocol version %d is not supported\n"),prot);
-#endif
- return SPWQ_PROTOCOL_ERROR;
- }
-
- if( (fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1 )
- {
-#ifdef SPWQ_USE_LOGGING
- log_error ("can't create socket: %s\n", strerror(errno) );
-#endif
- return SPWQ_SYS_ERROR;
- }
-
- memset (&client_addr, 0, sizeof client_addr);
- client_addr.sun_family = AF_UNIX;
- strcpy (client_addr.sun_path, infostr);
- len = (offsetof (struct sockaddr_un, sun_path)
- + strlen(client_addr.sun_path) + 1);
-
- if (connect (fd, (struct sockaddr*)&client_addr, len ) == -1)
- {
-#ifdef SPWQ_USE_LOGGING
- log_error ( _("can't connect to `%s': %s\n"), infostr, strerror (errno));
-#endif
- close (fd );
- return SPWQ_IO_ERROR;
- }
-
- nread = readline (fd, line, DIM(line));
- if (nread < 3 || !(line[0] == 'O' && line[1] == 'K'
- && (line[2] == '\n' || line[2] == ' ')) )
- {
-#ifdef SPWQ_USE_LOGGING
- log_error ( _("communication problem with gpg-agent\n"));
-#endif
- close (fd );
- return SPWQ_PROTOCOL_ERROR;
- }
-
- rc = agent_send_all_options (fd);
- if (rc)
- {
-#ifdef SPWQ_USE_LOGGING
- log_error (_("problem setting the gpg-agent options\n"));
-#endif
- close (fd);
- return rc;
- }
-
- *rfd = fd;
- return 0;
-}
-
-
-/* Copy text to BUFFER and escape as required. Return a poiinter to
- the end of the new buffer. NOte that BUFFER must be large enough
- to keep the entire text; allocataing it 3 times the size of TEXT
- is sufficient. */
-static char *
-copy_and_escape (char *buffer, const char *text)
-{
- int i;
- char *p = buffer;
-
- for (i=0; text[i]; i++)
- {
- if (text[i] < ' ' || text[i] == '+')
- {
- sprintf (p, "%%%02X", text[i]);
- p += 3;
- }
- else if (text[i] == ' ')
- *p++ = '+';
- else
- *p++ = text[i];
- }
- return p;
-}
-
-
-/* Ask the gpg-agent for a passphrase and present the user with a
- DESCRIPTION, a PROMPT and optiaonlly with a TRYAGAIN extra text.
- If a CACHEID is not NULL it is used to locate the passphrase in in
- the cache and store it under this ID. If ERRORCODE is not NULL it
- should point a variable receiving an errorcode; thsi errocode might
- be 0 if the user canceled the operation. The function returns NULL
- to indicate an error. */
-char *
-simple_pwquery (const char *cacheid,
- const char *tryagain,
- const char *prompt,
- const char *description,
- int *errorcode)
-{
- int fd = -1;
- int nread;
- char *result = NULL;
- char *pw = NULL;
- char *p;
- int rc, i;
-
- rc = agent_open (&fd);
- if (rc)
- goto leave;
-
- if (!cacheid)
- cacheid = "X";
- if (!tryagain)
- tryagain = "X";
- if (!prompt)
- prompt = "X";
- if (!description)
- description = "X";
-
- {
- char *line;
- /* We allocate 3 times the needed space so that there is enough
- space for escaping. */
- line = spwq_malloc (15
- + 3*strlen (cacheid) + 1
- + 3*strlen (tryagain) + 1
- + 3*strlen (prompt) + 1
- + 3*strlen (description) + 1
- + 2);
- if (!line)
- {
- rc = SPWQ_OUT_OF_CORE;
- goto leave;
- }
- strcpy (line, "GET_PASSPHRASE ");
- p = line+15;
- p = copy_and_escape (p, cacheid);
- *p++ = ' ';
- p = copy_and_escape (p, tryagain);
- *p++ = ' ';
- p = copy_and_escape (p, prompt);
- *p++ = ' ';
- p = copy_and_escape (p, description);
- *p++ = '\n';
- rc = writen (fd, line, p - line);
- spwq_free (line);
- if (rc)
- goto leave;
- }
-
- /* get response */
- pw = spwq_secure_malloc (500);
- nread = readline (fd, pw, 499);
- if (nread < 0)
- {
- rc = -nread;
- goto leave;
- }
- if (nread < 3)
- {
- rc = SPWQ_PROTOCOL_ERROR;
- goto leave;
- }
-
- if (pw[0] == 'O' && pw[1] == 'K' && pw[2] == ' ')
- { /* we got a passphrase - convert it back from hex */
- size_t pwlen = 0;
-
- for (i=3; i < nread && hexdigitp (pw+i); i+=2)
- pw[pwlen++] = xtoi_2 (pw+i);
- pw[pwlen] = 0; /* make a C String */
- result = pw;
- pw = NULL;
- }
- else if (nread > 7 && !memcmp (pw, "ERR 111", 7)
- && (pw[7] == ' ' || pw[7] == '\n') )
- {
-#ifdef SPWQ_USE_LOGGING
- log_info (_("canceled by user\n") );
-#endif
- *errorcode = 0; /* canceled */
- }
- else
- {
-#ifdef SPWQ_USE_LOGGING
- log_error (_("problem with the agent\n"));
-#endif
- rc = SPWQ_ERR_RESPONSE;
- }
-
- leave:
- if (errorcode)
- *errorcode = rc;
- if (fd != -1)
- close (fd);
- if (pw)
- spwq_free (pw);
- return result;
-}
diff --git a/agent/simple-pwquery.h b/agent/simple-pwquery.h
deleted file mode 100644
index a1b276ff6..000000000
--- a/agent/simple-pwquery.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/* simple-pwquery.c - A simple password query cleint for gpg-agent
- * 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
- */
-
-#ifndef SIMPLE_PWQUERY_H
-#define SIMPLE_PWQUERY_H
-
-#ifdef SIMPLE_PWQUERY_IMPLEMENTATION /* Begin configuration stuff. */
-
-/* Include whatever files you need. */
-#include <gcrypt.h>
-#include "../jnlib/logging.h"
-
-/* Try to write error message using the standard log mechanism. The
- current implementation requires that the HAVE_JNLIB_LOGGING is also
- defined. */
-#define SPWQ_USE_LOGGING 1
-
-/* Memory allocation functions used by the implementation. Note, that
- the returned value is expected to be freed with
- spwq_secure_free. */
-#define spwq_malloc(a) gcry_malloc (a)
-#define spwq_free(a) gcry_free (a)
-#define spwq_secure_malloc(a) gcry_malloc_secure (a)
-#define spwq_secure_free(a) gcry_free (a)
-
-
-#endif /*SIMPLE_PWQUERY_IMPLEMENTATION*/ /* End configuration stuff. */
-
-
-/* Ask the gpg-agent for a passphrase and present the user with a
- DESCRIPTION, a PROMPT and optiaonlly with a TRYAGAIN extra text.
- If a CACHEID is not NULL it is used to locate the passphrase in in
- the cache and store it under this ID. If ERRORCODE is not NULL it
- should point a variable receiving an errorcode; thsi errocode might
- be 0 if the user canceled the operation. The function returns NULL
- to indicate an error. */
-char *simple_pwquery (const char *cacheid,
- const char *tryagain,
- const char *prompt,
- const char *description,
- int *errorcode);
-
-
-#define SPWQ_OUT_OF_CORE 1
-#define SPWQ_IO_ERROR 2
-#define SPWQ_PROTOCOL_ERROR 3
-#define SPWQ_ERR_RESPONSE 4
-#define SPWQ_NO_AGENT 5
-#define SPWQ_SYS_ERROR 6
-#define SPWQ_GENERAL_ERROR 7
-
-#endif /*SIMPLE_PWQUERY_H*/
diff --git a/agent/trans.c b/agent/trans.c
deleted file mode 100644
index 7fa5e3d6b..000000000
--- a/agent/trans.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/* trans.c - translatable strings
- * Copyright (C) 2001 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
- */
-
-/* To avoid any problems with the gettext implementation (there used
- to be some vulnerabilities in the last years and the use of
- external files is a minor security problem in itself), we use our
- own simple translation stuff */
-
-#include <config.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "agent.h"
-
-const char *
-trans (const char *text)
-{
- return text;
-}
diff --git a/agent/trustlist.c b/agent/trustlist.c
deleted file mode 100644
index 8575aedb0..000000000
--- a/agent/trustlist.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/* trustlist.c - Maintain the list of trusted keys
- * 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 <ctype.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "agent.h"
-#include <assuan.h> /* fixme: need a way to avoid assuan calls here */
-
-static const char headerblurb[] =
-"# This is the list of trusted keys. Comments like this one and empty\n"
-"# lines are allowed but keep in mind that the entire file is integrity\n"
-"# protected by the use of a MAC, so changing the file does not make\n"
-"# much sense without the knowledge of the MAC key. Lines do have a\n"
-"# length limit but this is not serious limitation as the format of the\n"
-"# entries is fixed and checked by gpg-agent: A non-comment line starts\n"
-"# with optional white spaces, followed by exactly 40 hex character,\n"
-"# optioanlly followed by a flag character which my either be 'P', 'S'\n"
-"# or '*'. Additional data delimited with by a white space is ignored.\n"
-"\n";
-
-
-static FILE *trustfp;
-
-
-static int
-open_list (int append)
-{
- char *fname;
-
- fname = make_filename (opt.homedir, "trustlist.txt", NULL);
- trustfp = fopen (fname, append? "a+":"r");
- if (!trustfp && errno == ENOENT)
- {
- trustfp = fopen (fname, "wx");
- if (!trustfp)
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("can't create `%s': %s\n", fname, strerror (errno));
- xfree (fname);
- return tmperr;
- }
- fputs (headerblurb, trustfp);
- fclose (trustfp);
- trustfp = fopen (fname, append? "a+":"r");
- }
-
- if (!trustfp)
- {
- gpg_error_t tmperr = gpg_error (gpg_err_code_from_errno (errno));
- log_error ("can't open `%s': %s\n", fname, strerror (errno));
- xfree (fname);
- return tmperr;
- }
-
- /*FIXME: check the MAC */
-
- return 0;
-}
-
-
-
-/* Read the trustlist and return entry by entry. KEY must point to a
- buffer of at least 41 characters. KEYFLAG does return either 'P',
- 'S' or '*'.
-
- Reading a valid entry return 0, EOF returns -1 any other error
- returns the appropriate error code. */
-static int
-read_list (char *key, int *keyflag)
-{
- int rc;
- int c, i;
- char *p, line[256];
-
- if (!trustfp)
- {
- rc = open_list (0);
- if (rc)
- return rc;
- }
-
- do
- {
- if (!fgets (line, DIM(line)-1, trustfp) )
- {
- if (feof (trustfp))
- return -1;
- return gpg_error (gpg_err_code_from_errno (errno));
- }
-
- if (!*line || line[strlen(line)-1] != '\n')
- {
- /* eat until end of line */
- while ( (c=getc (trustfp)) != EOF && c != '\n')
- ;
- return gpg_error (*line? GPG_ERR_LINE_TOO_LONG
- : GPG_ERR_INCOMPLETE_LINE);
- }
-
- /* Allow for emty lines and spaces */
- for (p=line; spacep (p); p++)
- ;
- }
- while (!*p || *p == '\n' || *p == '#');
-
- for (i=0; hexdigitp (p+i) && i < 40; i++)
- key[i] = p[i] >= 'a'? (p[i] & 0xdf): p[i];
- key[i] = 0;
- if (i!=40 || !(spacep (p+i) || p[i] == '\n'))
- {
- log_error ("invalid formatted fingerprint in trustlist\n");
- return gpg_error (GPG_ERR_BAD_DATA);
- }
- assert (p[i]);
- if (p[i] == '\n')
- *keyflag = '*';
- else
- {
- i++;
- if ( p[i] == 'P' || p[i] == 'p')
- *keyflag = 'P';
- else if ( p[i] == 'S' || p[i] == 's')
- *keyflag = 'S';
- else if ( p[i] == '*')
- *keyflag = '*';
- else
- {
- log_error ("invalid keyflag in trustlist\n");
- return gpg_error (GPG_ERR_BAD_DATA);
- }
- i++;
- if ( !(spacep (p+i) || p[i] == '\n'))
- {
- log_error ("invalid keyflag in trustlist\n");
- return gpg_error (GPG_ERR_BAD_DATA);
- }
- }
-
- return 0;
-}
-
-/* check whether the given fpr is in our trustdb. We expect FPR to be
- an all uppercase hexstring of 40 characters. */
-int
-agent_istrusted (const char *fpr)
-{
- int rc;
- static char key[41];
- int keyflag;
-
- if (trustfp)
- rewind (trustfp);
- while (!(rc=read_list (key, &keyflag)))
- {
- if (!strcmp (key, fpr))
- return 0;
- }
- if (rc != -1)
- {
- /* error in the trustdb - close it to give the user a chance for
- correction */
- fclose (trustfp);
- trustfp = NULL;
- }
- return rc;
-}
-
-
-/* write all trust entries to FP */
-int
-agent_listtrusted (void *assuan_context)
-{
- int rc;
- static char key[51];
- int keyflag;
-
- if (trustfp)
- rewind (trustfp);
- while (!(rc=read_list (key, &keyflag)))
- {
- key[40] = ' ';
- key[41] = keyflag;
- key[42] = '\n';
- assuan_send_data (assuan_context, key, 43);
- assuan_send_data (assuan_context, NULL, 0); /* flush */
- }
- if (rc == -1)
- rc = 0;
- if (rc)
- {
- /* error in the trustdb - close it to give the user a chance for
- correction */
- fclose (trustfp);
- trustfp = NULL;
- }
- return rc;
-}
-
-
-/* Insert the given fpr into our trustdb. We expect FPR to be an all
- uppercase hexstring of 40 characters. FLAG is either 'P' or 'C'.
- This function does first check whether that key has alreay ben put
- into the trustdb and returns success in this case. Before a FPR
- actually gets inserted, the user is asked by means of the pin-entry
- whether this is actual wants he want to do.
-*/
-int
-agent_marktrusted (CTRL ctrl, const char *name, const char *fpr, int flag)
-{
- int rc;
- static char key[41];
- int keyflag;
- char *desc;
-
- if (trustfp)
- rewind (trustfp);
- while (!(rc=read_list (key, &keyflag)))
- {
- if (!strcmp (key, fpr))
- return 0;
- }
- fclose (trustfp);
- trustfp = NULL;
- if (rc != -1)
- return rc; /* error in the trustdb */
-
- /* insert a new one */
- if (asprintf (&desc,
- "Please verify that the certificate identified as:%%0A"
- " \"%s\"%%0A"
- "has the fingerprint:%%0A"
- " %s", name, fpr) < 0 )
- return out_of_core ();
- rc = agent_get_confirmation (ctrl, desc, "Correct", "No");
- free (desc);
- if (rc)
- return rc;
-
- if (asprintf (&desc,
- "Do you ultimately trust%%0A"
- " \"%s\"%%0A"
- "to correctly certify user certificates?",
- name) < 0 )
- return out_of_core ();
- rc = agent_get_confirmation (ctrl, desc, "Yes", "No");
- free (desc);
- if (rc)
- return rc;
-
- /* now check again to avoid duplicates. Also open in append mode now */
- rc = open_list (1);
- if (rc)
- return rc;
- rewind (trustfp);
- while (!(rc=read_list (key, &keyflag)))
- {
- if (!strcmp (key, fpr))
- return 0;
- }
- if (rc != -1)
- {
- fclose (trustfp);
- trustfp = NULL;
- return rc; /* error in the trustdb */
- }
- rc = 0;
-
- /* append the key */
- fflush (trustfp);
- fputs ("\n# ", trustfp);
- print_sanitized_string (trustfp, name, 0);
- fprintf (trustfp, "\n%s %c\n", fpr, flag);
- if (ferror (trustfp))
- rc = gpg_error (gpg_err_code_from_errno (errno));
-
- /* close because we are in append mode */
- if (fclose (trustfp))
- rc = gpg_error (gpg_err_code_from_errno (errno));
- trustfp = NULL;
- return rc;
-}