diff options
Diffstat (limited to '')
-rw-r--r-- | agent/ChangeLog | 565 | ||||
-rw-r--r-- | agent/Makefile.am | 62 | ||||
-rw-r--r-- | agent/agent.h | 226 | ||||
-rw-r--r-- | agent/cache.c | 314 | ||||
-rw-r--r-- | agent/call-scd.c | 661 | ||||
-rw-r--r-- | agent/command.c | 782 | ||||
-rw-r--r-- | agent/divert-scd.c | 319 | ||||
-rw-r--r-- | agent/findkey.c | 359 | ||||
-rw-r--r-- | agent/genkey.c | 240 | ||||
-rw-r--r-- | agent/gpg-agent.c | 1063 | ||||
-rw-r--r-- | agent/keyformat.txt | 163 | ||||
-rw-r--r-- | agent/learncard.c | 448 | ||||
-rw-r--r-- | agent/minip12.c | 1140 | ||||
-rw-r--r-- | agent/minip12.h | 33 | ||||
-rw-r--r-- | agent/pkdecrypt.c | 138 | ||||
-rw-r--r-- | agent/pksign.c | 185 | ||||
-rw-r--r-- | agent/protect-tool.c | 977 | ||||
-rw-r--r-- | agent/protect.c | 971 | ||||
-rw-r--r-- | agent/query.c | 473 | ||||
-rw-r--r-- | agent/sexp-parse.h | 98 | ||||
-rw-r--r-- | agent/simple-pwquery.c | 486 | ||||
-rw-r--r-- | agent/simple-pwquery.h | 69 | ||||
-rw-r--r-- | agent/trans.c | 42 | ||||
-rw-r--r-- | agent/trustlist.c | 306 |
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; -} |