mirror of
git://git.gnupg.org/gnupg.git
synced 2025-04-17 15:44:34 +02:00
This commit was manufactured by cvs2svn to create branch
'STABLE-BRANCH-1-2'.
This commit is contained in:
parent
811b782cba
commit
69161803cb
410
agent/ChangeLog
410
agent/ChangeLog
@ -1,410 +0,0 @@
|
||||
2002-09-09 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpg-agent.c (create_private_keys_directory)
|
||||
(create_directories): New.
|
||||
(main): Try to create a home directory.
|
||||
|
||||
2002-09-04 Neal H. Walfield <neal@g10code.de>
|
||||
|
||||
* gpg-agent.c (main): Use sigaction, not signal.
|
||||
|
||||
2002-09-03 Neal H. Walfield <neal@g10code.de>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* query.c (start_pinentry): Use GNUPG_DERAULT_PINENTRY.
|
||||
* call-scd.c (start_scd): Use GNUPG_DEFAULT_SCDAEMON.
|
||||
|
||||
2002-06-28 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* protect-tool.c (read_file): New.
|
||||
(read_key): Factored most code out to read_file.
|
||||
|
||||
2002-06-17 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* gpg-agent.c (main): New option --disable-pth.
|
||||
|
||||
2002-06-11 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* protect-tool.c: Add command --show-keygrip
|
||||
(show_keygrip): New.
|
||||
|
||||
2002-05-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* cache.c (housekeeping, agent_put_cache): Use our time() wrapper.
|
||||
|
||||
2002-04-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <marcus@g10code.de>
|
||||
|
||||
* 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 <marcus@g10code.de>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* protect-tool.c (show_file): New. Used as default action.
|
||||
|
||||
2002-03-28 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* learncard.c (kpinfo_cb): Remove the content restrictions from
|
||||
the keyID.
|
||||
|
||||
2002-03-06 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* call-scd.c (inq_needpin): New.
|
||||
(agent_card_pksign): Add getpin_cb args.
|
||||
(agent_card_pkdecrypt): New.
|
||||
|
||||
2002-03-04 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* cache.c (housekeeping): Fixed linking in the remove case.
|
||||
|
||||
2002-02-01 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* protect.c: New.
|
||||
(hash_passphrase): Based on the GnuPG 1.0.6 version.
|
||||
* protect-tool.c: New
|
||||
|
||||
2002-01-29 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* findkey.c (agent_key_available): New.
|
||||
* command.c (cmd_havekey): New.
|
||||
(register_commands): And register new command.
|
||||
|
||||
2002-01-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* trustlist.c: New.
|
||||
* command.c (cmd_istrusted, cmd_listtrusted, cmd_marktrusted): New.
|
||||
|
||||
2002-01-07 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* genkey.c: Store the secret part and return the public part.
|
||||
|
||||
2002-01-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* command.c (cmd_get_passphrase): New.
|
||||
(cmd_clear_passphrase): New.
|
||||
* query.c (agent_get_passphrase): New.
|
||||
|
||||
2002-01-02 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* keyformat.txt: New.
|
||||
|
||||
2001-12-19 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* query.c (start_pinentry): Add new argument to assuan_pipe_connect.
|
||||
|
||||
2001-12-18 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am: Use LIBGCRYPT macros
|
||||
|
||||
2001-12-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <marcus@g10code.de>
|
||||
|
||||
* query.c (LINELENGTH): Removed.
|
||||
(agent_askpin): Use ASSUAN_LINELENGTH, not LINELENGTH.
|
||||
|
||||
2001-11-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@gnupg.org>
|
||||
|
||||
* 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 <wk@openit.de>
|
||||
|
||||
* 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 <wk@openit.de>
|
||||
|
||||
* 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.
|
@ -1,62 +0,0 @@
|
||||
# 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
|
||||
|
||||
## 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) $(PTH_CFLAGS)
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
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 ../assuan/libassuan.a \
|
||||
../common/libcommon.a $(LIBGCRYPT_LIBS) $(PTH_LIBS)
|
||||
|
||||
gpg_protect_tool_SOURCES = \
|
||||
protect-tool.c \
|
||||
protect.c \
|
||||
minip12.c minip12.h \
|
||||
simple-pwquery.c simple-pwquery.h
|
||||
|
||||
gpg_protect_tool_LDADD = ../jnlib/libjnlib.a \
|
||||
../common/libcommon.a $(LIBGCRYPT_LIBS)
|
||||
|
||||
|
||||
|
||||
|
195
agent/agent.h
195
agent/agent.h
@ -1,195 +0,0 @@
|
||||
/* agent.h - Global definitions for the agent
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef AGENT_H
|
||||
#define AGENT_H
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include "../common/util.h"
|
||||
#include "../common/errors.h"
|
||||
|
||||
#define MAX_DIGEST_LEN 24
|
||||
|
||||
/* A large struct name "opt" to keep global flags */
|
||||
struct {
|
||||
unsigned int debug; /* debug flags (DBG_foo_VALUE) */
|
||||
int 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;
|
||||
char *display;
|
||||
char *ttyname;
|
||||
char *ttytype;
|
||||
char *lc_ctype;
|
||||
char *lc_messages;
|
||||
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;
|
||||
|
||||
} 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;
|
||||
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 */
|
||||
|
||||
/*-- 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 agent_key_from_file (const unsigned char *grip,
|
||||
unsigned char **shadow_info, int ignore_cache);
|
||||
int agent_key_available (const unsigned char *grip);
|
||||
|
||||
/*-- query.c --*/
|
||||
int agent_askpin (const char *desc_text, struct pin_entry_info_s *pininfo);
|
||||
int agent_get_passphrase (char **retpass,
|
||||
const char *desc, const char *prompt,
|
||||
const char *errtext);
|
||||
int agent_get_confirmation (const char *desc, const char *ok,
|
||||
const char *cancel);
|
||||
|
||||
/*-- cache.c --*/
|
||||
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);
|
||||
|
||||
/*-- 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 (const char *name, const char *fpr, int flag);
|
||||
|
||||
|
||||
/*-- divert-scd.c --*/
|
||||
int divert_pksign (const unsigned char *digest, size_t digestlen, int algo,
|
||||
const unsigned char *shadow_info, unsigned char **r_sig);
|
||||
int divert_pkdecrypt (const unsigned char *cipher,
|
||||
const unsigned char *shadow_info,
|
||||
char **r_buf, size_t *r_len);
|
||||
|
||||
/*-- 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);
|
||||
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);
|
||||
|
||||
|
||||
/*-- learncard.c --*/
|
||||
int agent_handle_learn (void *assuan_context);
|
||||
|
||||
|
||||
#endif /*AGENT_H*/
|
285
agent/cache.c
285
agent/cache.c
@ -1,285 +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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
592
agent/call-scd.c
592
agent/call-scd.c
@ -1,592 +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/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;
|
||||
};
|
||||
|
||||
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 = GNUPG_Internal_Error;
|
||||
}
|
||||
#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 GNUPG_Internal_Error;
|
||||
}
|
||||
#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))
|
||||
{
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
return unlock_scd (seterr (Write_Error));
|
||||
}
|
||||
|
||||
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 (seterr (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 == 8 && !memcmp (keyword, "SERIALNO", keywordlen))
|
||||
{
|
||||
log_debug ("learn_status_cb: serialno `%s'\n", line);
|
||||
}
|
||||
else
|
||||
log_debug ("learn_status_cb: ignoring `%.*s'\n", keywordlen, keyword);
|
||||
|
||||
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)
|
||||
{
|
||||
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;
|
||||
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 (seterr (General_Error));
|
||||
|
||||
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)
|
||||
{
|
||||
xfree (*r_buf);
|
||||
return unlock_scd (GNUPG_Out_Of_Core);
|
||||
}
|
||||
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 (seterr (General_Error));
|
||||
|
||||
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 (GNUPG_Out_Of_Core);
|
||||
|
||||
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 (GNUPG_Out_Of_Core);
|
||||
|
||||
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 (GNUPG_Out_Of_Core);
|
||||
|
||||
if (!gcry_sexp_canon_len (*r_buf, buflen, NULL, NULL))
|
||||
{
|
||||
xfree (*r_buf); *r_buf = NULL;
|
||||
return unlock_scd (GNUPG_Invalid_Value);
|
||||
}
|
||||
|
||||
return unlock_scd (0);
|
||||
}
|
||||
|
||||
|
||||
|
697
agent/command.c
697
agent/command.c
@ -1,697 +0,0 @@
|
||||
/* command.c - gpg-agent command handler
|
||||
* 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: 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 "agent.h"
|
||||
#include "../assuan/assuan.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)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* 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", gnupg_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", gnupg_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)
|
||||
{
|
||||
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 (p, fpr, flag);
|
||||
if (rc)
|
||||
log_error ("command marktrusted failed: %s\n", gnupg_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 n;
|
||||
char *p;
|
||||
unsigned char buf[20];
|
||||
|
||||
/* parse the hash value */
|
||||
for (p=line,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");
|
||||
n /= 2;
|
||||
if (n != 20)
|
||||
return set_error (Parameter_Error, "invalid length of keygrip");
|
||||
|
||||
for (p=line, n=0; n < 20; p += 2, n++)
|
||||
buf[n] = xtoi_2 (p);
|
||||
|
||||
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 n;
|
||||
char *p;
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
unsigned char *buf;
|
||||
|
||||
/* parse the hash value */
|
||||
for (p=line,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");
|
||||
n /= 2;
|
||||
if (n != 20)
|
||||
return set_error (Parameter_Error, "invalid length of keygrip");
|
||||
|
||||
buf = ctrl->keygrip;
|
||||
for (p=line, n=0; n < 20; p += 2, n++)
|
||||
buf[n] = xtoi_2 (p);
|
||||
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 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 */
|
||||
for (p=line,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");
|
||||
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", gnupg_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", gnupg_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", gnupg_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)
|
||||
{
|
||||
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 (&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", gnupg_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", gnupg_strerror (rc));
|
||||
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);
|
||||
|
||||
/* FIXME: We should not change opt. here. It is not a problem right
|
||||
now but as soon as we are allowing concurrent connections we mess
|
||||
things up */
|
||||
if (!strcmp (key, "display"))
|
||||
{
|
||||
if (opt.display)
|
||||
free (opt.display);
|
||||
opt.display = strdup (value);
|
||||
if (!opt.display)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
}
|
||||
else if (!strcmp (key, "ttyname"))
|
||||
{
|
||||
if (opt.ttyname)
|
||||
free (opt.ttyname);
|
||||
opt.ttyname = strdup (value);
|
||||
if (!opt.ttyname)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
}
|
||||
else if (!strcmp (key, "ttytype"))
|
||||
{
|
||||
if (opt.ttytype)
|
||||
free (opt.ttytype);
|
||||
opt.ttytype = strdup (value);
|
||||
if (!opt.ttytype)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
}
|
||||
else if (!strcmp (key, "lc-ctype"))
|
||||
{
|
||||
if (opt.lc_ctype)
|
||||
free (opt.lc_ctype);
|
||||
opt.lc_ctype = strdup (value);
|
||||
if (!opt.lc_ctype)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
}
|
||||
else if (!strcmp (key, "lc-messages"))
|
||||
{
|
||||
if (opt.lc_messages)
|
||||
free (opt.lc_messages);
|
||||
opt.lc_messages = strdup (value);
|
||||
if (!opt.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 cmd_id;
|
||||
int (*handler)(ASSUAN_CONTEXT, char *line);
|
||||
} table[] = {
|
||||
{ "ISTRUSTED", 0, cmd_istrusted },
|
||||
{ "HAVEKEY", 0, cmd_havekey },
|
||||
{ "SIGKEY", 0, cmd_sigkey },
|
||||
{ "SETKEY", 0, cmd_sigkey },
|
||||
{ "SETHASH", 0, cmd_sethash },
|
||||
{ "PKSIGN", 0, cmd_pksign },
|
||||
{ "PKDECRYPT", 0, cmd_pkdecrypt },
|
||||
{ "GENKEY", 0, cmd_genkey },
|
||||
{ "GET_PASSPHRASE",0, cmd_get_passphrase },
|
||||
{ "CLEAR_PASSPHRASE",0, cmd_clear_passphrase },
|
||||
{ "LISTTRUSTED", 0, cmd_listtrusted },
|
||||
{ "MARKTRUSTED", 0, cmd_marktrusted },
|
||||
{ "LEARN", 0, cmd_learn },
|
||||
{ "", ASSUAN_CMD_INPUT, NULL },
|
||||
{ "", ASSUAN_CMD_OUTPUT, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
int i, j, rc;
|
||||
|
||||
for (i=j=0; table[i].name; i++)
|
||||
{
|
||||
rc = assuan_register_command (ctx,
|
||||
table[i].cmd_id? table[i].cmd_id
|
||||
: (ASSUAN_CMD_USER + j++),
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -1,305 +0,0 @@
|
||||
/* divert-scd.c - divert operations to the scdaemon
|
||||
* 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 "sexp-parse.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
static int
|
||||
ask_for_card (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 GNUPG_Invalid_Sexp;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
want_sn = xtrymalloc (n*2+1);
|
||||
if (!want_sn)
|
||||
return GNUPG_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 GNUPG_Invalid_Sexp;
|
||||
want_kid = xtrymalloc (n+1);
|
||||
if (!want_kid)
|
||||
{
|
||||
xfree (want_sn);
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
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 (rc == GNUPG_Card_Not_Present)
|
||||
{
|
||||
log_debug ("no card present\n");
|
||||
rc = 0;
|
||||
no_card = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error ("error accesing card: %s\n", gnupg_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 = GNUPG_Out_Of_Core;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = agent_get_confirmation (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 GNUPG_Internal_Error;
|
||||
}
|
||||
|
||||
frame = xtrymalloc (asnlen + digestlen);
|
||||
if (!frame)
|
||||
return GNUPG_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;
|
||||
|
||||
assert (!opaque);
|
||||
|
||||
if (maxbuf < 2)
|
||||
return GNUPG_Invalid_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 (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 (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 (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, NULL,
|
||||
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 (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 GNUPG_Invalid_Sexp;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "enc-val"))
|
||||
return GNUPG_Unknown_Sexp;
|
||||
if (*s != '(')
|
||||
return GNUPG_Unknown_Sexp;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "rsa"))
|
||||
return GNUPG_Unsupported_Algorithm;
|
||||
if (*s != '(')
|
||||
return GNUPG_Unknown_Sexp;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "a"))
|
||||
return GNUPG_Unknown_Sexp;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Unknown_Sexp;
|
||||
ciphertext = s;
|
||||
ciphertextlen = n;
|
||||
|
||||
rc = ask_for_card (shadow_info, &kid);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = agent_card_pkdecrypt (kid, getpin_cb, NULL,
|
||||
ciphertext, ciphertextlen,
|
||||
&plaintext, &plaintextlen);
|
||||
if (!rc)
|
||||
{
|
||||
*r_buf = plaintext;
|
||||
*r_len = plaintextlen;
|
||||
}
|
||||
xfree (kid);
|
||||
return rc;
|
||||
}
|
350
agent/findkey.c
350
agent/findkey.c
@ -1,350 +0,0 @@
|
||||
/* findkey.c - locate the secret key
|
||||
* Copyright (C) 2001,02 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 seterr (General_Error);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
close (fd);
|
||||
}
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
log_error ("can't create `%s': %s\n", fname, strerror (errno));
|
||||
xfree (fname);
|
||||
return seterr (File_Create_Error);
|
||||
}
|
||||
|
||||
if (fwrite (buffer, length, 1, fp) != 1)
|
||||
{
|
||||
log_error ("error writing `%s': %s\n", fname, strerror (errno));
|
||||
fclose (fp);
|
||||
remove (fname);
|
||||
xfree (fname);
|
||||
return seterr (File_Create_Error);
|
||||
}
|
||||
if ( fclose (fp) )
|
||||
{
|
||||
log_error ("error closing `%s': %s\n", fname, strerror (errno));
|
||||
remove (fname);
|
||||
xfree (fname);
|
||||
return seterr (File_Create_Error);
|
||||
}
|
||||
|
||||
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
|
||||
cahing mechanism. */
|
||||
static int
|
||||
unprotect (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 (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
|
||||
agent_key_from_file (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 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, gcry_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 (&buf, grip, ignore_cache);
|
||||
if (rc)
|
||||
log_error ("failed to unprotect the secret key: %s\n",
|
||||
gnupg_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 = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
memcpy (*shadow_info, s, n);
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
if (rc)
|
||||
log_error ("get_shadow_info failed: %s\n", gnupg_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 = GNUPG_Bad_Secret_Key;
|
||||
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, gcry_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;
|
||||
}
|
||||
|
||||
|
||||
|
200
agent/genkey.c
200
agent/genkey.c
@ -1,200 +0,0 @@
|
||||
/* pksign.c - Generate a keypair
|
||||
* 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 "agent.h"
|
||||
#include "i18n.h"
|
||||
|
||||
static int
|
||||
store_key (GCRY_SEXP private, const char *passphrase)
|
||||
{
|
||||
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 seterr (General_Error);
|
||||
}
|
||||
|
||||
len = gcry_sexp_sprint (private, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||
assert (len);
|
||||
buf = gcry_malloc_secure (len);
|
||||
if (!buf)
|
||||
return seterr (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, 0);
|
||||
xfree (buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Callback function to compare the first entered PIN with the one
|
||||
currently beeing 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 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", gcry_strerror (rc));
|
||||
return seterr (Invalid_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 (text1, pi);
|
||||
if (!rc)
|
||||
rc = agent_askpin (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", gcry_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 seterr (Invalid_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 seterr (Invalid_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);
|
||||
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 = xmalloc (len);
|
||||
if (!buf)
|
||||
{
|
||||
gcry_sexp_release (s_private);
|
||||
gcry_sexp_release (s_public);
|
||||
return seterr (Out_Of_Core);
|
||||
}
|
||||
len = gcry_sexp_sprint (s_public, GCRYSEXP_FMT_CANON, buf, len);
|
||||
assert (len);
|
||||
if (fwrite (buf, len, 1, outfp) != 1)
|
||||
{
|
||||
log_error ("error writing public key: %s\n", strerror (errno));
|
||||
gcry_sexp_release (s_private);
|
||||
gcry_sexp_release (s_public);
|
||||
xfree (buf);
|
||||
return seterr (File_Create_Error);
|
||||
}
|
||||
gcry_sexp_release (s_public);
|
||||
xfree (buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,908 +0,0 @@
|
||||
/* gpg-agent.c - The GnuPG Agent
|
||||
* Copyright (C) 2000, 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 <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
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#define JNLIB_NEED_LOG_LOGV
|
||||
#include "agent.h"
|
||||
#include "../assuan/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,
|
||||
|
||||
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"},
|
||||
|
||||
{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];
|
||||
|
||||
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 );
|
||||
}
|
||||
|
||||
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 ();
|
||||
|
||||
/* 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);
|
||||
#ifdef USE_GNU_PTH
|
||||
assuan_set_io_func (pth_read, pth_write);
|
||||
#endif
|
||||
|
||||
gcry_set_log_handler (my_gcry_logger, NULL);
|
||||
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
|
||||
|
||||
may_coredump = disable_core_dumps ();
|
||||
|
||||
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;
|
||||
opt.def_cache_ttl = 10*60; /* default to 10 minutes */
|
||||
|
||||
|
||||
/* 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) )
|
||||
{
|
||||
switch (pargs.r_opt)
|
||||
{
|
||||
case oQuiet: opt.quiet = 1; break;
|
||||
case oVerbose: opt.verbose++; break;
|
||||
case oBatch: opt.batch=1; break;
|
||||
|
||||
case oDebug: opt.debug |= pargs.r.ret_ulong; break;
|
||||
case oDebugAll: opt.debug = ~0; break;
|
||||
case 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 oNoGrab: opt.no_grab = 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 oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break;
|
||||
case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break;
|
||||
case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break;
|
||||
case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break;
|
||||
case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break;
|
||||
case oLCmessages: opt.lc_messages = xstrdup (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 : pargs.err = configfp? 1:2; break;
|
||||
}
|
||||
}
|
||||
if (configfp)
|
||||
{
|
||||
fclose( configfp );
|
||||
configfp = NULL;
|
||||
xfree(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");
|
||||
}
|
||||
|
||||
/* now start with logging to a file if this is desired */
|
||||
if (logfile)
|
||||
{
|
||||
log_set_file (logfile);
|
||||
log_set_prefix (NULL, 1|2|4);
|
||||
}
|
||||
|
||||
|
||||
if (pipe_server)
|
||||
{ /* this is the simple pipe based server */
|
||||
start_command_handler (-1, -1);
|
||||
}
|
||||
else if (!is_daemon)
|
||||
{
|
||||
log_info (_("please use the option `--daemon'"
|
||||
" to run the program in the background\n"));
|
||||
}
|
||||
else
|
||||
{ /* regular server mode */
|
||||
int fd;
|
||||
pid_t pid;
|
||||
int len;
|
||||
struct sockaddr_un serv_addr;
|
||||
char *p;
|
||||
|
||||
*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;
|
||||
|
||||
if (!pth_init ())
|
||||
{
|
||||
log_error ("failed to initialize the Pth library\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
reread_configuration (void)
|
||||
{
|
||||
/* FIXME: Move parts of the option parsing to here. */
|
||||
}
|
||||
|
||||
|
||||
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\n");
|
||||
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)
|
||||
{
|
||||
if (pth_event_occurred (ev))
|
||||
{
|
||||
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*/
|
@ -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.
|
@ -1,380 +0,0 @@
|
||||
/* learncard.c - Handle the LEARN command
|
||||
* 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/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;
|
||||
};
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* This callback is used by agent_card_leanr 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 = GNUPG_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 = GNUPG_Invalid_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 = GNUPG_Invalid_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_leanr 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 = GNUPG_Invalid_Response;
|
||||
return;
|
||||
}
|
||||
*pend = 0; /* ignore trailing stuff */
|
||||
|
||||
item = xtrycalloc (1, sizeof *item + strlen (p));
|
||||
if (!item)
|
||||
{
|
||||
parm->error = GNUPG_Out_Of_Core;
|
||||
return;
|
||||
}
|
||||
item->type = type;
|
||||
strcpy (item->id, p);
|
||||
/* store it */
|
||||
item->next = parm->info;
|
||||
parm->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",
|
||||
gnupg_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;
|
||||
char *serialno = NULL;
|
||||
KEYPAIR_INFO item;
|
||||
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);
|
||||
|
||||
/* Check whether a card is present and get the serial number */
|
||||
rc = agent_card_serialno (&serialno);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
/* now gather all the availabe info */
|
||||
rc = agent_card_learn (kpinfo_cb, &parm, certinfo_cb, &cparm);
|
||||
if (!rc && (parm.error || cparm.error))
|
||||
rc = parm.error? parm.error : cparm.error;
|
||||
if (rc)
|
||||
{
|
||||
log_debug ("agent_card_learn failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
log_info ("card has S/N: %s\n", serialno);
|
||||
|
||||
/* 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", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
{
|
||||
unsigned char *shadow_info = make_shadow_info (serialno, item->id);
|
||||
if (!shadow_info)
|
||||
{
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
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", gnupg_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", gnupg_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);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
1146
agent/minip12.c
1146
agent/minip12.c
File diff suppressed because it is too large
Load Diff
@ -1,32 +0,0 @@
|
||||
/* minip12.h - Global definitions for the minimal pkcs-12 implementation.
|
||||
* 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 MINIP12_H
|
||||
#define MINIP12_H
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
GcryMPI *p12_parse (const unsigned char *buffer, size_t length,
|
||||
const char *pw);
|
||||
|
||||
unsigned char *p12_build (GcryMPI *kparms, const char *pw, size_t *r_length);
|
||||
|
||||
|
||||
#endif /*MINIP12_H*/
|
@ -1,138 +0,0 @@
|
||||
/* pkdecrypt.c - public key decryption (well, acually using a secret key)
|
||||
* 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
|
||||
*/
|
||||
|
||||
#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 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 = seterr (No_Secret_Key);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = gcry_sexp_sscan (&s_cipher, NULL, ciphertext, ciphertextlen);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to convert ciphertext: %s\n", gcry_strerror (rc));
|
||||
rc = seterr (Invalid_Data);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
{
|
||||
log_printhex ("keygrip:", ctrl->keygrip, 20);
|
||||
log_printhex ("cipher: ", ciphertext, ciphertextlen);
|
||||
}
|
||||
s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info, 0);
|
||||
if (!s_skey && !shadow_info)
|
||||
{
|
||||
log_error ("failed to read the secret key\n");
|
||||
rc = seterr (No_Secret_Key);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!s_skey)
|
||||
{ /* divert operation to the smartcard */
|
||||
|
||||
if (!gcry_sexp_canon_len (ciphertext, ciphertextlen, NULL, NULL))
|
||||
{
|
||||
rc = GNUPG_Invalid_Sexp;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = divert_pkdecrypt (ciphertext, shadow_info, &buf, &len );
|
||||
if (rc)
|
||||
{
|
||||
log_error ("smartcard decryption failed: %s\n", gnupg_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", gcry_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;
|
||||
}
|
||||
|
||||
|
183
agent/pksign.c
183
agent/pksign.c
@ -1,183 +0,0 @@
|
||||
/* pksign.c - public key signing (well, acually using a secret key)
|
||||
* 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
|
||||
*/
|
||||
|
||||
#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 *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 GNUPG_Internal_Error;
|
||||
}
|
||||
|
||||
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 GNUPG_Internal_Error;
|
||||
}
|
||||
|
||||
/* 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 GNUPG_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, &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 s_skey = NULL, s_hash = NULL, s_sig = NULL;
|
||||
GCRY_MPI frame = NULL;
|
||||
unsigned char *shadow_info = NULL;
|
||||
int rc;
|
||||
char *buf = NULL;
|
||||
size_t len;
|
||||
|
||||
if (!ctrl->have_keygrip)
|
||||
return seterr (No_Secret_Key);
|
||||
|
||||
s_skey = agent_key_from_file (ctrl->keygrip, &shadow_info, ignore_cache);
|
||||
if (!s_skey && !shadow_info)
|
||||
{
|
||||
log_error ("failed to read the secret key\n");
|
||||
rc = seterr (No_Secret_Key);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!s_skey)
|
||||
{ /* divert operation to the smartcard */
|
||||
unsigned char *sigbuf;
|
||||
|
||||
rc = divert_pksign (ctrl->digest.value,
|
||||
ctrl->digest.valuelen,
|
||||
ctrl->digest.algo,
|
||||
shadow_info, &sigbuf);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("smartcard signing failed: %s\n", gnupg_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", gcry_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;
|
||||
}
|
||||
|
||||
|
@ -1,977 +0,0 @@
|
||||
/* protect-tool.c - A tool to test the secret key protection
|
||||
* 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 <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gcrypt.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
|
||||
{
|
||||
MPI n; /* public modulus */
|
||||
MPI e; /* public exponent */
|
||||
MPI d; /* exponent */
|
||||
MPI p; /* prime p. */
|
||||
MPI q; /* prime q. */
|
||||
MPI 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, GcryMPI 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, gcry_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 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, gcry_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 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, gcry_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);
|
||||
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", gnupg_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", gnupg_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", gnupg_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", gnupg_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;
|
||||
GcrySexp 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;
|
||||
MPI t = gcry_mpi_snew (0);
|
||||
MPI t1 = gcry_mpi_snew (0);
|
||||
MPI t2 = gcry_mpi_snew (0);
|
||||
MPI 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)
|
||||
{
|
||||
GcryMPI 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;
|
||||
GcryMPI *kparms;
|
||||
struct rsa_secret_key_s sk;
|
||||
GcrySexp 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",
|
||||
gcry_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", gnupg_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 GcryMPI *
|
||||
sexp_to_kparms (GCRY_SEXP sexp)
|
||||
{
|
||||
GcrySexp list, l2;
|
||||
const char *name;
|
||||
const char *s;
|
||||
size_t n;
|
||||
int i, idx;
|
||||
const char *elems;
|
||||
GcryMPI *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;
|
||||
}
|
||||
|
||||
/* Paramter 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)
|
||||
{
|
||||
GcryMPI kparms[9], *kp;
|
||||
unsigned char *key;
|
||||
size_t keylen;
|
||||
GcrySexp 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;
|
||||
}
|
967
agent/protect.c
967
agent/protect.c
@ -1,967 +0,0 @@
|
||||
/* protect.c - Un/Protect a secret key
|
||||
* Copyright (C) 1998, 1999, 2000, 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>
|
||||
|
||||
#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 GNUPG_Invalid_Sexp;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "private-key"))
|
||||
return GNUPG_Unknown_Sexp;
|
||||
if (*s != '(')
|
||||
return GNUPG_Unknown_Sexp;
|
||||
hash_begin = s;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s += n; /* skip over the algorithm name */
|
||||
|
||||
while (*s == '(')
|
||||
{
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s += n;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s += n;
|
||||
if ( *s != ')' )
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s++;
|
||||
}
|
||||
if (*s != ')')
|
||||
return GNUPG_Invalid_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 hd;
|
||||
const char *modestr = "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc";
|
||||
int blklen, enclen, outlen;
|
||||
char *iv = NULL;
|
||||
int rc = 0;
|
||||
char *outbuf = NULL;
|
||||
char *p;
|
||||
int saltpos, ivpos, encpos;
|
||||
|
||||
hd = gcry_cipher_open (PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
|
||||
GCRY_CIPHER_SECURE);
|
||||
if (!hd)
|
||||
return map_gcry_err (gcry_errno());
|
||||
|
||||
|
||||
/* 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 = GNUPG_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 = GNUPG_Out_Of_Core;
|
||||
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 = GNUPG_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 out malloc system */
|
||||
char *psave = p;
|
||||
p = xtrymalloc (strlen (psave)+1);
|
||||
if (p)
|
||||
strcpy (p, psave);
|
||||
free (psave);
|
||||
}
|
||||
if (!p)
|
||||
{
|
||||
xfree (iv);
|
||||
xfree (outbuf);
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
*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 GNUPG_Invalid_Sexp;
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "private-key"))
|
||||
return GNUPG_Unknown_Sexp;
|
||||
if (*s != '(')
|
||||
return GNUPG_Unknown_Sexp;
|
||||
depth++;
|
||||
hash_begin = s;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
|
||||
for (infidx=0; protect_info[infidx].algo
|
||||
&& !smatch (&s, n, protect_info[infidx].algo); infidx++)
|
||||
;
|
||||
if (!protect_info[infidx].algo)
|
||||
return GNUPG_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 GNUPG_Invalid_Sexp;
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (n != 1 || c != *s)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s += n;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s +=n; /* skip value */
|
||||
if (*s != ')')
|
||||
return GNUPG_Invalid_Sexp;
|
||||
depth--;
|
||||
if (i == protect_info[infidx].prot_to)
|
||||
prot_end = s;
|
||||
s++;
|
||||
}
|
||||
if (*s != ')' || !prot_begin || !prot_end )
|
||||
return GNUPG_Invalid_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)
|
||||
{
|
||||
xfree (protected);
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
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 hd;
|
||||
unsigned char *outbuf;
|
||||
size_t reallen;
|
||||
|
||||
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
|
||||
if (protectedlen < 4 || (protectedlen%blklen))
|
||||
return GNUPG_Corrupted_Protection;
|
||||
|
||||
hd = gcry_cipher_open (PROT_CIPHER, GCRY_CIPHER_MODE_CBC,
|
||||
GCRY_CIPHER_SECURE);
|
||||
if (!hd)
|
||||
return map_gcry_err (gcry_errno());
|
||||
|
||||
outbuf = gcry_malloc_secure (protectedlen);
|
||||
if (!outbuf)
|
||||
rc = GNUPG_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 = GNUPG_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 GNUPG_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 GNUPG_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 GNUPG_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 GNUPG_Bug;
|
||||
n = gcry_sexp_canon_len (cleartext, 0, NULL, NULL);
|
||||
if (!n)
|
||||
return GNUPG_Bug;
|
||||
newlistlen += n;
|
||||
newlist = gcry_malloc_secure (newlistlen);
|
||||
if (!newlist)
|
||||
return GNUPG_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 GNUPG_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 GNUPG_Invalid_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 GNUPG_Invalid_Sexp;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "protected-private-key"))
|
||||
return GNUPG_Unknown_Sexp;
|
||||
if (*s != '(')
|
||||
return GNUPG_Unknown_Sexp;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
|
||||
for (infidx=0; protect_info[infidx].algo
|
||||
&& !smatch (&s, n, protect_info[infidx].algo); infidx++)
|
||||
;
|
||||
if (!protect_info[infidx].algo)
|
||||
return GNUPG_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 GNUPG_Invalid_Sexp;
|
||||
prot_begin = s;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_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 GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc"))
|
||||
return GNUPG_Unsupported_Protection;
|
||||
if (*s != '(' || s[1] != '(')
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s += 2;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "sha1"))
|
||||
return GNUPG_Unsupported_Protection;
|
||||
n = snext (&s);
|
||||
if (n != 8)
|
||||
return GNUPG_Corrupted_Protection;
|
||||
s2ksalt = s;
|
||||
s += n;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_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 GNUPG_Invalid_Sexp;
|
||||
s2kcount = strtoul (s, NULL, 10);
|
||||
if (!s2kcount)
|
||||
return GNUPG_Corrupted_Protection;
|
||||
s += n;
|
||||
s++; /* skip list end */
|
||||
|
||||
n = snext (&s);
|
||||
if (n != 16) /* Wrong blocksize for IV (we support ony aes-128) */
|
||||
return GNUPG_Corrupted_Protection;
|
||||
iv = s;
|
||||
s += n;
|
||||
if (*s != ')' )
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_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 = GNUPG_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)
|
||||
{
|
||||
GCRY_MD_HD md;
|
||||
int pass, i;
|
||||
int used = 0;
|
||||
int pwlen = strlen (passphrase);
|
||||
|
||||
if ( (s2kmode != 0 && s2kmode != 1 && s2kmode != 3)
|
||||
|| !hashalgo || !keylen || !key || !passphrase)
|
||||
return GNUPG_Invalid_Value;
|
||||
if ((s2kmode == 1 ||s2kmode == 3) && !s2ksalt)
|
||||
return GNUPG_Invalid_Value;
|
||||
|
||||
md = gcry_md_open (hashalgo, GCRY_MD_FLAG_SECURE);
|
||||
if (!md)
|
||||
return map_gcry_err (gcry_errno());
|
||||
|
||||
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 GNUPG_Invalid_Value;
|
||||
s = pubkey;
|
||||
if (*s != '(')
|
||||
return GNUPG_Invalid_Sexp;
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "public-key"))
|
||||
return GNUPG_Unknown_Sexp;
|
||||
if (*s != '(')
|
||||
return GNUPG_Unknown_Sexp;
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s += n; /* skip over the algorithm name */
|
||||
|
||||
while (*s != ')')
|
||||
{
|
||||
if (*s != '(')
|
||||
return GNUPG_Invalid_Sexp;
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s += n;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s +=n; /* skip value */
|
||||
if (*s != ')')
|
||||
return GNUPG_Invalid_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 GNUPG_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 GNUPG_Invalid_Sexp;
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (!smatch (&s, n, "shadowed-private-key"))
|
||||
return GNUPG_Unknown_Sexp;
|
||||
if (*s != '(')
|
||||
return GNUPG_Unknown_Sexp;
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s += n; /* skip over the algorithm name */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (*s == ')')
|
||||
return GNUPG_Unknown_Sexp;
|
||||
if (*s != '(')
|
||||
return GNUPG_Invalid_Sexp;
|
||||
depth++;
|
||||
s++;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (smatch (&s, n, "shadowed"))
|
||||
break;
|
||||
s += n;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
s +=n; /* skip value */
|
||||
if (*s != ')')
|
||||
return GNUPG_Invalid_Sexp;
|
||||
depth--;
|
||||
s++;
|
||||
}
|
||||
/* found the shadowed list, s points to the protocol */
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_Sexp;
|
||||
if (smatch (&s, n, "t1-v1"))
|
||||
{
|
||||
if (*s != '(')
|
||||
return GNUPG_Invalid_Sexp;
|
||||
*shadow_info = s;
|
||||
}
|
||||
else
|
||||
return GNUPG_Unsupported_Protocol;
|
||||
return 0;
|
||||
}
|
||||
|
460
agent/query.c
460
agent/query.c
@ -1,460 +0,0 @@
|
||||
/* query.c - fork of the pinentry to query stuff from the user
|
||||
* 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
|
||||
*/
|
||||
|
||||
#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/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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
unlock_pinentry (int rc)
|
||||
{
|
||||
#ifdef USE_GNU_PTH
|
||||
if (!pth_mutex_release (&entry_lock))
|
||||
{
|
||||
log_error ("failed to release the entry lock\n");
|
||||
if (!rc)
|
||||
rc = GNUPG_Internal_Error;
|
||||
}
|
||||
#endif
|
||||
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 (void)
|
||||
{
|
||||
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 GNUPG_Internal_Error;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (entry_ctx)
|
||||
return 0;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("no running PIN Entry - starting it\n");
|
||||
|
||||
if (fflush (NULL))
|
||||
{
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
return unlock_pinentry (seterr (Write_Error));
|
||||
}
|
||||
|
||||
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++;
|
||||
|
||||
/* FIXME: We must do this thread specific */
|
||||
argv[0] = pgmname;
|
||||
if (opt.display)
|
||||
{
|
||||
argv[1] = "--display";
|
||||
argv[2] = opt.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 (seterr (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 (opt.ttyname)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttyname=%s", opt.ttyname) < 0 )
|
||||
return unlock_pinentry (GNUPG_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 (opt.ttytype)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttytype=%s", opt.ttytype) < 0 )
|
||||
return unlock_pinentry (GNUPG_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 (opt.lc_ctype)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-ctype=%s", opt.lc_ctype) < 0 )
|
||||
return unlock_pinentry (GNUPG_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 (opt.lc_messages)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-messages=%s", opt.lc_messages) < 0 )
|
||||
return unlock_pinentry (GNUPG_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 (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 seterr (Invalid_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 ();
|
||||
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 (rc == GNUPG_Bad_Passphrase || rc == GNUPG_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 (pininfo->min_digits? GNUPG_Bad_PIN
|
||||
: GNUPG_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 (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 GNUPG_Bad_Passphrase;
|
||||
|
||||
rc = start_pinentry ();
|
||||
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 (seterr (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)
|
||||
{
|
||||
xfree (parm.buffer);
|
||||
return unlock_pinentry (seterr (Out_Of_Core));
|
||||
}
|
||||
|
||||
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, GNUPG_Not_Confirmed for what the text says or an
|
||||
other error. */
|
||||
int
|
||||
agent_get_confirmation (const char *desc, const char *ok, const char *cancel)
|
||||
{
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
rc = start_pinentry ();
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 GNUPG_Invalid_Sexp;
|
||||
n = snext (&s);
|
||||
if (!n)
|
||||
return GNUPG_Invalid_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*/
|
@ -1,485 +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
|
||||
*/
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (ttyname (1))
|
||||
dft_ttyname = ttyname (1);
|
||||
if (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;
|
||||
}
|
@ -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*/
|
@ -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;
|
||||
}
|
@ -1,304 +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/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)
|
||||
{
|
||||
log_error ("can't create `%s': %s\n", fname, strerror (errno));
|
||||
xfree (fname);
|
||||
return seterr (File_Create_Error);
|
||||
}
|
||||
fputs (headerblurb, trustfp);
|
||||
fclose (trustfp);
|
||||
trustfp = fopen (fname, append? "a+":"r");
|
||||
}
|
||||
|
||||
if (!trustfp)
|
||||
{
|
||||
log_error ("can't open `%s': %s\n", fname, strerror (errno));
|
||||
xfree (fname);
|
||||
return seterr (File_Open_Error);
|
||||
}
|
||||
|
||||
/*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 GNUPG_Read_Error;
|
||||
}
|
||||
|
||||
if (!*line || line[strlen(line)-1] != '\n')
|
||||
{
|
||||
/* eat until end of line */
|
||||
while ( (c=getc (trustfp)) != EOF && c != '\n')
|
||||
;
|
||||
return *line? GNUPG_Line_Too_Long: GNUPG_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 GNUPG_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 GNUPG_Bad_Data;
|
||||
}
|
||||
i++;
|
||||
if ( !(spacep (p+i) || p[i] == '\n'))
|
||||
{
|
||||
log_error ("invalid keyflag in trustlist\n");
|
||||
return GNUPG_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 (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 GNUPG_Out_Of_Core;
|
||||
rc = agent_get_confirmation (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 GNUPG_Out_Of_Core;
|
||||
rc = agent_get_confirmation (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 = GNUPG_Write_Error;
|
||||
|
||||
/* close because we are in append mode */
|
||||
if (fclose (trustfp))
|
||||
rc = GNUPG_File_Error;
|
||||
trustfp = NULL;
|
||||
return rc;
|
||||
}
|
250
assuan/ChangeLog
250
assuan/ChangeLog
@ -1,250 +0,0 @@
|
||||
2002-08-16 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan.h: Renamed Bad_Certificate_Path to Bad_Certificate_Chain.
|
||||
|
||||
2002-07-30 Werner Koch <wk@gnupg.org>
|
||||
|
||||
Changed the license from GPL to LGPL.
|
||||
|
||||
2002-07-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-handler.c (_IO_cookie_io_functions_t): Define it here if
|
||||
it does not exists.
|
||||
|
||||
2002-06-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-pipe-connect.c (assuan_pipe_connect): No special handling
|
||||
for the log_fd and stderr. Connect stderr to /dev/null if it
|
||||
should not be retained.
|
||||
|
||||
2002-06-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-buffer.c (assuan_write_line): Make sure we never
|
||||
accidently print an extra LF.
|
||||
|
||||
2002-05-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-util.c (assuan_set_io_func): New.
|
||||
* assuan-buffer.c (writen, readline): Use the new functions
|
||||
instead of pth.
|
||||
* assuan-socket-server.c (accept_connection): Don't use the
|
||||
pth_accept - using the assuan included accept code would be a bad
|
||||
idea within Pth so we don't need a replacement function.
|
||||
|
||||
2002-05-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-socket-server.c (assuan_init_connected_socket_server): New.
|
||||
(accept_connection): Factored most code out to..
|
||||
(accept_connection_bottom): .. new function.
|
||||
|
||||
2002-04-04 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-buffer.c (my_log_prefix): New. Use it for all i/o debug
|
||||
output.
|
||||
|
||||
2002-03-06 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-client.c (_assuan_read_from_server): Detect END.
|
||||
(assuan_transact): Pass it to the data callback.
|
||||
|
||||
2002-02-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-client.c (assuan_transact): Add 2 more arguments to
|
||||
support status lines. Passing NULL yields the old behaviour.
|
||||
|
||||
* assuan-handler.c (process_request): Flush data lines send
|
||||
without using the data fp.
|
||||
|
||||
2002-02-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-inquire.c (assuan_inquire): Check for a cancel command
|
||||
and return ASSUAN_Canceled. Allow for non-data inquiry.
|
||||
|
||||
* assuan.h: Add a few token specific error codes.
|
||||
|
||||
2002-02-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-defs.h (assuan_context_s): New var CLIENT_PID.
|
||||
* assuan-pipe-server.c (_assuan_new_context): set default value.
|
||||
* assuan-socket-server.c (accept_connection): get the actual pid.
|
||||
|
||||
2002-02-12 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-buffer.c (writen,readline) [USE_GNU_PT]: Use pth_read/write.
|
||||
* assuan-socket-server.c (accept_connection) [USE_GNU_PTH]: Ditto.
|
||||
|
||||
2002-02-01 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* Makefile.am (MOSTLYCLEANFILES): New variable.
|
||||
|
||||
2002-01-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-socket-connect.c (LOGERRORX): and removed typo.
|
||||
|
||||
2002-01-22 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* assuan-socket-connect.c (LOGERRORX): Reverse arguments to fputs.
|
||||
|
||||
2002-01-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-connect.c: Move all except assuan_get_pid to...
|
||||
* assuan-pipe-connect.c: this.
|
||||
(assuan_pipe_disconnect): Removed.
|
||||
(do_finish, do_deinit): New
|
||||
(assuan_pipe_connect): and set them into the context.
|
||||
* assuan-socket-connect.c: New.
|
||||
|
||||
* assuan-util.c (_assuan_log_sanitized_string): New.
|
||||
|
||||
* assuan-pipe-server.c (assuan_init_pipe_server): Factored most
|
||||
code out to ...
|
||||
(_assuan_new_context): new func.
|
||||
(_assuan_release_context): New
|
||||
* assuan-connect.c (assuan_pipe_connect): Use the new functions.
|
||||
|
||||
2002-01-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan.h: Added Invalid Option error code.
|
||||
|
||||
* assuan-handler.c (std_handler_option): New.
|
||||
(std_cmd_tbl): Add OPTION as standard command.
|
||||
(assuan_register_option_handler): New.
|
||||
(dispatch_command): Use case insensitive matching as a fallback.
|
||||
(my_strcasecmp): New.
|
||||
|
||||
2002-01-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-buffer.c (_assuan_read_line): Add output logging.
|
||||
(assuan_write_line): Ditto.
|
||||
(_assuan_cookie_write_data): Ditto.
|
||||
(_assuan_cookie_write_flush): Ditto.
|
||||
* assuan-util.c (_assuan_log_print_buffer): New.
|
||||
(assuan_set_log_stream): New.
|
||||
(assuan_begin_confidential): New.
|
||||
(assuan_end_confidential): New.
|
||||
|
||||
* assuan-defs.h: Add a few handler variables.
|
||||
* assuan-pipe-server.c (assuan_deinit_pipe_server): Removed.
|
||||
(deinit_pipe_server): New.
|
||||
(assuan_deinit_server): New. Changed all callers to use this.
|
||||
* assuan-listen.c (assuan_accept): Use the accept handler.
|
||||
* assuan-handler.c (process_request): Use the close Handler.
|
||||
* assuan-socket-server.c: New.
|
||||
|
||||
2002-01-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-client.c (_assuan_read_from_server): Skip spaces after
|
||||
the keyword.
|
||||
|
||||
2002-01-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-handler.c (assuan_set_okay_line): New.
|
||||
(process_request): And use it here.
|
||||
|
||||
2002-01-02 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-inquire.c (init_membuf,put_membuf,get_membuf): Apply a
|
||||
hidden 0 behind the buffer so that the buffer can be used as a
|
||||
string in certain contexts.
|
||||
|
||||
2001-12-14 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* assuan-connect.c (assuan_pipe_connect): New argument
|
||||
FD_CHILD_LIST. Don't close those fds.
|
||||
* assuan.h: Likewise for prototype.
|
||||
|
||||
2001-12-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-listen.c (assuan_close_input_fd): New.
|
||||
(assuan_close_output_fd): New.
|
||||
* assuan-handler.c (std_handler_reset): Always close them after a
|
||||
reset command.
|
||||
(std_handler_bye): Likewise.
|
||||
|
||||
2001-12-14 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* assuan-buffer.c (_assuan_read_line): New variable ATTICLEN, use
|
||||
it to save the length of the attic line.
|
||||
Rediddle the code a bit to make it more clear what happens.
|
||||
|
||||
2001-12-14 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* assuan-defs.h (LINELENGTH): Define as ASSUAN_LINELENGTH.
|
||||
assuan.h: Define ASSUAN_LINELENGTH.
|
||||
|
||||
2001-12-13 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* assuan-buffer.c (assuan_read_line): Fix order of execution to
|
||||
get correct return values.
|
||||
|
||||
2001-12-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-handler.c (assuan_get_active_fds): Fixed silly bug,
|
||||
pretty obvious that nobody ever tested this function.
|
||||
|
||||
2001-12-12 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-connect.c (assuan_pipe_connect): Implemented the inital
|
||||
handshake.
|
||||
* assuan-client.c (read_from_server): Renamed to
|
||||
(_assuan_read_from_server): this and made external.
|
||||
|
||||
* assuan-listen.c (assuan_set_hello_line): New.
|
||||
(assuan_accept): Use a custom hello line is available.
|
||||
|
||||
* assuan-buffer.c (assuan_read_line): New.
|
||||
(assuan_pending_line): New.
|
||||
(_assuan_write_line): Renamed to ..
|
||||
(assuan_write_line): this, made public and changed all callers.
|
||||
|
||||
2001-12-04 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-connect.c (assuan_pipe_connect): Add more error reporting.
|
||||
* assuan-client.c: New.
|
||||
|
||||
* assuan-inquire.c: New.
|
||||
* assuan-handler.c (process_request): Check for nested invocations.
|
||||
|
||||
2001-11-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-handler.c (assuan_register_input_notify): New.
|
||||
(assuan_register_output_notify): New.
|
||||
|
||||
2001-11-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan.h: Added more status codes.
|
||||
|
||||
2001-11-25 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-handler.c (assuan_register_bye_notify)
|
||||
(assuan_register_reset_notify)
|
||||
(assuan_register_cancel_notify): New and call them from the
|
||||
standard handlers.
|
||||
(assuan_process): Moved bulk of function to ..
|
||||
(process_request): .. new.
|
||||
(assuan_process_next): One shot version of above.
|
||||
(assuan_get_active_fds): New.
|
||||
|
||||
2001-11-24 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* assuan-connect.c (assuan_get_pid): New.
|
||||
|
||||
* assuan-buffer.c (_assuan_read_line): Deal with reads of more
|
||||
than a line.
|
||||
* assuan-defs.h: Add space in the context for this.
|
||||
|
||||
|
||||
***********************************************************
|
||||
* Please note that Assuan is maintained as part of GnuPG. *
|
||||
* You may find it source-copied in other packages. *
|
||||
***********************************************************
|
||||
|
||||
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.
|
@ -1,49 +0,0 @@
|
||||
# Assuan Makefile
|
||||
# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of Assuan.
|
||||
#
|
||||
# Assuan is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# Assuan 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser 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
|
||||
|
||||
EXTRA_DIST = mkerrors
|
||||
INCLUDES = -I.. -I$(top_srcdir)/include
|
||||
BUILT_SOURCES = assuan-errors.c
|
||||
MOSTLYCLEANFILES = assuan-errors.c
|
||||
|
||||
noinst_LIBRARIES = libassuan.a
|
||||
|
||||
|
||||
#libassuan_a_LDFLAGS =
|
||||
libassuan_a_SOURCES = \
|
||||
assuan.h \
|
||||
assuan-defs.h \
|
||||
assuan-util.c \
|
||||
assuan-errors.c \
|
||||
assuan-buffer.c \
|
||||
assuan-handler.c \
|
||||
assuan-inquire.c \
|
||||
assuan-listen.c \
|
||||
assuan-connect.c \
|
||||
assuan-client.c \
|
||||
assuan-pipe-server.c \
|
||||
assuan-socket-server.c \
|
||||
assuan-pipe-connect.c \
|
||||
assuan-socket-connect.c
|
||||
|
||||
|
||||
assuan-errors.c : assuan.h
|
||||
$(srcdir)/mkerrors < $(srcdir)/assuan.h > assuan-errors.c
|
@ -1,443 +0,0 @@
|
||||
/* assuan-buffer.c - read and send data
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include "assuan-defs.h"
|
||||
|
||||
#ifdef HAVE_JNLIB_LOGGING
|
||||
#include "../jnlib/logging.h"
|
||||
#endif
|
||||
|
||||
|
||||
static const char *
|
||||
my_log_prefix (void)
|
||||
{
|
||||
#ifdef HAVE_JNLIB_LOGGING
|
||||
return log_get_prefix (NULL);
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
writen ( int fd, const char *buffer, size_t length )
|
||||
{
|
||||
while (length)
|
||||
{
|
||||
int nwritten = _assuan_write_wrapper?
|
||||
_assuan_write_wrapper (fd, buffer, length):
|
||||
write (fd, buffer, length);
|
||||
|
||||
if (nwritten < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -1; /* write error */
|
||||
}
|
||||
length -= nwritten;
|
||||
buffer += nwritten;
|
||||
}
|
||||
return 0; /* okay */
|
||||
}
|
||||
|
||||
/* read an entire line */
|
||||
static int
|
||||
readline (int fd, char *buf, size_t buflen, int *r_nread, int *eof)
|
||||
{
|
||||
size_t nleft = buflen;
|
||||
char *p;
|
||||
|
||||
*eof = 0;
|
||||
*r_nread = 0;
|
||||
while (nleft > 0)
|
||||
{
|
||||
int n = _assuan_read_wrapper?
|
||||
_assuan_read_wrapper (fd, buf, nleft):
|
||||
read (fd, buf, nleft);
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -1; /* read error */
|
||||
}
|
||||
else if (!n)
|
||||
{
|
||||
*eof = 1;
|
||||
break; /* allow incomplete lines */
|
||||
}
|
||||
p = buf;
|
||||
nleft -= n;
|
||||
buf += n;
|
||||
*r_nread += n;
|
||||
|
||||
for (; n && *p != '\n'; n--, p++)
|
||||
;
|
||||
if (n)
|
||||
break; /* at least one full line available - that's enough for now */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
_assuan_read_line (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
char *line = ctx->inbound.line;
|
||||
int n, nread, atticlen;
|
||||
int rc;
|
||||
|
||||
if (ctx->inbound.eof)
|
||||
return -1;
|
||||
|
||||
atticlen = ctx->inbound.attic.linelen;
|
||||
if (atticlen)
|
||||
{
|
||||
memcpy (line, ctx->inbound.attic.line, atticlen);
|
||||
ctx->inbound.attic.linelen = 0;
|
||||
for (n=0; n < atticlen && line[n] != '\n'; n++)
|
||||
;
|
||||
if (n < atticlen)
|
||||
{
|
||||
rc = 0; /* found another line in the attic */
|
||||
nread = atticlen;
|
||||
atticlen = 0;
|
||||
}
|
||||
else
|
||||
{ /* read the rest */
|
||||
assert (atticlen < LINELENGTH);
|
||||
rc = readline (ctx->inbound.fd, line + atticlen,
|
||||
LINELENGTH - atticlen, &nread, &ctx->inbound.eof);
|
||||
}
|
||||
}
|
||||
else
|
||||
rc = readline (ctx->inbound.fd, line, LINELENGTH,
|
||||
&nread, &ctx->inbound.eof);
|
||||
if (rc)
|
||||
{
|
||||
if (ctx->log_fp)
|
||||
fprintf (ctx->log_fp, "%s[%p] <- [Error: %s]\n",
|
||||
my_log_prefix (), ctx, strerror (errno));
|
||||
return ASSUAN_Read_Error;
|
||||
}
|
||||
if (!nread)
|
||||
{
|
||||
assert (ctx->inbound.eof);
|
||||
if (ctx->log_fp)
|
||||
fprintf (ctx->log_fp, "%s[%p] <- [EOF]\n", my_log_prefix (),ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->inbound.attic.pending = 0;
|
||||
nread += atticlen;
|
||||
for (n=0; n < nread; n++)
|
||||
{
|
||||
if (line[n] == '\n')
|
||||
{
|
||||
if (n+1 < nread)
|
||||
{
|
||||
char *s, *d;
|
||||
int i;
|
||||
|
||||
n++;
|
||||
/* we have to copy the rest because the handlers are
|
||||
allowed to modify the passed buffer */
|
||||
for (d=ctx->inbound.attic.line, s=line+n, i=nread-n; i; i--)
|
||||
{
|
||||
if (*s=='\n')
|
||||
ctx->inbound.attic.pending = 1;
|
||||
*d++ = *s++;
|
||||
}
|
||||
ctx->inbound.attic.linelen = nread-n;
|
||||
n--;
|
||||
}
|
||||
if (n && line[n-1] == '\r')
|
||||
n--;
|
||||
line[n] = 0;
|
||||
ctx->inbound.linelen = n;
|
||||
if (ctx->log_fp)
|
||||
{
|
||||
fprintf (ctx->log_fp, "%s[%p] <- ", my_log_prefix (), ctx);
|
||||
if (ctx->confidential)
|
||||
fputs ("[Confidential data not shown]", ctx->log_fp);
|
||||
else
|
||||
_assuan_log_print_buffer (ctx->log_fp,
|
||||
ctx->inbound.line,
|
||||
ctx->inbound.linelen);
|
||||
putc ('\n', ctx->log_fp);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->log_fp)
|
||||
fprintf (ctx->log_fp, "%s[%p] <- [Invalid line]\n", my_log_prefix (), ctx);
|
||||
*line = 0;
|
||||
ctx->inbound.linelen = 0;
|
||||
return ctx->inbound.eof? ASSUAN_Line_Not_Terminated : ASSUAN_Line_Too_Long;
|
||||
}
|
||||
|
||||
|
||||
/* Read the next line from the client or server and return a pointer
|
||||
to a buffer with holding that line. linelen returns the length of
|
||||
the line. This buffer is valid until another read operation is
|
||||
done on this buffer. The caller is allowed to modify this buffer.
|
||||
He should only use the buffer if the function returns without an
|
||||
error.
|
||||
|
||||
Returns: 0 on success or an assuan error code
|
||||
See also: assuan_pending_line().
|
||||
*/
|
||||
AssuanError
|
||||
assuan_read_line (ASSUAN_CONTEXT ctx, char **line, size_t *linelen)
|
||||
{
|
||||
AssuanError err;
|
||||
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
|
||||
err = _assuan_read_line (ctx);
|
||||
*line = ctx->inbound.line;
|
||||
*linelen = ctx->inbound.linelen;
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/* Return true when a full line is pending for a read, without the need
|
||||
for actual IO */
|
||||
int
|
||||
assuan_pending_line (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
return ctx && ctx->inbound.attic.pending;
|
||||
}
|
||||
|
||||
|
||||
AssuanError
|
||||
assuan_write_line (ASSUAN_CONTEXT ctx, const char *line )
|
||||
{
|
||||
int rc;
|
||||
size_t len;
|
||||
const char *s;
|
||||
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
|
||||
/* Make sure that we never take a LF from the user - this might
|
||||
violate the protocol. */
|
||||
s = strchr (line, '\n');
|
||||
len = s? (s-line) : strlen (line);
|
||||
|
||||
/* fixme: we should do some kind of line buffering. */
|
||||
if (ctx->log_fp)
|
||||
{
|
||||
fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx);
|
||||
if (s)
|
||||
fputs ("[supplied line contained a LF]", ctx->log_fp);
|
||||
if (ctx->confidential)
|
||||
fputs ("[Confidential data not shown]", ctx->log_fp);
|
||||
else
|
||||
_assuan_log_print_buffer (ctx->log_fp, line, len);
|
||||
putc ('\n', ctx->log_fp);
|
||||
}
|
||||
|
||||
rc = writen (ctx->outbound.fd, line, len);
|
||||
if (rc)
|
||||
rc = ASSUAN_Write_Error;
|
||||
if (!rc)
|
||||
{
|
||||
rc = writen (ctx->outbound.fd, "\n", 1);
|
||||
if (rc)
|
||||
rc = ASSUAN_Write_Error;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Write out the data in buffer as datalines with line wrapping and
|
||||
percent escaping. This fucntion is used for GNU's custom streams */
|
||||
int
|
||||
_assuan_cookie_write_data (void *cookie, const char *buffer, size_t size)
|
||||
{
|
||||
ASSUAN_CONTEXT ctx = cookie;
|
||||
char *line;
|
||||
size_t linelen;
|
||||
|
||||
if (ctx->outbound.data.error)
|
||||
return 0;
|
||||
|
||||
line = ctx->outbound.data.line;
|
||||
linelen = ctx->outbound.data.linelen;
|
||||
line += linelen;
|
||||
while (size)
|
||||
{
|
||||
/* insert data line header */
|
||||
if (!linelen)
|
||||
{
|
||||
*line++ = 'D';
|
||||
*line++ = ' ';
|
||||
linelen += 2;
|
||||
}
|
||||
|
||||
/* copy data, keep some space for the CRLF and to escape one character */
|
||||
while (size && linelen < LINELENGTH-2-2)
|
||||
{
|
||||
if (*buffer == '%' || *buffer == '\r' || *buffer == '\n')
|
||||
{
|
||||
sprintf (line, "%%%02X", *(unsigned char*)buffer);
|
||||
line += 3;
|
||||
linelen += 3;
|
||||
buffer++;
|
||||
}
|
||||
else
|
||||
{
|
||||
*line++ = *buffer++;
|
||||
linelen++;
|
||||
}
|
||||
size--;
|
||||
}
|
||||
|
||||
if (linelen >= LINELENGTH-2-2)
|
||||
{
|
||||
if (ctx->log_fp)
|
||||
{
|
||||
fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx);
|
||||
if (ctx->confidential)
|
||||
fputs ("[Confidential data not shown]", ctx->log_fp);
|
||||
else
|
||||
_assuan_log_print_buffer (ctx->log_fp,
|
||||
ctx->outbound.data.line,
|
||||
linelen);
|
||||
putc ('\n', ctx->log_fp);
|
||||
}
|
||||
*line++ = '\n';
|
||||
linelen++;
|
||||
if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
|
||||
{
|
||||
ctx->outbound.data.error = ASSUAN_Write_Error;
|
||||
return 0;
|
||||
}
|
||||
line = ctx->outbound.data.line;
|
||||
linelen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->outbound.data.linelen = linelen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Write out any buffered data
|
||||
This fucntion is used for GNU's custom streams */
|
||||
int
|
||||
_assuan_cookie_write_flush (void *cookie)
|
||||
{
|
||||
ASSUAN_CONTEXT ctx = cookie;
|
||||
char *line;
|
||||
size_t linelen;
|
||||
|
||||
if (ctx->outbound.data.error)
|
||||
return 0;
|
||||
|
||||
line = ctx->outbound.data.line;
|
||||
linelen = ctx->outbound.data.linelen;
|
||||
line += linelen;
|
||||
if (linelen)
|
||||
{
|
||||
if (ctx->log_fp)
|
||||
{
|
||||
fprintf (ctx->log_fp, "%s[%p] -> ", my_log_prefix (), ctx);
|
||||
if (ctx->confidential)
|
||||
fputs ("[Confidential data not shown]", ctx->log_fp);
|
||||
else
|
||||
_assuan_log_print_buffer (ctx->log_fp,
|
||||
ctx->outbound.data.line,
|
||||
linelen);
|
||||
putc ('\n', ctx->log_fp);
|
||||
}
|
||||
*line++ = '\n';
|
||||
linelen++;
|
||||
if (writen (ctx->outbound.fd, ctx->outbound.data.line, linelen))
|
||||
{
|
||||
ctx->outbound.data.error = ASSUAN_Write_Error;
|
||||
return 0;
|
||||
}
|
||||
ctx->outbound.data.linelen = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* assuan_send_data:
|
||||
* @ctx: An assuan context
|
||||
* @buffer: Data to send or NULL to flush
|
||||
* @length: length of the data to send/
|
||||
*
|
||||
* This function may be used by the server or the client to send data
|
||||
* lines. The data will be escaped as required by the Assuan protocol
|
||||
* and may get buffered until a line is full. To force sending the
|
||||
* data out @buffer may be passed as NULL (in which case @length must
|
||||
* also be 0); however when used by a client this flush operation does
|
||||
* also send the terminating "END" command to terminate the reponse on
|
||||
* a INQUIRE response. However, when assuan_transact() is used, this
|
||||
* function takes care of sending END itself.
|
||||
*
|
||||
* Return value: 0 on success or an error code
|
||||
**/
|
||||
|
||||
AssuanError
|
||||
assuan_send_data (ASSUAN_CONTEXT ctx, const void *buffer, size_t length)
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
if (!buffer && length)
|
||||
return ASSUAN_Invalid_Value;
|
||||
|
||||
if (!buffer)
|
||||
{ /* flush what we have */
|
||||
_assuan_cookie_write_flush (ctx);
|
||||
if (ctx->outbound.data.error)
|
||||
return ctx->outbound.data.error;
|
||||
if (!ctx->is_server)
|
||||
return assuan_write_line (ctx, "END");
|
||||
}
|
||||
else
|
||||
{
|
||||
_assuan_cookie_write_data (ctx, buffer, length);
|
||||
if (ctx->outbound.data.error)
|
||||
return ctx->outbound.data.error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,225 +0,0 @@
|
||||
/* assuan-client.c - client functions
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
#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))
|
||||
|
||||
|
||||
AssuanError
|
||||
_assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off)
|
||||
{
|
||||
char *line;
|
||||
int linelen;
|
||||
AssuanError rc;
|
||||
|
||||
*okay = 0;
|
||||
*off = 0;
|
||||
do
|
||||
{
|
||||
rc = _assuan_read_line (ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
line = ctx->inbound.line;
|
||||
linelen = ctx->inbound.linelen;
|
||||
}
|
||||
while (*line == '#' || !linelen);
|
||||
|
||||
if (linelen >= 1
|
||||
&& line[0] == 'D' && line[1] == ' ')
|
||||
{
|
||||
*okay = 2; /* data line */
|
||||
*off = 2;
|
||||
}
|
||||
else if (linelen >= 1
|
||||
&& line[0] == 'S'
|
||||
&& (line[1] == '\0' || line[1] == ' '))
|
||||
{
|
||||
*okay = 4;
|
||||
*off = 1;
|
||||
while (line[*off] == ' ')
|
||||
++*off;
|
||||
}
|
||||
else if (linelen >= 2
|
||||
&& line[0] == 'O' && line[1] == 'K'
|
||||
&& (line[2] == '\0' || line[2] == ' '))
|
||||
{
|
||||
*okay = 1;
|
||||
*off = 2;
|
||||
while (line[*off] == ' ')
|
||||
++*off;
|
||||
}
|
||||
else if (linelen >= 3
|
||||
&& line[0] == 'E' && line[1] == 'R' && line[2] == 'R'
|
||||
&& (line[3] == '\0' || line[3] == ' '))
|
||||
{
|
||||
*okay = 0;
|
||||
*off = 3;
|
||||
while (line[*off] == ' ')
|
||||
++*off;
|
||||
}
|
||||
else if (linelen >= 7
|
||||
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
|
||||
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
|
||||
&& line[6] == 'E'
|
||||
&& (line[7] == '\0' || line[7] == ' '))
|
||||
{
|
||||
*okay = 3;
|
||||
*off = 7;
|
||||
while (line[*off] == ' ')
|
||||
++*off;
|
||||
}
|
||||
else if (linelen >= 3
|
||||
&& line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
|
||||
&& (line[3] == '\0' || line[3] == ' '))
|
||||
{
|
||||
*okay = 5; /* end line */
|
||||
*off = 3;
|
||||
}
|
||||
else
|
||||
rc = ASSUAN_Invalid_Response;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* assuan_transact:
|
||||
* @ctx: The Assuan context
|
||||
* @command: Coimmand line to be send to server
|
||||
* @data_cb: Callback function for data lines
|
||||
* @data_cb_arg: first argument passed to @data_cb
|
||||
* @inquire_cb: Callback function for a inquire response
|
||||
* @inquire_cb_arg: first argument passed to @inquire_cb
|
||||
* @status_cb: Callback function for a status response
|
||||
* @status_cb_arg: first argument passed to @status_cb
|
||||
*
|
||||
* FIXME: Write documentation
|
||||
*
|
||||
* Return value: 0 on success or error code. The error code may be
|
||||
* the one one returned by the server in error lines or from the
|
||||
* callback functions.
|
||||
**/
|
||||
AssuanError
|
||||
assuan_transact (ASSUAN_CONTEXT ctx,
|
||||
const char *command,
|
||||
AssuanError (*data_cb)(void *, const void *, size_t),
|
||||
void *data_cb_arg,
|
||||
AssuanError (*inquire_cb)(void*, const char *),
|
||||
void *inquire_cb_arg,
|
||||
AssuanError (*status_cb)(void*, const char *),
|
||||
void *status_cb_arg)
|
||||
{
|
||||
int rc, okay, off;
|
||||
unsigned char *line;
|
||||
int linelen;
|
||||
|
||||
rc = assuan_write_line (ctx, command);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
again:
|
||||
rc = _assuan_read_from_server (ctx, &okay, &off);
|
||||
if (rc)
|
||||
return rc; /* error reading from server */
|
||||
|
||||
line = ctx->inbound.line + off;
|
||||
linelen = ctx->inbound.linelen - off;
|
||||
|
||||
if (!okay)
|
||||
{
|
||||
rc = atoi (line);
|
||||
if (rc < 100)
|
||||
rc = ASSUAN_Server_Fault;
|
||||
}
|
||||
else if (okay == 2)
|
||||
{
|
||||
if (!data_cb)
|
||||
rc = ASSUAN_No_Data_Callback;
|
||||
else
|
||||
{
|
||||
unsigned char *s, *d;
|
||||
|
||||
for (s=d=line; linelen; linelen--)
|
||||
{
|
||||
if (*s == '%' && linelen > 2)
|
||||
{ /* handle escaping */
|
||||
s++;
|
||||
*d++ = xtoi_2 (s);
|
||||
s += 2;
|
||||
linelen -= 2;
|
||||
}
|
||||
else
|
||||
*d++ = *s++;
|
||||
}
|
||||
*d = 0; /* add a hidden string terminator */
|
||||
rc = data_cb (data_cb_arg, line, d - line);
|
||||
if (!rc)
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
else if (okay == 3)
|
||||
{
|
||||
if (!inquire_cb)
|
||||
{
|
||||
assuan_write_line (ctx, "END"); /* get out of inquire mode */
|
||||
_assuan_read_from_server (ctx, &okay, &off); /* dummy read */
|
||||
rc = ASSUAN_No_Inquire_Callback;
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = inquire_cb (inquire_cb_arg, line);
|
||||
if (!rc)
|
||||
rc = assuan_send_data (ctx, NULL, 0); /* flush and send END */
|
||||
if (!rc)
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
else if (okay == 4)
|
||||
{
|
||||
if (status_cb)
|
||||
rc = status_cb (status_cb_arg, line);
|
||||
if (!rc)
|
||||
goto again;
|
||||
}
|
||||
else if (okay == 5)
|
||||
{
|
||||
if (!data_cb)
|
||||
rc = ASSUAN_No_Data_Callback;
|
||||
else
|
||||
{
|
||||
rc = data_cb (data_cb_arg, NULL, 0);
|
||||
if (!rc)
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
@ -1,54 +0,0 @@
|
||||
/* assuan-connect.c - Establish a connection (client)
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
/* Disconnect and release the context CTX. */
|
||||
void
|
||||
assuan_disconnect (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
assuan_write_line (ctx, "BYE");
|
||||
ctx->finish_handler (ctx);
|
||||
ctx->deinit_handler (ctx);
|
||||
ctx->deinit_handler = NULL;
|
||||
_assuan_release_context (ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pid_t
|
||||
assuan_get_pid (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
return ctx ? ctx->pid : -1;
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
/* assuan-defs.c - Internal definitions to Assuan
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 ASSUAN_DEFS_H
|
||||
#define ASSUAN_DEFS_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "assuan.h"
|
||||
|
||||
#define LINELENGTH ASSUAN_LINELENGTH
|
||||
|
||||
struct cmdtbl_s {
|
||||
const char *name;
|
||||
int cmd_id;
|
||||
int (*handler)(ASSUAN_CONTEXT, char *line);
|
||||
};
|
||||
|
||||
struct assuan_context_s {
|
||||
AssuanError err_no;
|
||||
const char *err_str;
|
||||
int os_errno; /* last system error number used with certain error codes*/
|
||||
|
||||
int confidential;
|
||||
int is_server; /* set if this is context belongs to a server */
|
||||
int in_inquire;
|
||||
char *hello_line;
|
||||
char *okay_line; /* see assan_set_okay_line() */
|
||||
|
||||
void *user_pointer; /* for assuan_[gs]et_pointer () */
|
||||
|
||||
FILE *log_fp;
|
||||
|
||||
struct {
|
||||
int fd;
|
||||
int eof;
|
||||
char line[LINELENGTH];
|
||||
int linelen; /* w/o CR, LF - might not be the same as
|
||||
strlen(line) due to embedded nuls. However a nul
|
||||
is always written at this pos */
|
||||
struct {
|
||||
char line[LINELENGTH];
|
||||
int linelen ;
|
||||
int pending; /* i.e. at least one line is available in the attic */
|
||||
} attic;
|
||||
} inbound;
|
||||
|
||||
struct {
|
||||
int fd;
|
||||
struct {
|
||||
FILE *fp;
|
||||
char line[LINELENGTH];
|
||||
int linelen;
|
||||
int error;
|
||||
} data;
|
||||
} outbound;
|
||||
|
||||
int pipe_mode; /* We are in pipe mode, i.e. we can handle just one
|
||||
connection and must terminate then */
|
||||
pid_t pid; /* In pipe mode, the pid of the child server process.
|
||||
In socket mode, the pid of the server */
|
||||
int listen_fd; /* The fd we are listening on (used by socket servers) */
|
||||
int connected_fd; /* helper */
|
||||
|
||||
pid_t client_pid; /* for a socket server the PID of the client or -1
|
||||
if not available */
|
||||
|
||||
void (*deinit_handler)(ASSUAN_CONTEXT);
|
||||
int (*accept_handler)(ASSUAN_CONTEXT);
|
||||
int (*finish_handler)(ASSUAN_CONTEXT);
|
||||
|
||||
struct cmdtbl_s *cmdtbl;
|
||||
size_t cmdtbl_used; /* used entries */
|
||||
size_t cmdtbl_size; /* allocated size of table */
|
||||
|
||||
void (*bye_notify_fnc)(ASSUAN_CONTEXT);
|
||||
void (*reset_notify_fnc)(ASSUAN_CONTEXT);
|
||||
void (*cancel_notify_fnc)(ASSUAN_CONTEXT);
|
||||
int (*option_handler_fnc)(ASSUAN_CONTEXT,const char*, const char*);
|
||||
void (*input_notify_fnc)(ASSUAN_CONTEXT, const char *);
|
||||
void (*output_notify_fnc)(ASSUAN_CONTEXT, const char *);
|
||||
|
||||
int input_fd; /* set by INPUT command */
|
||||
int output_fd; /* set by OUTPUT command */
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*-- assuan-pipe-server.c --*/
|
||||
int _assuan_new_context (ASSUAN_CONTEXT *r_ctx);
|
||||
void _assuan_release_context (ASSUAN_CONTEXT ctx);
|
||||
|
||||
|
||||
/*-- assuan-handler.c --*/
|
||||
int _assuan_register_std_commands (ASSUAN_CONTEXT ctx);
|
||||
|
||||
/*-- assuan-buffer.c --*/
|
||||
int _assuan_read_line (ASSUAN_CONTEXT ctx);
|
||||
int _assuan_cookie_write_data (void *cookie, const char *buffer, size_t size);
|
||||
int _assuan_cookie_write_flush (void *cookie);
|
||||
|
||||
/*-- assuan-client.c --*/
|
||||
AssuanError _assuan_read_from_server (ASSUAN_CONTEXT ctx, int *okay, int *off);
|
||||
|
||||
|
||||
/*-- assuan-util.c --*/
|
||||
extern ssize_t (*_assuan_read_wrapper)(int,void*,size_t);
|
||||
extern ssize_t (*_assuan_write_wrapper)(int,const void*,size_t);
|
||||
|
||||
void *_assuan_malloc (size_t n);
|
||||
void *_assuan_calloc (size_t n, size_t m);
|
||||
void *_assuan_realloc (void *p, size_t n);
|
||||
void _assuan_free (void *p);
|
||||
|
||||
#define xtrymalloc(a) _assuan_malloc ((a))
|
||||
#define xtrycalloc(a,b) _assuan_calloc ((a),(b))
|
||||
#define xtryrealloc(a,b) _assuan_realloc((a),(b))
|
||||
#define xfree(a) _assuan_free ((a))
|
||||
|
||||
#define set_error(c,e,t) assuan_set_error ((c), ASSUAN_ ## e, (t))
|
||||
|
||||
void _assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length);
|
||||
void _assuan_log_sanitized_string (const char *string);
|
||||
|
||||
|
||||
#endif /*ASSUAN_DEFS_H*/
|
||||
|
@ -1,708 +0,0 @@
|
||||
/* assuan-handler.c - dispatch commands
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
|
||||
#define digitp(a) ((a) >= '0' && (a) <= '9')
|
||||
|
||||
|
||||
#if !HAVE_FOPENCOOKIE
|
||||
/* Provide structure for our dummy replacement function. Usually this
|
||||
is defined in ../common/util.h but assuan should be self
|
||||
contained. */
|
||||
/* Fixme: Remove fopencoookie :-(( */
|
||||
typedef struct
|
||||
{
|
||||
ssize_t (*read)(void*,char*,size_t);
|
||||
ssize_t (*write)(void*,const char*,size_t);
|
||||
int (*seek)(void*,off_t*,int);
|
||||
int (*close)(void*);
|
||||
} _IO_cookie_io_functions_t;
|
||||
typedef _IO_cookie_io_functions_t cookie_io_functions_t;
|
||||
FILE *fopencookie (void *cookie, const char *opentype,
|
||||
cookie_io_functions_t funclist);
|
||||
#endif /*!HAVE_FOPENCOOKIE*/
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
dummy_handler (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
return set_error (ctx, Server_Fault, "no handler registered");
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
std_handler_nop (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
return 0; /* okay */
|
||||
}
|
||||
|
||||
static int
|
||||
std_handler_cancel (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
if (ctx->cancel_notify_fnc)
|
||||
ctx->cancel_notify_fnc (ctx);
|
||||
return set_error (ctx, Not_Implemented, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
std_handler_option (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
char *key, *value, *p;
|
||||
|
||||
for (key=line; spacep (key); key++)
|
||||
;
|
||||
if (!*key)
|
||||
return set_error (ctx, Syntax_Error, "argument required");
|
||||
if (*key == '=')
|
||||
return set_error (ctx, Syntax_Error, "no option name given");
|
||||
for (value=key; *value && !spacep (value) && *value != '='; value++)
|
||||
;
|
||||
if (*value)
|
||||
{
|
||||
if (spacep (value))
|
||||
*value++ = 0; /* terminate key */
|
||||
for (; spacep (value); value++)
|
||||
;
|
||||
if (*value == '=')
|
||||
{
|
||||
*value++ = 0; /* terminate key */
|
||||
for (; spacep (value); value++)
|
||||
;
|
||||
if (!*value)
|
||||
return set_error (ctx, Syntax_Error, "option argument expected");
|
||||
}
|
||||
if (*value)
|
||||
{
|
||||
for (p = value + strlen(value) - 1; p > value && spacep (p); p--)
|
||||
;
|
||||
if (p > value)
|
||||
*++p = 0; /* strip trailing spaces */
|
||||
}
|
||||
}
|
||||
|
||||
if (*key == '-' && key[1] == '-' && key[2])
|
||||
key += 2; /* the double dashes are optional */
|
||||
if (*key == '-')
|
||||
return set_error (ctx, Syntax_Error,
|
||||
"option should not begin with one dash");
|
||||
|
||||
if (ctx->option_handler_fnc)
|
||||
return ctx->option_handler_fnc (ctx, key, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
std_handler_bye (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
if (ctx->bye_notify_fnc)
|
||||
ctx->bye_notify_fnc (ctx);
|
||||
assuan_close_input_fd (ctx);
|
||||
assuan_close_output_fd (ctx);
|
||||
return -1; /* pretty simple :-) */
|
||||
}
|
||||
|
||||
static int
|
||||
std_handler_auth (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
return set_error (ctx, Not_Implemented, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
std_handler_reset (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
if (ctx->reset_notify_fnc)
|
||||
ctx->reset_notify_fnc (ctx);
|
||||
assuan_close_input_fd (ctx);
|
||||
assuan_close_output_fd (ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
std_handler_end (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
return set_error (ctx, Not_Implemented, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
parse_cmd_input_output (ASSUAN_CONTEXT ctx, char *line, int *rfd)
|
||||
{
|
||||
char *endp;
|
||||
|
||||
if (strncmp (line, "FD=", 3))
|
||||
return set_error (ctx, Syntax_Error, "FD=<n> expected");
|
||||
line += 3;
|
||||
if (!digitp (*line))
|
||||
return set_error (ctx, Syntax_Error, "number required");
|
||||
*rfd = strtoul (line, &endp, 10);
|
||||
/* remove that argument so that a notify handler won't see it */
|
||||
memset (line, ' ', endp? (endp-line):strlen(line));
|
||||
|
||||
if (*rfd == ctx->inbound.fd)
|
||||
return set_error (ctx, Parameter_Conflict, "fd same as inbound fd");
|
||||
if (*rfd == ctx->outbound.fd)
|
||||
return set_error (ctx, Parameter_Conflict, "fd same as outbound fd");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Format is INPUT FD=<n> */
|
||||
static int
|
||||
std_handler_input (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
int rc, fd;
|
||||
|
||||
rc = parse_cmd_input_output (ctx, line, &fd);
|
||||
if (rc)
|
||||
return rc;
|
||||
ctx->input_fd = fd;
|
||||
if (ctx->input_notify_fnc)
|
||||
ctx->input_notify_fnc (ctx, line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Format is OUTPUT FD=<n> */
|
||||
static int
|
||||
std_handler_output (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
int rc, fd;
|
||||
|
||||
rc = parse_cmd_input_output (ctx, line, &fd);
|
||||
if (rc)
|
||||
return rc;
|
||||
ctx->output_fd = fd;
|
||||
if (ctx->output_notify_fnc)
|
||||
ctx->output_notify_fnc (ctx, line);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* This is a table with the standard commands and handler for them.
|
||||
The table is used to initialize a new context and assuciate strings
|
||||
and handlers with cmd_ids */
|
||||
static struct {
|
||||
const char *name;
|
||||
int cmd_id;
|
||||
int (*handler)(ASSUAN_CONTEXT, char *line);
|
||||
int always; /* always initialize this command */
|
||||
} std_cmd_table[] = {
|
||||
{ "NOP", ASSUAN_CMD_NOP, std_handler_nop, 1 },
|
||||
{ "CANCEL", ASSUAN_CMD_CANCEL, std_handler_cancel, 1 },
|
||||
{ "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
|
||||
{ "BYE", ASSUAN_CMD_BYE, std_handler_bye, 1 },
|
||||
{ "AUTH", ASSUAN_CMD_AUTH, std_handler_auth, 1 },
|
||||
{ "RESET", ASSUAN_CMD_RESET, std_handler_reset, 1 },
|
||||
{ "END", ASSUAN_CMD_END, std_handler_end, 1 },
|
||||
|
||||
{ "INPUT", ASSUAN_CMD_INPUT, std_handler_input },
|
||||
{ "OUTPUT", ASSUAN_CMD_OUTPUT, std_handler_output },
|
||||
{ "OPTION", ASSUAN_CMD_OPTION, std_handler_option, 1 },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* assuan_register_command:
|
||||
* @ctx: the server context
|
||||
* @cmd_id: An ID value for the command
|
||||
* @cmd_name: A string with the command name
|
||||
* @handler: The handler function to be called
|
||||
*
|
||||
* Register a handler to be used for a given command.
|
||||
*
|
||||
* The @cmd_name must be %NULL or an empty string for all @cmd_ids
|
||||
* below %ASSUAN_CMD_USER because predefined values are used.
|
||||
*
|
||||
* Return value:
|
||||
**/
|
||||
int
|
||||
assuan_register_command (ASSUAN_CONTEXT ctx,
|
||||
int cmd_id, const char *cmd_name,
|
||||
int (*handler)(ASSUAN_CONTEXT, char *))
|
||||
{
|
||||
int i;
|
||||
|
||||
if (cmd_name && !*cmd_name)
|
||||
cmd_name = NULL;
|
||||
|
||||
if (cmd_id < ASSUAN_CMD_USER)
|
||||
{
|
||||
if (cmd_name)
|
||||
return ASSUAN_Invalid_Value; /* must be NULL for these values*/
|
||||
|
||||
for (i=0; std_cmd_table[i].name; i++)
|
||||
{
|
||||
if (std_cmd_table[i].cmd_id == cmd_id)
|
||||
{
|
||||
cmd_name = std_cmd_table[i].name;
|
||||
if (!handler)
|
||||
handler = std_cmd_table[i].handler;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!std_cmd_table[i].name)
|
||||
return ASSUAN_Invalid_Value; /* not a pre-registered one */
|
||||
}
|
||||
|
||||
if (!handler)
|
||||
handler = dummy_handler;
|
||||
|
||||
if (!cmd_name)
|
||||
return ASSUAN_Invalid_Value;
|
||||
|
||||
/* fprintf (stderr, "DBG-assuan: registering %d as `%s'\n", cmd_id, cmd_name); */
|
||||
|
||||
if (!ctx->cmdtbl)
|
||||
{
|
||||
ctx->cmdtbl_size = 50;
|
||||
ctx->cmdtbl = xtrycalloc ( ctx->cmdtbl_size, sizeof *ctx->cmdtbl);
|
||||
if (!ctx->cmdtbl)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
ctx->cmdtbl_used = 0;
|
||||
}
|
||||
else if (ctx->cmdtbl_used >= ctx->cmdtbl_size)
|
||||
{
|
||||
struct cmdtbl_s *x;
|
||||
|
||||
x = xtryrealloc ( ctx->cmdtbl, (ctx->cmdtbl_size+10) * sizeof *x);
|
||||
if (!x)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
ctx->cmdtbl = x;
|
||||
ctx->cmdtbl_size += 50;
|
||||
}
|
||||
|
||||
ctx->cmdtbl[ctx->cmdtbl_used].name = cmd_name;
|
||||
ctx->cmdtbl[ctx->cmdtbl_used].cmd_id = cmd_id;
|
||||
ctx->cmdtbl[ctx->cmdtbl_used].handler = handler;
|
||||
ctx->cmdtbl_used++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
assuan_register_bye_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
ctx->bye_notify_fnc = fnc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
assuan_register_reset_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
ctx->reset_notify_fnc = fnc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
assuan_register_cancel_notify (ASSUAN_CONTEXT ctx, void (*fnc)(ASSUAN_CONTEXT))
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
ctx->cancel_notify_fnc = fnc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
assuan_register_option_handler (ASSUAN_CONTEXT ctx,
|
||||
int (*fnc)(ASSUAN_CONTEXT,
|
||||
const char*, const char*))
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
ctx->option_handler_fnc = fnc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
assuan_register_input_notify (ASSUAN_CONTEXT ctx,
|
||||
void (*fnc)(ASSUAN_CONTEXT, const char *))
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
ctx->input_notify_fnc = fnc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
assuan_register_output_notify (ASSUAN_CONTEXT ctx,
|
||||
void (*fnc)(ASSUAN_CONTEXT, const char *))
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
ctx->output_notify_fnc = fnc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Helper to register the standards commands */
|
||||
int
|
||||
_assuan_register_std_commands (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
for (i=0; std_cmd_table[i].name; i++)
|
||||
{
|
||||
if (std_cmd_table[i].always)
|
||||
{
|
||||
rc = assuan_register_command (ctx, std_cmd_table[i].cmd_id,
|
||||
NULL, NULL);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Process the special data lines. The "D " has already been removed
|
||||
from the line. As all handlers this function may modify the line. */
|
||||
static int
|
||||
handle_data_line (ASSUAN_CONTEXT ctx, char *line, int linelen)
|
||||
{
|
||||
return set_error (ctx, Not_Implemented, NULL);
|
||||
}
|
||||
|
||||
/* like ascii_strcasecmp but assume that B is already uppercase */
|
||||
static int
|
||||
my_strcasecmp (const char *a, const char *b)
|
||||
{
|
||||
if (a == b)
|
||||
return 0;
|
||||
|
||||
for (; *a && *b; a++, b++)
|
||||
{
|
||||
if (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) != *b)
|
||||
break;
|
||||
}
|
||||
return *a == *b? 0 : (((*a >= 'a' && *a <= 'z')? (*a&~0x20):*a) - *b);
|
||||
}
|
||||
|
||||
/* Parse the line, break out the command, find it in the command
|
||||
table, remove leading and white spaces from the arguments, all the
|
||||
handler with the argument line and return the error */
|
||||
static int
|
||||
dispatch_command (ASSUAN_CONTEXT ctx, char *line, int linelen)
|
||||
{
|
||||
char *p;
|
||||
const char *s;
|
||||
int shift, i;
|
||||
|
||||
if (*line == 'D' && line[1] == ' ') /* divert to special handler */
|
||||
return handle_data_line (ctx, line+2, linelen-2);
|
||||
|
||||
for (p=line; *p && *p != ' ' && *p != '\t'; p++)
|
||||
;
|
||||
if (p==line)
|
||||
return set_error (ctx, Invalid_Command, "leading white-space");
|
||||
if (*p)
|
||||
{ /* Skip over leading WS after the keyword */
|
||||
*p++ = 0;
|
||||
while ( *p == ' ' || *p == '\t')
|
||||
p++;
|
||||
}
|
||||
shift = p - line;
|
||||
|
||||
for (i=0; (s=ctx->cmdtbl[i].name); i++)
|
||||
{
|
||||
if (!strcmp (line, s))
|
||||
break;
|
||||
}
|
||||
if (!s)
|
||||
{ /* and try case insensitive */
|
||||
for (i=0; (s=ctx->cmdtbl[i].name); i++)
|
||||
{
|
||||
if (!my_strcasecmp (line, s))
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!s)
|
||||
return set_error (ctx, Unknown_Command, NULL);
|
||||
line += shift;
|
||||
linelen -= shift;
|
||||
|
||||
/* fprintf (stderr, "DBG-assuan: processing %s `%s'\n", s, line); */
|
||||
return ctx->cmdtbl[i].handler (ctx, line);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
process_request (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (ctx->in_inquire)
|
||||
return ASSUAN_Nested_Commands;
|
||||
|
||||
rc = _assuan_read_line (ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
if (*ctx->inbound.line == '#' || !ctx->inbound.linelen)
|
||||
return 0; /* comment line - ignore */
|
||||
|
||||
ctx->outbound.data.error = 0;
|
||||
ctx->outbound.data.linelen = 0;
|
||||
/* dispatch command and return reply */
|
||||
rc = dispatch_command (ctx, ctx->inbound.line, ctx->inbound.linelen);
|
||||
/* check from data write errors */
|
||||
if (ctx->outbound.data.fp)
|
||||
{ /* Flush the data lines */
|
||||
fclose (ctx->outbound.data.fp);
|
||||
ctx->outbound.data.fp = NULL;
|
||||
if (!rc && ctx->outbound.data.error)
|
||||
rc = ctx->outbound.data.error;
|
||||
}
|
||||
else /* flush any data send w/o using the data fp */
|
||||
{
|
||||
assuan_send_data (ctx, NULL, 0);
|
||||
if (!rc && ctx->outbound.data.error)
|
||||
rc = ctx->outbound.data.error;
|
||||
}
|
||||
/* Error handling */
|
||||
if (!rc)
|
||||
{
|
||||
rc = assuan_write_line (ctx, ctx->okay_line? ctx->okay_line : "OK");
|
||||
}
|
||||
else if (rc == -1)
|
||||
{ /* No error checking because the peer may have already disconnect */
|
||||
assuan_write_line (ctx, "OK closing connection");
|
||||
ctx->finish_handler (ctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
char errline[256];
|
||||
|
||||
if (rc < 100)
|
||||
sprintf (errline, "ERR %d server fault (%.50s)",
|
||||
ASSUAN_Server_Fault, assuan_strerror (rc));
|
||||
else
|
||||
{
|
||||
const char *text = ctx->err_no == rc? ctx->err_str:NULL;
|
||||
|
||||
sprintf (errline, "ERR %d %.50s%s%.100s",
|
||||
rc, assuan_strerror (rc), text? " - ":"", text?text:"");
|
||||
}
|
||||
rc = assuan_write_line (ctx, errline);
|
||||
}
|
||||
|
||||
ctx->confidential = 0;
|
||||
if (ctx->okay_line)
|
||||
{
|
||||
xfree (ctx->okay_line);
|
||||
ctx->okay_line = NULL;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* assuan_process:
|
||||
* @ctx: assuan context
|
||||
*
|
||||
* This fucntion is used to handle the assuan protocol after a
|
||||
* connection has been established using assuan_accept(). This is the
|
||||
* main protocol handler.
|
||||
*
|
||||
* Return value: 0 on success or an error code if the assuan operation
|
||||
* failed. Note, that no error is returned for operational errors.
|
||||
**/
|
||||
int
|
||||
assuan_process (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
do {
|
||||
rc = process_request (ctx);
|
||||
} while (!rc);
|
||||
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* assuan_process_next:
|
||||
* @ctx: Assuan context
|
||||
*
|
||||
* Same as assuan_process() but the user has to provide the outer
|
||||
* loop. He should loop as long as the return code is zero and stop
|
||||
* otherwise; -1 is regular end.
|
||||
*
|
||||
* See also: assuan_get_active_fds()
|
||||
* Return value: -1 for end of server, 0 on success or an error code
|
||||
**/
|
||||
int
|
||||
assuan_process_next (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
return process_request (ctx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* assuan_get_active_fds:
|
||||
* @ctx: Assuan context
|
||||
* @what: 0 for read fds, 1 for write fds
|
||||
* @fdarray: Caller supplied array to store the FDs
|
||||
* @fdarraysize: size of that array
|
||||
*
|
||||
* Return all active filedescriptors for the given context. This
|
||||
* function can be used to select on the fds and call
|
||||
* assuan_process_next() if there is an active one. The first fd in
|
||||
* the array is the one used for the command connection.
|
||||
*
|
||||
* Note, that write FDs are not yet supported.
|
||||
*
|
||||
* Return value: number of FDs active and put into @fdarray or -1 on
|
||||
* error which is most likely a too small fdarray.
|
||||
**/
|
||||
int
|
||||
assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
|
||||
int *fdarray, int fdarraysize)
|
||||
{
|
||||
int n = 0;
|
||||
|
||||
if (!ctx || fdarraysize < 2 || what < 0 || what > 1)
|
||||
return -1;
|
||||
|
||||
if (!what)
|
||||
{
|
||||
if (ctx->inbound.fd != -1)
|
||||
fdarray[n++] = ctx->inbound.fd;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ctx->outbound.fd != -1)
|
||||
fdarray[n++] = ctx->outbound.fd;
|
||||
if (ctx->outbound.data.fp)
|
||||
fdarray[n++] = fileno (ctx->outbound.data.fp);
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Return a FP to be used for data output. The FILE pointer is valid
|
||||
until the end of a handler. So a close is not needed. Assuan does
|
||||
all the buffering needed to insert the status line as well as the
|
||||
required line wappping and quoting for data lines.
|
||||
|
||||
We use GNU's custom streams here. There should be an alternative
|
||||
implementaion for systems w/o a glibc, a simple implementation
|
||||
could use a child process */
|
||||
FILE *
|
||||
assuan_get_data_fp (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
cookie_io_functions_t cookie_fnc;
|
||||
|
||||
if (ctx->outbound.data.fp)
|
||||
return ctx->outbound.data.fp;
|
||||
|
||||
cookie_fnc.read = NULL;
|
||||
cookie_fnc.write = _assuan_cookie_write_data;
|
||||
cookie_fnc.seek = NULL;
|
||||
cookie_fnc.close = _assuan_cookie_write_flush;
|
||||
|
||||
ctx->outbound.data.fp = fopencookie (ctx, "wb", cookie_fnc);
|
||||
ctx->outbound.data.error = 0;
|
||||
return ctx->outbound.data.fp;
|
||||
}
|
||||
|
||||
|
||||
/* Set the text used for the next OK reponse. This string is
|
||||
automatically reset to NULL after the next command. */
|
||||
AssuanError
|
||||
assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line)
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
if (!line)
|
||||
{
|
||||
xfree (ctx->okay_line);
|
||||
ctx->okay_line = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* FIXME: we need to use gcry_is_secure() to test whether
|
||||
we should allocate the entire line in secure memory */
|
||||
char *buf = xtrymalloc (3+strlen(line)+1);
|
||||
if (!buf)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
strcpy (buf, "OK ");
|
||||
strcpy (buf+3, line);
|
||||
xfree (ctx->okay_line);
|
||||
ctx->okay_line = buf;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
assuan_write_status (ASSUAN_CONTEXT ctx, const char *keyword, const char *text)
|
||||
{
|
||||
char buffer[256];
|
||||
char *helpbuf;
|
||||
size_t n;
|
||||
|
||||
if ( !ctx || !keyword)
|
||||
return;
|
||||
if (!text)
|
||||
text = "";
|
||||
|
||||
n = 2 + strlen (keyword) + 1 + strlen (text) + 1;
|
||||
if (n < sizeof (buffer))
|
||||
{
|
||||
strcpy (buffer, "S ");
|
||||
strcat (buffer, keyword);
|
||||
if (*text)
|
||||
{
|
||||
strcat (buffer, " ");
|
||||
strcat (buffer, text);
|
||||
}
|
||||
assuan_write_line (ctx, buffer);
|
||||
}
|
||||
else if ( (helpbuf = xtrymalloc (n)) )
|
||||
{
|
||||
strcpy (helpbuf, "S ");
|
||||
strcat (helpbuf, keyword);
|
||||
if (*text)
|
||||
{
|
||||
strcat (helpbuf, " ");
|
||||
strcat (helpbuf, text);
|
||||
}
|
||||
assuan_write_line (ctx, helpbuf);
|
||||
xfree (helpbuf);
|
||||
}
|
||||
}
|
@ -1,239 +0,0 @@
|
||||
/* assuan-inquire.c - handle inquire stuff
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
#define digitp(a) ((a) >= '0' && (a) <= '9')
|
||||
#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))
|
||||
|
||||
|
||||
struct membuf {
|
||||
size_t len;
|
||||
size_t size;
|
||||
char *buf;
|
||||
int out_of_core;
|
||||
int too_large;
|
||||
size_t maxlen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* A simple implemnation 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, size_t maxlen)
|
||||
{
|
||||
mb->len = 0;
|
||||
mb->size = initiallen;
|
||||
mb->out_of_core = 0;
|
||||
mb->too_large = 0;
|
||||
mb->maxlen = maxlen;
|
||||
/* we need to allocate one byte more for get_membuf */
|
||||
mb->buf = xtrymalloc (initiallen+1);
|
||||
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 || mb->too_large)
|
||||
return;
|
||||
|
||||
if (mb->maxlen && mb->len + len > mb->maxlen)
|
||||
{
|
||||
mb->too_large = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (mb->len + len >= mb->size)
|
||||
{
|
||||
char *p;
|
||||
|
||||
mb->size += len + 1024;
|
||||
/* we need to allocate one byte more for get_membuf */
|
||||
p = xtryrealloc (mb->buf, mb->size+1);
|
||||
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 || mb->too_large)
|
||||
{
|
||||
xfree (mb->buf);
|
||||
mb->buf = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mb->buf[mb->len] = 0; /* there is enough space for the hidden eos */
|
||||
p = mb->buf;
|
||||
*len = mb->len;
|
||||
mb->buf = NULL;
|
||||
mb->out_of_core = 1; /* don't allow a reuse */
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
free_membuf (struct membuf *mb)
|
||||
{
|
||||
xfree (mb->buf);
|
||||
mb->buf = NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* assuan_inquire:
|
||||
* @ctx: An assuan context
|
||||
* @keyword: The keyword used for the inquire
|
||||
* @r_buffer: Returns an allocated buffer
|
||||
* @r_length: Returns the length of this buffer
|
||||
* @maxlen: If not 0, the size limit of the inquired data.
|
||||
*
|
||||
* A Server may use this to Send an inquire. r_buffer, r_length and
|
||||
* maxlen may all be NULL/0 to indicate that no real data is expected.
|
||||
*
|
||||
* Return value: 0 on success or an ASSUAN error code
|
||||
**/
|
||||
AssuanError
|
||||
assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
|
||||
char **r_buffer, size_t *r_length, size_t maxlen)
|
||||
{
|
||||
AssuanError rc;
|
||||
struct membuf mb;
|
||||
char cmdbuf[100];
|
||||
unsigned char *line, *p;
|
||||
int linelen;
|
||||
int nodataexpected;
|
||||
|
||||
if (!ctx || !keyword || (10 + strlen (keyword) >= sizeof (cmdbuf)))
|
||||
return ASSUAN_Invalid_Value;
|
||||
nodataexpected = !r_buffer && !r_length && !maxlen;
|
||||
if (!nodataexpected && (!r_buffer || !r_length))
|
||||
return ASSUAN_Invalid_Value;
|
||||
if (!ctx->is_server)
|
||||
return ASSUAN_Not_A_Server;
|
||||
if (ctx->in_inquire)
|
||||
return ASSUAN_Nested_Commands;
|
||||
|
||||
ctx->in_inquire = 1;
|
||||
if (nodataexpected)
|
||||
memset (&mb, 0, sizeof mb); /* avoid compiler warnings */
|
||||
else
|
||||
init_membuf (&mb, maxlen? maxlen:1024, maxlen);
|
||||
|
||||
strcpy (stpcpy (cmdbuf, "INQUIRE "), keyword);
|
||||
rc = assuan_write_line (ctx, cmdbuf);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
do
|
||||
{
|
||||
rc = _assuan_read_line (ctx);
|
||||
if (rc)
|
||||
goto leave;
|
||||
line = ctx->inbound.line;
|
||||
linelen = ctx->inbound.linelen;
|
||||
}
|
||||
while (*line == '#' || !linelen);
|
||||
if (line[0] == 'E' && line[1] == 'N' && line[2] == 'D'
|
||||
&& (!line[3] || line[3] == ' '))
|
||||
break; /* END command received*/
|
||||
if (line[0] == 'C' && line[1] == 'A' && line[2] == 'N')
|
||||
{
|
||||
rc = ASSUAN_Canceled;
|
||||
goto leave;
|
||||
}
|
||||
if (line[0] != 'D' || line[1] != ' ' || nodataexpected)
|
||||
{
|
||||
rc = ASSUAN_Unexpected_Command;
|
||||
goto leave;
|
||||
}
|
||||
if (linelen < 3)
|
||||
continue;
|
||||
line += 2;
|
||||
linelen -= 2;
|
||||
|
||||
p = line;
|
||||
while (linelen)
|
||||
{
|
||||
for (;linelen && *p != '%'; linelen--, p++)
|
||||
;
|
||||
put_membuf (&mb, line, p-line);
|
||||
if (linelen > 2)
|
||||
{ /* handle escaping */
|
||||
unsigned char tmp[1];
|
||||
p++;
|
||||
*tmp = xtoi_2 (p);
|
||||
p += 2;
|
||||
linelen -= 3;
|
||||
put_membuf (&mb, tmp, 1);
|
||||
}
|
||||
line = p;
|
||||
}
|
||||
if (mb.too_large)
|
||||
{
|
||||
rc = ASSUAN_Too_Much_Data;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
if (!nodataexpected)
|
||||
{
|
||||
*r_buffer = get_membuf (&mb, r_length);
|
||||
if (!*r_buffer)
|
||||
rc = ASSUAN_Out_Of_Core;
|
||||
}
|
||||
|
||||
leave:
|
||||
if (!nodataexpected)
|
||||
free_membuf (&mb);
|
||||
ctx->in_inquire = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,132 +0,0 @@
|
||||
/* assuan-listen.c - Wait for a connection (server)
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
AssuanError
|
||||
assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line)
|
||||
{
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
if (!line)
|
||||
{
|
||||
xfree (ctx->hello_line);
|
||||
ctx->hello_line = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
char *buf = xtrymalloc (3+strlen(line)+1);
|
||||
if (!buf)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
strcpy (buf, "OK ");
|
||||
strcpy (buf+3, line);
|
||||
xfree (ctx->hello_line);
|
||||
ctx->hello_line = buf;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* assuan_accept:
|
||||
* @ctx: context
|
||||
*
|
||||
* Cancel any existing connectiion and wait for a connection from a
|
||||
* client. The initial handshake is performed which may include an
|
||||
* initial authentication or encryption negotiation.
|
||||
*
|
||||
* Return value: 0 on success or an error if the connection could for
|
||||
* some reason not be established.
|
||||
**/
|
||||
AssuanError
|
||||
assuan_accept (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!ctx)
|
||||
return ASSUAN_Invalid_Value;
|
||||
|
||||
if (ctx->pipe_mode > 1)
|
||||
return -1; /* second invocation for pipemode -> terminate */
|
||||
ctx->finish_handler (ctx);
|
||||
|
||||
rc = ctx->accept_handler (ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* send the hello */
|
||||
rc = assuan_write_line (ctx, ctx->hello_line? ctx->hello_line
|
||||
: "OK Your orders please");
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (ctx->pipe_mode)
|
||||
ctx->pipe_mode = 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
assuan_get_input_fd (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
return ctx? ctx->input_fd : -1;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
assuan_get_output_fd (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
return ctx? ctx->output_fd : -1;
|
||||
}
|
||||
|
||||
|
||||
/* Close the fd descriptor set by the command INPUT FD=n. We handle
|
||||
this fd inside assuan so that we can do some initial checks */
|
||||
AssuanError
|
||||
assuan_close_input_fd (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (!ctx || ctx->input_fd == -1)
|
||||
return ASSUAN_Invalid_Value;
|
||||
close (ctx->input_fd);
|
||||
ctx->input_fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Close the fd descriptor set by the command OUTPUT FD=n. We handle
|
||||
this fd inside assuan so that we can do some initial checks */
|
||||
AssuanError
|
||||
assuan_close_output_fd (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (!ctx || ctx->output_fd == -1)
|
||||
return ASSUAN_Invalid_Value;
|
||||
|
||||
close (ctx->output_fd);
|
||||
ctx->output_fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,288 +0,0 @@
|
||||
/* assuan-pipe-connect.c - Establish a pipe connection (client)
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
#ifdef _POSIX_OPEN_MAX
|
||||
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
|
||||
#else
|
||||
#define MAX_OPEN_FDS 20
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_JNLIB_LOGGING
|
||||
#include "../jnlib/logging.h"
|
||||
#define LOGERROR1(a,b) log_error ((a), (b))
|
||||
#else
|
||||
#define LOGERROR1(a,b) fprintf (stderr, (a), (b))
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static int
|
||||
writen ( int fd, const char *buffer, size_t length )
|
||||
{
|
||||
while (length)
|
||||
{
|
||||
int nwritten = write (fd, buffer, length);
|
||||
|
||||
if (nwritten < 0)
|
||||
{
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
return -1; /* write error */
|
||||
}
|
||||
length -= nwritten;
|
||||
buffer += nwritten;
|
||||
}
|
||||
return 0; /* okay */
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
do_finish (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (ctx->inbound.fd != -1)
|
||||
{
|
||||
close (ctx->inbound.fd);
|
||||
ctx->inbound.fd = -1;
|
||||
}
|
||||
if (ctx->outbound.fd != -1)
|
||||
{
|
||||
close (ctx->outbound.fd);
|
||||
ctx->outbound.fd = -1;
|
||||
}
|
||||
if (ctx->pid != -1)
|
||||
{
|
||||
waitpid (ctx->pid, NULL, 0); /* FIXME Check return value. */
|
||||
ctx->pid = -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
do_deinit (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
do_finish (ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Connect to a server over a pipe, creating the assuan context and
|
||||
returning it in CTX. The server filename is NAME, the argument
|
||||
vector in ARGV. FD_CHILD_LIST is a -1 terminated list of file
|
||||
descriptors not to close in the child. */
|
||||
AssuanError
|
||||
assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name, char *const argv[],
|
||||
int *fd_child_list)
|
||||
{
|
||||
static int fixed_signals = 0;
|
||||
AssuanError err;
|
||||
int rp[2];
|
||||
int wp[2];
|
||||
|
||||
if (!ctx || !name || !argv || !argv[0])
|
||||
return ASSUAN_Invalid_Value;
|
||||
|
||||
if (!fixed_signals)
|
||||
{
|
||||
struct sigaction act;
|
||||
|
||||
sigaction (SIGPIPE, NULL, &act);
|
||||
if (act.sa_handler == SIG_DFL)
|
||||
{
|
||||
act.sa_handler = SIG_IGN;
|
||||
sigemptyset (&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction (SIGPIPE, &act, NULL);
|
||||
}
|
||||
fixed_signals = 1;
|
||||
/* FIXME: This is not MT safe */
|
||||
}
|
||||
|
||||
if (pipe (rp) < 0)
|
||||
return ASSUAN_General_Error;
|
||||
|
||||
if (pipe (wp) < 0)
|
||||
{
|
||||
close (rp[0]);
|
||||
close (rp[1]);
|
||||
return ASSUAN_General_Error;
|
||||
}
|
||||
|
||||
err = _assuan_new_context (ctx);
|
||||
if (err)
|
||||
{
|
||||
close (rp[0]);
|
||||
close (rp[1]);
|
||||
close (wp[0]);
|
||||
close (wp[1]);
|
||||
return err;
|
||||
}
|
||||
(*ctx)->pipe_mode = 1;
|
||||
(*ctx)->inbound.fd = rp[0]; /* Our inbound is read end of read pipe. */
|
||||
(*ctx)->outbound.fd = wp[1]; /* Our outbound is write end of write pipe. */
|
||||
(*ctx)->deinit_handler = do_deinit;
|
||||
(*ctx)->finish_handler = do_finish;
|
||||
|
||||
(*ctx)->pid = fork ();
|
||||
if ((*ctx)->pid < 0)
|
||||
{
|
||||
close (rp[0]);
|
||||
close (rp[1]);
|
||||
close (wp[0]);
|
||||
close (wp[1]);
|
||||
_assuan_release_context (*ctx);
|
||||
return ASSUAN_General_Error;
|
||||
}
|
||||
|
||||
if ((*ctx)->pid == 0)
|
||||
{
|
||||
int i, n;
|
||||
char errbuf[512];
|
||||
int *fdp;
|
||||
|
||||
/* Close all files which will not be duped and are not in the
|
||||
fd_child_list. */
|
||||
n = sysconf (_SC_OPEN_MAX);
|
||||
if (n < 0)
|
||||
n = MAX_OPEN_FDS;
|
||||
for (i=0; i < n; i++)
|
||||
{
|
||||
fdp = fd_child_list;
|
||||
if (fdp)
|
||||
{
|
||||
while (*fdp != -1 && *fdp != i)
|
||||
fdp++;
|
||||
}
|
||||
|
||||
if (!(fdp && *fdp != -1)
|
||||
&& i != rp[1] && i != wp[0])
|
||||
close(i);
|
||||
}
|
||||
errno = 0;
|
||||
|
||||
/* Dup stderr to /dev/null unless it is in the list of FDs to be
|
||||
passed to the child. */
|
||||
fdp = fd_child_list;
|
||||
if (fdp)
|
||||
{
|
||||
for (; *fdp != -1 && *fdp != STDERR_FILENO; fdp++)
|
||||
;
|
||||
}
|
||||
if (!fdp || *fdp == -1)
|
||||
{
|
||||
int fd = open ("/dev/null", O_WRONLY);
|
||||
if (fd == -1)
|
||||
{
|
||||
LOGERROR1 ("can't open `/dev/null': %s\n", strerror (errno));
|
||||
_exit (4);
|
||||
}
|
||||
if (dup2 (fd, STDERR_FILENO) == -1)
|
||||
{
|
||||
LOGERROR1 ("dup2(dev/null, 2) failed: %s\n", strerror (errno));
|
||||
_exit (4);
|
||||
}
|
||||
close (fd);
|
||||
}
|
||||
|
||||
/* Dup handles and to stdin/stdout and exec. */
|
||||
if (rp[1] != STDOUT_FILENO)
|
||||
{
|
||||
if (dup2 (rp[1], STDOUT_FILENO) == -1)
|
||||
{
|
||||
LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
|
||||
_exit (4);
|
||||
}
|
||||
close (rp[1]);
|
||||
}
|
||||
if (wp[0] != STDIN_FILENO)
|
||||
{
|
||||
if (dup2 (wp[0], STDIN_FILENO) == -1)
|
||||
{
|
||||
LOGERROR1 ("dup2 failed in child: %s\n", strerror (errno));
|
||||
_exit (4);
|
||||
}
|
||||
close (wp[0]);
|
||||
}
|
||||
|
||||
execv (name, argv);
|
||||
/* oops - use the pipe to tell the parent about it */
|
||||
snprintf (errbuf, sizeof(errbuf)-1, "ERR %d can't exec `%s': %.50s\n",
|
||||
ASSUAN_Problem_Starting_Server, name, strerror (errno));
|
||||
errbuf[sizeof(errbuf)-1] = 0;
|
||||
writen (1, errbuf, strlen (errbuf));
|
||||
_exit (4);
|
||||
}
|
||||
|
||||
close (rp[1]);
|
||||
close (wp[0]);
|
||||
|
||||
/* initial handshake */
|
||||
{
|
||||
int okay, off;
|
||||
|
||||
err = _assuan_read_from_server (*ctx, &okay, &off);
|
||||
if (err)
|
||||
{
|
||||
LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
|
||||
}
|
||||
else if (okay != 1)
|
||||
{
|
||||
LOGERROR1 ("can't connect server: `%s'\n", (*ctx)->inbound.line);
|
||||
err = ASSUAN_Connect_Failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
assuan_disconnect (*ctx);
|
||||
*ctx = NULL;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,124 +0,0 @@
|
||||
/* assuan-pipe-server.c - Assuan server working over a pipe
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
static void
|
||||
deinit_pipe_server (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
/* nothing to do for this simple server */
|
||||
}
|
||||
|
||||
static int
|
||||
accept_connection (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
/* This is a NOP for a pipe server */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
finish_connection (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
/* This is a NOP for a pipe server */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Create a new context. Note that the handlers are set up for a pipe
|
||||
server/client - this way we don't need extra dummy functions */
|
||||
int
|
||||
_assuan_new_context (ASSUAN_CONTEXT *r_ctx)
|
||||
{
|
||||
ASSUAN_CONTEXT ctx;
|
||||
int rc;
|
||||
|
||||
*r_ctx = NULL;
|
||||
ctx = xtrycalloc (1, sizeof *ctx);
|
||||
if (!ctx)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
ctx->input_fd = -1;
|
||||
ctx->output_fd = -1;
|
||||
|
||||
ctx->inbound.fd = -1;
|
||||
ctx->outbound.fd = -1;
|
||||
|
||||
ctx->listen_fd = -1;
|
||||
ctx->client_pid = (pid_t)-1;
|
||||
/* use the pipe server handler as a default */
|
||||
ctx->deinit_handler = deinit_pipe_server;
|
||||
ctx->accept_handler = accept_connection;
|
||||
ctx->finish_handler = finish_connection;
|
||||
|
||||
rc = _assuan_register_std_commands (ctx);
|
||||
if (rc)
|
||||
xfree (ctx);
|
||||
else
|
||||
*r_ctx = ctx;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2])
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = _assuan_new_context (r_ctx);
|
||||
if (!rc)
|
||||
{
|
||||
ASSUAN_CONTEXT ctx = *r_ctx;
|
||||
|
||||
ctx->is_server = 1;
|
||||
ctx->inbound.fd = filedes[0];
|
||||
ctx->outbound.fd = filedes[1];
|
||||
ctx->pipe_mode = 1;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
_assuan_release_context (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
xfree (ctx->hello_line);
|
||||
xfree (ctx->okay_line);
|
||||
xfree (ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
assuan_deinit_server (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
/* We use this function pointer to avoid linking other server
|
||||
when not needed but still allow for a generic deinit function */
|
||||
ctx->deinit_handler (ctx);
|
||||
ctx->deinit_handler = NULL;
|
||||
_assuan_release_context (ctx);
|
||||
}
|
||||
}
|
@ -1,150 +0,0 @@
|
||||
/* assuan-socket-connect.c - Assuan socket based client
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
#ifdef HAVE_JNLIB_LOGGING
|
||||
#include "../jnlib/logging.h"
|
||||
#define LOGERROR(a) log_error ((a))
|
||||
#define LOGERROR1(a,b) log_error ((a), (b))
|
||||
#define LOGERROR2(a,b,c) log_error ((a), (b), (c))
|
||||
#define LOGERRORX(a) log_printf ((a))
|
||||
#else
|
||||
#define LOGERROR(a) fprintf (stderr, (a))
|
||||
#define LOGERROR1(a,b) fprintf (stderr, (a), (b))
|
||||
#define LOGERROR2(a,b,c) fprintf (stderr, (a), (b), (c))
|
||||
#define LOGERRORX(a) fputs ((a), stderr)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
static int
|
||||
do_finish (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (ctx->inbound.fd != -1)
|
||||
{
|
||||
close (ctx->inbound.fd);
|
||||
}
|
||||
ctx->inbound.fd = -1;
|
||||
ctx->outbound.fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
do_deinit (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
do_finish (ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Make a connection to the Unix domain socket NAME and return a new
|
||||
Assuan context in CTX. SERVER_PID is currently not used but may
|
||||
becode handy in future. */
|
||||
AssuanError
|
||||
assuan_socket_connect (ASSUAN_CONTEXT *r_ctx,
|
||||
const char *name, pid_t server_pid)
|
||||
{
|
||||
AssuanError err;
|
||||
ASSUAN_CONTEXT ctx;
|
||||
int fd;
|
||||
struct sockaddr_un srvr_addr;
|
||||
size_t len;
|
||||
|
||||
if (!r_ctx || !name)
|
||||
return ASSUAN_Invalid_Value;
|
||||
*r_ctx = NULL;
|
||||
|
||||
/* we require that the name starts with a slash, so that we can
|
||||
alter reuse this function for other socket types */
|
||||
if (*name != '/')
|
||||
return ASSUAN_Invalid_Value;
|
||||
if (strlen (name)+1 >= sizeof srvr_addr.sun_path)
|
||||
return ASSUAN_Invalid_Value;
|
||||
|
||||
err = _assuan_new_context (&ctx);
|
||||
if (err)
|
||||
return err;
|
||||
ctx->pid = server_pid; /* save it in case we need it later */
|
||||
ctx->deinit_handler = do_deinit;
|
||||
ctx->finish_handler = do_finish;
|
||||
|
||||
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
{
|
||||
LOGERROR1 ("can't create socket: %s\n", strerror (errno));
|
||||
_assuan_release_context (ctx);
|
||||
return ASSUAN_General_Error;
|
||||
}
|
||||
|
||||
memset (&srvr_addr, 0, sizeof srvr_addr );
|
||||
srvr_addr.sun_family = AF_UNIX;
|
||||
strcpy (srvr_addr.sun_path, name);
|
||||
len = (offsetof (struct sockaddr_un, sun_path)
|
||||
+ strlen (srvr_addr.sun_path) + 1);
|
||||
|
||||
if (connect (fd, (struct sockaddr*)&srvr_addr, len) == -1)
|
||||
{
|
||||
LOGERROR2 ("can't connect to `%s': %s\n", name, strerror (errno));
|
||||
_assuan_release_context (ctx);
|
||||
close (fd );
|
||||
return ASSUAN_Connect_Failed;
|
||||
}
|
||||
|
||||
ctx->inbound.fd = fd;
|
||||
ctx->outbound.fd = fd;
|
||||
|
||||
/* initial handshake */
|
||||
{
|
||||
int okay, off;
|
||||
|
||||
err = _assuan_read_from_server (ctx, &okay, &off);
|
||||
if (err)
|
||||
{
|
||||
LOGERROR1 ("can't connect server: %s\n", assuan_strerror (err));
|
||||
}
|
||||
else if (okay != 1)
|
||||
{
|
||||
LOGERROR ("can't connect server: `");
|
||||
_assuan_log_sanitized_string (ctx->inbound.line);
|
||||
LOGERRORX ("'\n");
|
||||
err = ASSUAN_Connect_Failed;
|
||||
}
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
assuan_disconnect (ctx);
|
||||
}
|
||||
else
|
||||
*r_ctx = ctx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1,169 +0,0 @@
|
||||
/* assuan-socket-server.c - Assuan socket based server
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
static int
|
||||
accept_connection_bottom (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
int fd = ctx->connected_fd;
|
||||
|
||||
ctx->client_pid = (pid_t)-1;
|
||||
#ifdef HAVE_SO_PEERCRED
|
||||
{
|
||||
struct ucred cr;
|
||||
int cl = sizeof cr;
|
||||
|
||||
if ( !getsockopt (fd, SOL_SOCKET, SO_PEERCRED, &cr, &cl) )
|
||||
ctx->client_pid = cr.pid;
|
||||
}
|
||||
#endif
|
||||
|
||||
ctx->inbound.fd = fd;
|
||||
ctx->inbound.eof = 0;
|
||||
ctx->inbound.linelen = 0;
|
||||
ctx->inbound.attic.linelen = 0;
|
||||
ctx->inbound.attic.pending = 0;
|
||||
|
||||
ctx->outbound.fd = fd;
|
||||
ctx->outbound.data.linelen = 0;
|
||||
ctx->outbound.data.error = 0;
|
||||
|
||||
ctx->confidential = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
accept_connection (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
int fd;
|
||||
struct sockaddr_un clnt_addr;
|
||||
size_t len = sizeof clnt_addr;
|
||||
|
||||
ctx->client_pid = (pid_t)-1;
|
||||
fd = accept (ctx->listen_fd, (struct sockaddr*)&clnt_addr, &len );
|
||||
if (fd == -1)
|
||||
{
|
||||
ctx->os_errno = errno;
|
||||
return ASSUAN_Accept_Failed;
|
||||
}
|
||||
|
||||
ctx->connected_fd = fd;
|
||||
return accept_connection_bottom (ctx);
|
||||
}
|
||||
|
||||
static int
|
||||
finish_connection (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (ctx->inbound.fd != -1)
|
||||
{
|
||||
close (ctx->inbound.fd);
|
||||
}
|
||||
ctx->inbound.fd = -1;
|
||||
ctx->outbound.fd = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
deinit_socket_server (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
finish_connection (ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Initialize a server for the socket LISTEN_FD which has already be
|
||||
put into listen mode */
|
||||
int
|
||||
assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd)
|
||||
{
|
||||
ASSUAN_CONTEXT ctx;
|
||||
int rc;
|
||||
|
||||
*r_ctx = NULL;
|
||||
ctx = xtrycalloc (1, sizeof *ctx);
|
||||
if (!ctx)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
ctx->is_server = 1;
|
||||
ctx->input_fd = -1;
|
||||
ctx->output_fd = -1;
|
||||
|
||||
ctx->inbound.fd = -1;
|
||||
ctx->outbound.fd = -1;
|
||||
|
||||
ctx->listen_fd = listen_fd;
|
||||
ctx->connected_fd = -1;
|
||||
ctx->deinit_handler = deinit_socket_server;
|
||||
ctx->accept_handler = accept_connection;
|
||||
ctx->finish_handler = finish_connection;
|
||||
|
||||
rc = _assuan_register_std_commands (ctx);
|
||||
if (rc)
|
||||
xfree (ctx);
|
||||
else
|
||||
*r_ctx = ctx;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Initialize a server using the already accepted socket FD. */
|
||||
int
|
||||
assuan_init_connected_socket_server (ASSUAN_CONTEXT *r_ctx, int fd)
|
||||
{
|
||||
ASSUAN_CONTEXT ctx;
|
||||
int rc;
|
||||
|
||||
*r_ctx = NULL;
|
||||
ctx = xtrycalloc (1, sizeof *ctx);
|
||||
if (!ctx)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
ctx->is_server = 1;
|
||||
ctx->pipe_mode = 1; /* we wan't a second accept to indicate EOF */
|
||||
ctx->input_fd = -1;
|
||||
ctx->output_fd = -1;
|
||||
|
||||
ctx->inbound.fd = -1;
|
||||
ctx->outbound.fd = -1;
|
||||
|
||||
ctx->listen_fd = -1;
|
||||
ctx->connected_fd = fd;
|
||||
ctx->deinit_handler = deinit_socket_server;
|
||||
ctx->accept_handler = accept_connection_bottom;
|
||||
ctx->finish_handler = finish_connection;
|
||||
|
||||
rc = _assuan_register_std_commands (ctx);
|
||||
if (rc)
|
||||
xfree (ctx);
|
||||
else
|
||||
*r_ctx = ctx;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1,210 +0,0 @@
|
||||
/* assuan-util.c - Utility functions for Assuan
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "assuan-defs.h"
|
||||
|
||||
#ifdef HAVE_JNLIB_LOGGING
|
||||
#include "../jnlib/logging.h"
|
||||
#endif
|
||||
|
||||
ssize_t (*_assuan_read_wrapper)(int,void*,size_t) = NULL;
|
||||
ssize_t (*_assuan_write_wrapper)(int,const void*,size_t) = NULL;
|
||||
|
||||
|
||||
static void *(*alloc_func)(size_t n) = malloc;
|
||||
static void *(*realloc_func)(void *p, size_t n) = realloc;
|
||||
static void (*free_func)(void*) = free;
|
||||
|
||||
|
||||
|
||||
void
|
||||
assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
|
||||
void *(*new_realloc_func)(void *p, size_t n),
|
||||
void (*new_free_func)(void*) )
|
||||
{
|
||||
alloc_func = new_alloc_func;
|
||||
realloc_func = new_realloc_func;
|
||||
free_func = new_free_func;
|
||||
}
|
||||
|
||||
void *
|
||||
_assuan_malloc (size_t n)
|
||||
{
|
||||
return alloc_func (n);
|
||||
}
|
||||
|
||||
void *
|
||||
_assuan_realloc (void *a, size_t n)
|
||||
{
|
||||
return realloc_func (a, n);
|
||||
}
|
||||
|
||||
void *
|
||||
_assuan_calloc (size_t n, size_t m)
|
||||
{
|
||||
void *p = _assuan_malloc (n*m);
|
||||
if (p)
|
||||
memset (p, 0, n* m);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
_assuan_free (void *p)
|
||||
{
|
||||
if (p)
|
||||
free_func (p);
|
||||
}
|
||||
|
||||
/* For use with Pth it is required to have special read and write
|
||||
functions. We can't assume an ELF based system so we have to
|
||||
explicitly set them if we are going to use Pth. */
|
||||
void
|
||||
assuan_set_io_func (ssize_t (*r)(int,void*,size_t),
|
||||
ssize_t (*w)(int,const void*,size_t))
|
||||
{
|
||||
_assuan_read_wrapper = r;
|
||||
_assuan_write_wrapper = w;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Store the error in the context so that the error sending function
|
||||
can take out a descriptive text. Inside the assuan code, use the
|
||||
macro set_error instead of this function. */
|
||||
int
|
||||
assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text)
|
||||
{
|
||||
ctx->err_no = err;
|
||||
ctx->err_str = text;
|
||||
return err;
|
||||
}
|
||||
|
||||
void
|
||||
assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer)
|
||||
{
|
||||
if (ctx)
|
||||
ctx->user_pointer = pointer;
|
||||
}
|
||||
|
||||
void *
|
||||
assuan_get_pointer (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
return ctx? ctx->user_pointer : NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
if (ctx->log_fp)
|
||||
fflush (ctx->log_fp);
|
||||
ctx->log_fp = fp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
assuan_begin_confidential (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
ctx->confidential = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
assuan_end_confidential (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
if (ctx)
|
||||
{
|
||||
ctx->confidential = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_assuan_log_print_buffer (FILE *fp, const void *buffer, size_t length)
|
||||
{
|
||||
const unsigned char *s;
|
||||
int n;
|
||||
|
||||
for (n=length,s=buffer; n; n--, s++)
|
||||
{
|
||||
if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
|
||||
break;
|
||||
}
|
||||
s = buffer;
|
||||
if (!n && *s != '[')
|
||||
fwrite (buffer, length, 1, fp);
|
||||
else
|
||||
{
|
||||
putc ('[', fp);
|
||||
for (n=0; n < length; n++, s++)
|
||||
fprintf (fp, " %02x", *s);
|
||||
putc (' ', fp);
|
||||
putc (']', fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* print a user supplied string after filtering out potential bad
|
||||
characters*/
|
||||
void
|
||||
_assuan_log_sanitized_string (const char *string)
|
||||
{
|
||||
const unsigned char *s = string;
|
||||
#ifdef HAVE_JNLIB_LOGGING
|
||||
FILE *fp = log_get_stream ();
|
||||
#else
|
||||
FILE *fp = stderr;
|
||||
#endif
|
||||
|
||||
for (; *s; s++)
|
||||
{
|
||||
if (*s < 0x20 || (*s >= 0x7f && *s <= 0xa0))
|
||||
{
|
||||
putc ('\\', fp);
|
||||
if (*s == '\n')
|
||||
putc ('n', fp);
|
||||
else if (*s == '\r')
|
||||
putc ('r', fp);
|
||||
else if (*s == '\f')
|
||||
putc ('f', fp);
|
||||
else if (*s == '\v')
|
||||
putc ('v', fp);
|
||||
else if (*s == '\b')
|
||||
putc ('b', fp);
|
||||
else if (!*s)
|
||||
putc ('0', fp);
|
||||
else
|
||||
fprintf (fp, "x%02x", *s );
|
||||
}
|
||||
else
|
||||
putc (*s, fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
234
assuan/assuan.h
234
assuan/assuan.h
@ -1,234 +0,0 @@
|
||||
/* assuan.c - Definitions for the Assuan protocol
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of Assuan.
|
||||
*
|
||||
* Assuan is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU Lesser General Public License as
|
||||
* published by the Free Software Foundation; either version 2.1 of
|
||||
* the License, or (at your option) any later version.
|
||||
*
|
||||
* Assuan 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser 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 ASSUAN_H
|
||||
#define ASSUAN_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h> /* for ssize_t */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
ASSUAN_No_Error = 0,
|
||||
ASSUAN_General_Error = 1,
|
||||
ASSUAN_Out_Of_Core = 2,
|
||||
ASSUAN_Invalid_Value = 3,
|
||||
ASSUAN_Timeout = 4,
|
||||
ASSUAN_Read_Error = 5,
|
||||
ASSUAN_Write_Error = 6,
|
||||
ASSUAN_Problem_Starting_Server = 7,
|
||||
ASSUAN_Not_A_Server = 8,
|
||||
ASSUAN_Not_A_Client = 9,
|
||||
ASSUAN_Nested_Commands = 10,
|
||||
ASSUAN_Invalid_Response = 11,
|
||||
ASSUAN_No_Data_Callback = 12,
|
||||
ASSUAN_No_Inquire_Callback = 13,
|
||||
ASSUAN_Connect_Failed = 14,
|
||||
ASSUAN_Accept_Failed = 15,
|
||||
|
||||
/* error codes above 99 are meant as status codes */
|
||||
ASSUAN_Not_Implemented = 100,
|
||||
ASSUAN_Server_Fault = 101,
|
||||
ASSUAN_Invalid_Command = 102,
|
||||
ASSUAN_Unknown_Command = 103,
|
||||
ASSUAN_Syntax_Error = 104,
|
||||
ASSUAN_Parameter_Error = 105,
|
||||
ASSUAN_Parameter_Conflict = 106,
|
||||
ASSUAN_Line_Too_Long = 107,
|
||||
ASSUAN_Line_Not_Terminated = 108,
|
||||
ASSUAN_No_Input = 109,
|
||||
ASSUAN_No_Output = 110,
|
||||
ASSUAN_Canceled = 111,
|
||||
ASSUAN_Unsupported_Algorithm = 112,
|
||||
ASSUAN_Server_Resource_Problem = 113,
|
||||
ASSUAN_Server_IO_Error = 114,
|
||||
ASSUAN_Server_Bug = 115,
|
||||
ASSUAN_No_Data_Available = 116,
|
||||
ASSUAN_Invalid_Data = 117,
|
||||
ASSUAN_Unexpected_Command = 118,
|
||||
ASSUAN_Too_Much_Data = 119,
|
||||
ASSUAN_Inquire_Unknown = 120,
|
||||
ASSUAN_Inquire_Error = 121,
|
||||
ASSUAN_Invalid_Option = 122,
|
||||
ASSUAN_Invalid_Index = 123,
|
||||
ASSUAN_Unexpected_Status = 124,
|
||||
ASSUAN_Unexpected_Data = 125,
|
||||
ASSUAN_Invalid_Status = 126,
|
||||
|
||||
ASSUAN_Not_Confirmed = 128,
|
||||
|
||||
ASSUAN_Bad_Certificate = 201,
|
||||
ASSUAN_Bad_Certificate_Chain = 202,
|
||||
ASSUAN_Missing_Certificate = 203,
|
||||
ASSUAN_Bad_Signature = 204,
|
||||
ASSUAN_No_Agent = 205,
|
||||
ASSUAN_Agent_Error = 206,
|
||||
ASSUAN_No_Public_Key = 207,
|
||||
ASSUAN_No_Secret_Key = 208,
|
||||
ASSUAN_Invalid_Name = 209,
|
||||
|
||||
ASSUAN_Cert_Revoked = 301,
|
||||
ASSUAN_No_CRL_For_Cert = 302,
|
||||
ASSUAN_CRL_Too_Old = 303,
|
||||
ASSUAN_Not_Trusted = 304,
|
||||
|
||||
ASSUAN_Card_Error = 401,
|
||||
ASSUAN_Invalid_Card = 402,
|
||||
ASSUAN_No_PKCS15_App = 403,
|
||||
ASSUAN_Card_Not_Present = 404,
|
||||
ASSUAN_Invalid_Id = 405
|
||||
|
||||
} AssuanError;
|
||||
|
||||
/* This is a list of pre-registered ASSUAN commands */
|
||||
typedef enum {
|
||||
ASSUAN_CMD_NOP = 0,
|
||||
ASSUAN_CMD_CANCEL, /* cancel the current request */
|
||||
ASSUAN_CMD_BYE,
|
||||
ASSUAN_CMD_AUTH,
|
||||
ASSUAN_CMD_RESET,
|
||||
ASSUAN_CMD_OPTION,
|
||||
ASSUAN_CMD_DATA,
|
||||
ASSUAN_CMD_END,
|
||||
ASSUAN_CMD_INPUT,
|
||||
ASSUAN_CMD_OUTPUT,
|
||||
|
||||
ASSUAN_CMD_USER = 256 /* Other commands should be used with this offset*/
|
||||
} AssuanCommand;
|
||||
|
||||
#define ASSUAN_LINELENGTH 1002 /* 1000 + [CR,]LF */
|
||||
|
||||
struct assuan_context_s;
|
||||
typedef struct assuan_context_s *ASSUAN_CONTEXT;
|
||||
|
||||
/*-- assuan-handler.c --*/
|
||||
int assuan_register_command (ASSUAN_CONTEXT ctx,
|
||||
int cmd_id, const char *cmd_string,
|
||||
int (*handler)(ASSUAN_CONTEXT, char *));
|
||||
int assuan_register_bye_notify (ASSUAN_CONTEXT ctx,
|
||||
void (*fnc)(ASSUAN_CONTEXT));
|
||||
int assuan_register_reset_notify (ASSUAN_CONTEXT ctx,
|
||||
void (*fnc)(ASSUAN_CONTEXT));
|
||||
int assuan_register_cancel_notify (ASSUAN_CONTEXT ctx,
|
||||
void (*fnc)(ASSUAN_CONTEXT));
|
||||
int assuan_register_input_notify (ASSUAN_CONTEXT ctx,
|
||||
void (*fnc)(ASSUAN_CONTEXT, const char *));
|
||||
int assuan_register_output_notify (ASSUAN_CONTEXT ctx,
|
||||
void (*fnc)(ASSUAN_CONTEXT, const char *));
|
||||
|
||||
int assuan_register_option_handler (ASSUAN_CONTEXT ctx,
|
||||
int (*fnc)(ASSUAN_CONTEXT,
|
||||
const char*, const char*));
|
||||
|
||||
int assuan_process (ASSUAN_CONTEXT ctx);
|
||||
int assuan_process_next (ASSUAN_CONTEXT ctx);
|
||||
int assuan_get_active_fds (ASSUAN_CONTEXT ctx, int what,
|
||||
int *fdarray, int fdarraysize);
|
||||
|
||||
|
||||
FILE *assuan_get_data_fp (ASSUAN_CONTEXT ctx);
|
||||
AssuanError assuan_set_okay_line (ASSUAN_CONTEXT ctx, const char *line);
|
||||
void assuan_write_status (ASSUAN_CONTEXT ctx,
|
||||
const char *keyword, const char *text);
|
||||
|
||||
|
||||
/*-- assuan-listen.c --*/
|
||||
AssuanError assuan_set_hello_line (ASSUAN_CONTEXT ctx, const char *line);
|
||||
AssuanError assuan_accept (ASSUAN_CONTEXT ctx);
|
||||
int assuan_get_input_fd (ASSUAN_CONTEXT ctx);
|
||||
int assuan_get_output_fd (ASSUAN_CONTEXT ctx);
|
||||
AssuanError assuan_close_input_fd (ASSUAN_CONTEXT ctx);
|
||||
AssuanError assuan_close_output_fd (ASSUAN_CONTEXT ctx);
|
||||
|
||||
|
||||
/*-- assuan-pipe-server.c --*/
|
||||
int assuan_init_pipe_server (ASSUAN_CONTEXT *r_ctx, int filedes[2]);
|
||||
void assuan_deinit_server (ASSUAN_CONTEXT ctx);
|
||||
|
||||
/*-- assuan-socket-server.c --*/
|
||||
int assuan_init_socket_server (ASSUAN_CONTEXT *r_ctx, int listen_fd);
|
||||
int assuan_init_connected_socket_server (ASSUAN_CONTEXT *r_ctx, int fd);
|
||||
|
||||
|
||||
/*-- assuan-pipe-connect.c --*/
|
||||
AssuanError assuan_pipe_connect (ASSUAN_CONTEXT *ctx, const char *name,
|
||||
char *const argv[], int *fd_child_list);
|
||||
/*-- assuan-socket-connect.c --*/
|
||||
AssuanError assuan_socket_connect (ASSUAN_CONTEXT *ctx, const char *name,
|
||||
pid_t server_pid);
|
||||
|
||||
/*-- assuan-connect.c --*/
|
||||
void assuan_disconnect (ASSUAN_CONTEXT ctx);
|
||||
pid_t assuan_get_pid (ASSUAN_CONTEXT ctx);
|
||||
|
||||
/*-- assuan-client.c --*/
|
||||
AssuanError
|
||||
assuan_transact (ASSUAN_CONTEXT ctx,
|
||||
const char *command,
|
||||
AssuanError (*data_cb)(void *, const void *, size_t),
|
||||
void *data_cb_arg,
|
||||
AssuanError (*inquire_cb)(void*, const char *),
|
||||
void *inquire_cb_arg,
|
||||
AssuanError (*status_cb)(void*, const char *),
|
||||
void *status_cb_arg);
|
||||
|
||||
|
||||
/*-- assuan-inquire.c --*/
|
||||
AssuanError assuan_inquire (ASSUAN_CONTEXT ctx, const char *keyword,
|
||||
char **r_buffer, size_t *r_length, size_t maxlen);
|
||||
|
||||
/*-- assuan-buffer.c --*/
|
||||
AssuanError assuan_read_line (ASSUAN_CONTEXT ctx,
|
||||
char **line, size_t *linelen);
|
||||
int assuan_pending_line (ASSUAN_CONTEXT ctx);
|
||||
AssuanError assuan_write_line (ASSUAN_CONTEXT ctx, const char *line );
|
||||
AssuanError assuan_send_data (ASSUAN_CONTEXT ctx,
|
||||
const void *buffer, size_t length);
|
||||
|
||||
|
||||
/*-- assuan-util.c --*/
|
||||
void assuan_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
|
||||
void *(*new_realloc_func)(void *p, size_t n),
|
||||
void (*new_free_func)(void*) );
|
||||
void assuan_set_io_func (ssize_t (*r)(int,void*,size_t),
|
||||
ssize_t (*w)(int,const void*,size_t));
|
||||
void assuan_set_log_stream (ASSUAN_CONTEXT ctx, FILE *fp);
|
||||
int assuan_set_error (ASSUAN_CONTEXT ctx, int err, const char *text);
|
||||
void assuan_set_pointer (ASSUAN_CONTEXT ctx, void *pointer);
|
||||
void *assuan_get_pointer (ASSUAN_CONTEXT ctx);
|
||||
|
||||
void assuan_begin_confidential (ASSUAN_CONTEXT ctx);
|
||||
void assuan_end_confidential (ASSUAN_CONTEXT ctx);
|
||||
|
||||
/*-- assuan-errors.c (built) --*/
|
||||
const char *assuan_strerror (AssuanError err);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*ASSUAN_H*/
|
@ -1,71 +0,0 @@
|
||||
#!/bin/sh
|
||||
# mkerrors - Extract error strings from assuan.h
|
||||
# and create C source for assuan_strerror
|
||||
# Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is part of Assuan.
|
||||
#
|
||||
# Assuan is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU Lesser General Public License as
|
||||
# published by the Free Software Foundation; either version 2.1 of
|
||||
# the License, or (at your option) any later version.
|
||||
#
|
||||
# Assuan 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
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser 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
|
||||
|
||||
cat <<EOF
|
||||
/* Generated automatically by mkerrors */
|
||||
/* Do not edit! */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "assuan.h"
|
||||
|
||||
/**
|
||||
* assuan_strerror:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* errorcode. If this is an unknown value, a string with the value
|
||||
* is returned (Beware: it is hold in a static buffer).
|
||||
*
|
||||
* Return value: String with the error description.
|
||||
**/
|
||||
const char *
|
||||
assuan_strerror (AssuanError err)
|
||||
{
|
||||
const char *s;
|
||||
static char buf[25];
|
||||
|
||||
switch (err)
|
||||
{
|
||||
EOF
|
||||
|
||||
awk '
|
||||
/ASSUAN_No_Error/ { okay=1 }
|
||||
!okay {next}
|
||||
/}/ { exit 0 }
|
||||
/ASSUAN_[A-Za-z_]*/ { print_code($1) }
|
||||
|
||||
|
||||
function print_code( s )
|
||||
{
|
||||
printf " case %s: s=\"", s ;
|
||||
gsub(/_/, " ", s );
|
||||
printf "%s\"; break;\n", tolower(substr(s,8));
|
||||
}
|
||||
'
|
||||
|
||||
cat <<EOF
|
||||
default: sprintf (buf, "ec=%d", err ); s=buf; break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
EOF
|
139
common/ChangeLog
139
common/ChangeLog
@ -1,139 +0,0 @@
|
||||
2002-09-04 Neal H. Walfield <neal@g10code.de>
|
||||
|
||||
* vasprintf.c (vasprintf) [va_copy]: Use va_copy.
|
||||
[!va_copy && __va_copy]: Use __va_copy.
|
||||
[!va_copy && !__va_copy]: Only now fall back to using memcpy.
|
||||
|
||||
2002-08-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* errors.h: Added STATUS_IMPORT_PROBLEM.
|
||||
|
||||
2002-08-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* vasprintf.c: Hack to handle NULL for %s.
|
||||
|
||||
2002-08-09 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* signal.c: New. Taken from GnuPG 1.1.91.
|
||||
|
||||
2002-07-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* util.h (_IO_cookie_io_functions_t): Fixed typo. Noted by
|
||||
Richard Lefebvre.
|
||||
|
||||
2002-07-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* fseeko.c, ftello.c: New.
|
||||
|
||||
2002-06-28 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c (map_to_assuan_status): Map more errorcodes to Bad
|
||||
Certificate.
|
||||
|
||||
2002-06-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c (map_to_assuan_status): Map EOF to No_Data_Available.
|
||||
|
||||
2002-06-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* errors.h (gnupg_error_token): Add new prototype.
|
||||
(STATUS_ERROR): New.
|
||||
|
||||
* mkerrtok: New.
|
||||
* Makefile.am: Use it to create the new error token function.
|
||||
|
||||
2002-06-04 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c (map_to_assuan_status): Map Bad_CA_Certificate.
|
||||
|
||||
2002-05-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* no-pth.c, Makefile.am: Removed.
|
||||
|
||||
2002-05-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* mkdtemp.c: Replaced byte by unsigned char because it is no longer
|
||||
defined in gcrypt.h.
|
||||
|
||||
2002-05-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c (map_gcry_err): Add libgcrypt's new S-expression errors.
|
||||
(map_ksba_err): Add a few mappings.
|
||||
|
||||
2002-05-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gettime.c: New.
|
||||
|
||||
2002-05-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* errors.h: Added STARUS_EXPSIG and STATUS_EXPKEYSIG.
|
||||
|
||||
2002-04-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* cryptmiss.c: New.
|
||||
|
||||
2002-02-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c: Add more assuan<->gnupg mappings.
|
||||
|
||||
2002-02-12 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* fopencookie.c: Dummy function.
|
||||
|
||||
* vasprintf.c: New. Taken from binutils-2.9.1 and dropped all non
|
||||
ANSI-C stuff. Merged with asprintf version.
|
||||
|
||||
* no-pth.c: New.
|
||||
|
||||
2002-01-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* mkdtemp.c: Copied from gnupg-1.0.6c and changed to use libgcrypt.
|
||||
|
||||
2002-01-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* sysutils.c: New. This is the misc.c file from gnupg 1.0.6 with
|
||||
the OpenPGP stuff removed.
|
||||
* sysutils.h: New.
|
||||
|
||||
2002-01-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c: Add mapping for Not_Trusted.
|
||||
|
||||
2002-01-11 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c (map_assuan_err): Codes for CRL
|
||||
|
||||
2002-01-08 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* util.h (spacep): New.
|
||||
|
||||
2002-01-02 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c (map_to_assuan_status): New. Merged from ../agent
|
||||
and ../sm.
|
||||
|
||||
2001-12-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* maperror.c (map_gcry_err): Add some mappings.
|
||||
|
||||
2001-12-18 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am (AM_CPPFLAGS): Include flags for gcrypt and ksba
|
||||
|
||||
2001-12-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* util.h (digitp, hexdigitp): New ctype like macros.
|
||||
(atoi_1,atoi_2,atoi_4,xtoi_1,xtoi_2): 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.
|
||||
|
||||
|
@ -1,52 +0,0 @@
|
||||
# Makefile for common gnupg modules
|
||||
# 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
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
EXTRA_DIST = mkerrors mkerrtok
|
||||
#INCLUDES =
|
||||
BUILT_SOURCES = errors.c
|
||||
|
||||
noinst_LIBRARIES = libcommon.a
|
||||
|
||||
AM_CPPFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS)
|
||||
|
||||
libcommon_a_SOURCES = \
|
||||
util.h i18n.h \
|
||||
errors.c errors.h \
|
||||
maperror.c \
|
||||
sysutils.c sysutils.h \
|
||||
cryptmiss.c \
|
||||
gettime.c \
|
||||
signal.c
|
||||
|
||||
|
||||
libcommon_a_LIBADD = @LIBOBJS@
|
||||
|
||||
errors.c : errors.h mkerrors mkerrtok
|
||||
$(srcdir)/mkerrors < $(srcdir)/errors.h > errors.c
|
||||
$(srcdir)/mkerrtok < $(srcdir)/errors.h >> errors.c
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,14 +0,0 @@
|
||||
Stuff used by several modules of GnuPG. This way we can share error
|
||||
codes and serveral other things.
|
||||
|
||||
|
||||
These directories use it:
|
||||
|
||||
gpg
|
||||
sm
|
||||
agent
|
||||
|
||||
These directories don't use it:
|
||||
|
||||
assuan
|
||||
kbx
|
@ -1,39 +0,0 @@
|
||||
/* cryptmiss.c - Missing functions in libgcrypt
|
||||
* 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 "util.h"
|
||||
|
||||
char *
|
||||
gcry_strdup (const char *string)
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = gcry_malloc (strlen (string)+1);
|
||||
if (p)
|
||||
strcpy (p, string);
|
||||
return p;
|
||||
}
|
192
common/errors.h
192
common/errors.h
@ -1,192 +0,0 @@
|
||||
/* errors.h - Globally used error codes
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef GNUPG_COMMON_ERRORS_H
|
||||
#define GNUPG_COMMON_ERRORS_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
/* Error numbers */
|
||||
enum {
|
||||
GNUPG_EOF = -1,
|
||||
GNUPG_No_Error = 0,
|
||||
GNUPG_General_Error = 1,
|
||||
GNUPG_Out_Of_Core = 2,
|
||||
GNUPG_Invalid_Value = 3,
|
||||
GNUPG_IO_Error = 4,
|
||||
GNUPG_Resource_Limit = 5,
|
||||
GNUPG_Internal_Error = 6,
|
||||
GNUPG_Bad_Certificate = 7,
|
||||
GNUPG_Bad_Certificate_Chain = 8,
|
||||
GNUPG_Missing_Certificate = 9,
|
||||
GNUPG_No_Data = 10,
|
||||
GNUPG_Bad_Signature = 11,
|
||||
GNUPG_Not_Implemented = 12,
|
||||
GNUPG_Conflict = 13,
|
||||
GNUPG_Bug = 14,
|
||||
GNUPG_Read_Error = 15,
|
||||
GNUPG_Write_Error = 16,
|
||||
GNUPG_Incomplete_Line = 17,
|
||||
GNUPG_Invalid_Response = 18,
|
||||
GNUPG_No_Agent = 19,
|
||||
GNUPG_Agent_Error = 20,
|
||||
GNUPG_No_Public_Key = 21,
|
||||
GNUPG_No_Secret_Key = 22,
|
||||
GNUPG_File_Open_Error = 23,
|
||||
GNUPG_File_Create_Error = 24,
|
||||
GNUPG_File_Error = 25,
|
||||
GNUPG_Not_Supported = 26,
|
||||
GNUPG_Invalid_Data = 27,
|
||||
GNUPG_Assuan_Server_Fault = 28,
|
||||
GNUPG_Assuan_Error = 29, /* catch all assuan error */
|
||||
GNUPG_Invalid_Session_Key = 30,
|
||||
GNUPG_Invalid_Sexp = 31,
|
||||
GNUPG_Unsupported_Algorithm = 32,
|
||||
GNUPG_No_PIN_Entry = 33,
|
||||
GNUPG_PIN_Entry_Error = 34,
|
||||
GNUPG_Bad_PIN = 35,
|
||||
GNUPG_Bad_Passphrase = 36,
|
||||
GNUPG_Invalid_Name = 37,
|
||||
GNUPG_Bad_Public_Key = 38,
|
||||
GNUPG_Bad_Secret_Key = 39,
|
||||
GNUPG_Bad_Data = 40,
|
||||
GNUPG_Invalid_Parameter = 41,
|
||||
GNUPG_Tribute_to_D_A = 42,
|
||||
GNUPG_No_Dirmngr = 43,
|
||||
GNUPG_Dirmngr_Error = 44,
|
||||
GNUPG_Certificate_Revoked = 45,
|
||||
GNUPG_No_CRL_Known = 46,
|
||||
GNUPG_CRL_Too_Old = 47,
|
||||
GNUPG_Line_Too_Long = 48,
|
||||
GNUPG_Not_Trusted = 49,
|
||||
GNUPG_Canceled = 50,
|
||||
GNUPG_Bad_CA_Certificate = 51,
|
||||
GNUPG_Certificate_Expired = 52,
|
||||
GNUPG_Certificate_Too_Young = 53,
|
||||
GNUPG_Unsupported_Certificate = 54,
|
||||
GNUPG_Unknown_Sexp = 55,
|
||||
GNUPG_Unsupported_Protection = 56,
|
||||
GNUPG_Corrupted_Protection = 57,
|
||||
GNUPG_Ambiguous_Name = 58,
|
||||
GNUPG_Card_Error = 59,
|
||||
GNUPG_Card_Reset = 60,
|
||||
GNUPG_Card_Removed = 61,
|
||||
GNUPG_Invalid_Card = 62,
|
||||
GNUPG_Card_Not_Present = 63,
|
||||
GNUPG_No_PKCS15_App = 64,
|
||||
GNUPG_Not_Confirmed = 65,
|
||||
GNUPG_Configuration_Error = 66,
|
||||
GNUPG_No_Policy_Match = 67,
|
||||
GNUPG_Invalid_Index = 68,
|
||||
GNUPG_Invalid_Id = 69,
|
||||
GNUPG_No_Scdaemon = 70,
|
||||
GNUPG_Scdaemon_Error = 71,
|
||||
GNUPG_Unsupported_Protocol = 72,
|
||||
GNUPG_Bad_PIN_Method = 73,
|
||||
GNUPG_Card_Not_Initialized = 74,
|
||||
GNUPG_Unsupported_Operation = 75,
|
||||
GNUPG_Wrong_Key_Usage = 76,
|
||||
};
|
||||
|
||||
/* Status codes - fixme: should go into another file */
|
||||
enum {
|
||||
STATUS_ENTER,
|
||||
STATUS_LEAVE,
|
||||
STATUS_ABORT,
|
||||
STATUS_GOODSIG,
|
||||
STATUS_BADSIG,
|
||||
STATUS_ERRSIG,
|
||||
STATUS_BADARMOR,
|
||||
STATUS_RSA_OR_IDEA,
|
||||
STATUS_SIGEXPIRED,
|
||||
STATUS_KEYREVOKED,
|
||||
STATUS_TRUST_UNDEFINED,
|
||||
STATUS_TRUST_NEVER,
|
||||
STATUS_TRUST_MARGINAL,
|
||||
STATUS_TRUST_FULLY,
|
||||
STATUS_TRUST_ULTIMATE,
|
||||
|
||||
STATUS_SHM_INFO,
|
||||
STATUS_SHM_GET,
|
||||
STATUS_SHM_GET_BOOL,
|
||||
STATUS_SHM_GET_HIDDEN,
|
||||
|
||||
STATUS_NEED_PASSPHRASE,
|
||||
STATUS_VALIDSIG,
|
||||
STATUS_SIG_ID,
|
||||
STATUS_ENC_TO,
|
||||
STATUS_NODATA,
|
||||
STATUS_BAD_PASSPHRASE,
|
||||
STATUS_NO_PUBKEY,
|
||||
STATUS_NO_SECKEY,
|
||||
STATUS_NEED_PASSPHRASE_SYM,
|
||||
STATUS_DECRYPTION_FAILED,
|
||||
STATUS_DECRYPTION_OKAY,
|
||||
STATUS_MISSING_PASSPHRASE,
|
||||
STATUS_GOOD_PASSPHRASE,
|
||||
STATUS_GOODMDC,
|
||||
STATUS_BADMDC,
|
||||
STATUS_ERRMDC,
|
||||
STATUS_IMPORTED,
|
||||
STATUS_IMPORT_PROBLEM,
|
||||
STATUS_IMPORT_RES,
|
||||
STATUS_FILE_START,
|
||||
STATUS_FILE_DONE,
|
||||
STATUS_FILE_ERROR,
|
||||
|
||||
STATUS_BEGIN_DECRYPTION,
|
||||
STATUS_END_DECRYPTION,
|
||||
STATUS_BEGIN_ENCRYPTION,
|
||||
STATUS_END_ENCRYPTION,
|
||||
|
||||
STATUS_DELETE_PROBLEM,
|
||||
STATUS_GET_BOOL,
|
||||
STATUS_GET_LINE,
|
||||
STATUS_GET_HIDDEN,
|
||||
STATUS_GOT_IT,
|
||||
STATUS_PROGRESS,
|
||||
STATUS_SIG_CREATED,
|
||||
STATUS_SESSION_KEY,
|
||||
STATUS_NOTATION_NAME,
|
||||
STATUS_NOTATION_DATA,
|
||||
STATUS_POLICY_URL,
|
||||
STATUS_BEGIN_STREAM,
|
||||
STATUS_END_STREAM,
|
||||
STATUS_KEY_CREATED,
|
||||
STATUS_USERID_HIN,
|
||||
STATUS_UNEXPECTED,
|
||||
STATUS_INV_RECP,
|
||||
STATUS_NO_RECP,
|
||||
STATUS_ALREADY_SIGNED,
|
||||
|
||||
STATUS_EXPSIG,
|
||||
STATUS_EXPKEYSIG,
|
||||
|
||||
STATUS_TRUNCATED,
|
||||
STATUS_ERROR
|
||||
};
|
||||
|
||||
|
||||
/*-- errors.c (build by mkerror and mkerrtok) --*/
|
||||
const char *gnupg_strerror (int err);
|
||||
const char *gnupg_error_token (int err);
|
||||
|
||||
|
||||
#endif /*GNUPG_COMMON_ERRORS_H*/
|
@ -1,37 +0,0 @@
|
||||
/* fopencookie.c - Dummy glibc replacement
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
FILE *
|
||||
fopencookie (void *cookie, const char *opentype,
|
||||
cookie_io_functions_t funclist)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
/* fseeko.c - libc replacement function
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
fseeko (FILE *stream, off_t off, int whence)
|
||||
{
|
||||
return fseek (stream, off, whence);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,45 +0,0 @@
|
||||
/* ftello.c - libc replacement function
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
|
||||
off_t
|
||||
ftello (FILE *stream)
|
||||
{
|
||||
long int off;
|
||||
|
||||
off = ftell (stream);
|
||||
if (off == -1)
|
||||
return (off_t)-1;
|
||||
return off;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,87 +0,0 @@
|
||||
/* gettime.c - Wrapper for time functions
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
static unsigned long timewarp;
|
||||
static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
|
||||
|
||||
/* Wrapper for the time(3). We use this here so we can fake the time
|
||||
for tests */
|
||||
time_t
|
||||
gnupg_get_time ()
|
||||
{
|
||||
time_t current = time (NULL);
|
||||
if (timemode == NORMAL)
|
||||
return current;
|
||||
else if (timemode == FROZEN)
|
||||
return timewarp;
|
||||
else if (timemode == FUTURE)
|
||||
return current + timewarp;
|
||||
else
|
||||
return current - timewarp;
|
||||
}
|
||||
|
||||
/* set the time to NEWTIME so that gnupg_get_time returns a time
|
||||
starting with this one. With FREEZE set to 1 the returned time
|
||||
will never change. Just for completeness, a value of (time_t)-1
|
||||
for NEWTIME gets you back to rality. Note that this is obviously
|
||||
not thread-safe but this is not required. */
|
||||
void
|
||||
gnupg_set_time (time_t newtime, int freeze)
|
||||
{
|
||||
time_t current = time (NULL);
|
||||
|
||||
if ( newtime == (time_t)-1 || current == newtime)
|
||||
{
|
||||
timemode = NORMAL;
|
||||
timewarp = 0;
|
||||
}
|
||||
else if (freeze)
|
||||
{
|
||||
timemode = FROZEN;
|
||||
timewarp = current;
|
||||
}
|
||||
else if (newtime > current)
|
||||
{
|
||||
timemode = FUTURE;
|
||||
timewarp = newtime - current;
|
||||
}
|
||||
else
|
||||
{
|
||||
timemode = PAST;
|
||||
timewarp = current - newtime;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns true when we are in timewarp mode */
|
||||
int
|
||||
gnupg_faked_time_p (void)
|
||||
{
|
||||
return timemode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,47 +0,0 @@
|
||||
/* i18n.h
|
||||
* Copyright (C) 1998, 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
|
||||
*/
|
||||
|
||||
#ifndef GNUPG_COMMON_I18N_H
|
||||
#define GNUPG_COMMON_I18N_H
|
||||
|
||||
#ifdef USE_SIMPLE_GETTEXT
|
||||
int set_gettext_file( const char *filename );
|
||||
const char *gettext( const char *msgid );
|
||||
# define _(a) gettext (a)
|
||||
# define N_(a) (a)
|
||||
#else
|
||||
# ifdef HAVE_LOCALE_H
|
||||
# include <locale.h>
|
||||
# endif
|
||||
# ifdef ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
# define _(a) gettext (a)
|
||||
# ifdef gettext_noop
|
||||
# define N_(a) gettext_noop (a)
|
||||
# else
|
||||
# define N_(a) (a)
|
||||
# endif
|
||||
# else
|
||||
# define _(a) (a)
|
||||
# define N_(a) (a)
|
||||
# endif
|
||||
#endif /*!USE_SIMPLE_GETTEXT*/
|
||||
|
||||
#endif /*GNUPG_COMMON_I18N_H*/
|
@ -1,271 +0,0 @@
|
||||
/* maperror.c - Error mapping
|
||||
* 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 <unistd.h>
|
||||
|
||||
#include <ksba.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "errors.h"
|
||||
#include "../assuan/assuan.h"
|
||||
|
||||
/* Note: we might want to wrap this in a macro to get our hands on
|
||||
the line and file where the error occured */
|
||||
int
|
||||
map_ksba_err (int err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case -1:
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case KSBA_Out_Of_Core: err = GNUPG_Out_Of_Core; break;
|
||||
case KSBA_Invalid_Value: err = GNUPG_Invalid_Value; break;
|
||||
case KSBA_Not_Implemented: err = GNUPG_Not_Implemented; break;
|
||||
case KSBA_Conflict: err = GNUPG_Conflict; break;
|
||||
case KSBA_Read_Error: err = GNUPG_Read_Error; break;
|
||||
case KSBA_Write_Error: err = GNUPG_Write_Error; break;
|
||||
case KSBA_No_Data: err = GNUPG_No_Data; break;
|
||||
case KSBA_Bug: err = GNUPG_Bug; break;
|
||||
case KSBA_Unsupported_Algorithm: err = GNUPG_Unsupported_Algorithm; break;
|
||||
case KSBA_Invalid_Index: err = GNUPG_Invalid_Index; break;
|
||||
case KSBA_Invalid_Sexp: err = GNUPG_Invalid_Sexp; break;
|
||||
case KSBA_Unknown_Sexp: err = GNUPG_Unknown_Sexp; break;
|
||||
|
||||
default:
|
||||
err = seterr (General_Error);
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
map_gcry_err (int err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case GCRYERR_EOF:
|
||||
case -1:
|
||||
err = -1;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case GCRYERR_WRONG_PK_ALGO:
|
||||
case GCRYERR_INV_PK_ALGO:
|
||||
case GCRYERR_INV_MD_ALGO:
|
||||
case GCRYERR_INV_CIPHER_ALGO:
|
||||
err = GNUPG_Unsupported_Algorithm;
|
||||
break;
|
||||
case GCRYERR_INV_KEYLEN:
|
||||
case GCRYERR_WEAK_KEY:
|
||||
case GCRYERR_BAD_PUBLIC_KEY: err = GNUPG_Bad_Public_Key; break;
|
||||
case GCRYERR_BAD_SECRET_KEY: err = GNUPG_Bad_Secret_Key; break;
|
||||
case GCRYERR_BAD_SIGNATURE: err = GNUPG_Bad_Signature; break;
|
||||
|
||||
case GCRYERR_BAD_MPI:
|
||||
err = GNUPG_Bad_Data;
|
||||
break;
|
||||
|
||||
case GCRYERR_INV_ARG:
|
||||
case GCRYERR_INV_OP:
|
||||
case GCRYERR_INTERNAL:
|
||||
case GCRYERR_INV_CIPHER_MODE:
|
||||
err = GNUPG_Invalid_Value;
|
||||
break;
|
||||
|
||||
case GCRYERR_SELFTEST:
|
||||
err = GNUPG_Bug;
|
||||
break;
|
||||
|
||||
case GCRYERR_SEXP_INV_LEN_SPEC :
|
||||
case GCRYERR_SEXP_STRING_TOO_LONG :
|
||||
case GCRYERR_SEXP_UNMATCHED_PAREN :
|
||||
case GCRYERR_SEXP_NOT_CANONICAL :
|
||||
case GCRYERR_SEXP_BAD_CHARACTER :
|
||||
case GCRYERR_SEXP_BAD_QUOTATION :
|
||||
case GCRYERR_SEXP_ZERO_PREFIX :
|
||||
case GCRYERR_SEXP_NESTED_DH :
|
||||
case GCRYERR_SEXP_UNMATCHED_DH :
|
||||
case GCRYERR_SEXP_UNEXPECTED_PUNC :
|
||||
case GCRYERR_SEXP_BAD_HEX_CHAR :
|
||||
case GCRYERR_SEXP_ODD_HEX_NUMBERS :
|
||||
case GCRYERR_SEXP_BAD_OCT_CHAR :
|
||||
err = GNUPG_Invalid_Sexp;
|
||||
break;
|
||||
|
||||
case GCRYERR_NO_MEM: err = GNUPG_Out_Of_Core; break;
|
||||
|
||||
case GCRYERR_NOT_IMPL: err = GNUPG_Not_Implemented; break;
|
||||
case GCRYERR_CONFLICT: err = GNUPG_Conflict; break;
|
||||
|
||||
case GCRYERR_INV_OBJ: /* an object is not valid */
|
||||
case GCRYERR_TOO_SHORT: /* provided buffer too short */
|
||||
case GCRYERR_TOO_LARGE: /* object is too large */
|
||||
case GCRYERR_NO_OBJ: /* Missing item in an object */
|
||||
default:
|
||||
err = seterr (General_Error);
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
map_kbx_err (int err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case -1:
|
||||
case 0:
|
||||
break;
|
||||
|
||||
default:
|
||||
err = seterr (General_Error);
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
map_assuan_err (int err)
|
||||
{
|
||||
switch (err)
|
||||
{
|
||||
case -1:
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case ASSUAN_Canceled: err = GNUPG_Canceled; break;
|
||||
case ASSUAN_Invalid_Index: err = GNUPG_Invalid_Index; break;
|
||||
|
||||
case ASSUAN_Not_Implemented: err = GNUPG_Not_Implemented; break;
|
||||
case ASSUAN_Server_Fault: err = GNUPG_Assuan_Server_Fault; break;
|
||||
case ASSUAN_No_Public_Key: err = GNUPG_No_Public_Key; break;
|
||||
case ASSUAN_No_Secret_Key: err = GNUPG_No_Secret_Key; break;
|
||||
|
||||
case ASSUAN_Cert_Revoked: err = GNUPG_Certificate_Revoked; break;
|
||||
case ASSUAN_No_CRL_For_Cert: err = GNUPG_No_CRL_Known; break;
|
||||
case ASSUAN_CRL_Too_Old: err = GNUPG_CRL_Too_Old; break;
|
||||
|
||||
case ASSUAN_Not_Trusted: err = GNUPG_Not_Trusted; break;
|
||||
|
||||
case ASSUAN_Card_Error: err = GNUPG_Card_Error; break;
|
||||
case ASSUAN_Invalid_Card: err = GNUPG_Invalid_Card; break;
|
||||
case ASSUAN_No_PKCS15_App: err = GNUPG_No_PKCS15_App; break;
|
||||
case ASSUAN_Card_Not_Present: err= GNUPG_Card_Not_Present; break;
|
||||
case ASSUAN_Not_Confirmed: err = GNUPG_Not_Confirmed; break;
|
||||
case ASSUAN_Invalid_Id: err = GNUPG_Invalid_Id; break;
|
||||
|
||||
default:
|
||||
err = err < 100? GNUPG_Assuan_Server_Fault : GNUPG_Assuan_Error;
|
||||
break;
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Map GNUPG_xxx error codes to Assuan status codes */
|
||||
int
|
||||
map_to_assuan_status (int rc)
|
||||
{
|
||||
switch (rc)
|
||||
{
|
||||
case -1:
|
||||
rc = ASSUAN_No_Data_Available;
|
||||
break;
|
||||
case 0: break;
|
||||
case GNUPG_Bad_CA_Certificate:
|
||||
case GNUPG_Bad_Certificate:
|
||||
case GNUPG_Wrong_Key_Usage:
|
||||
case GNUPG_Certificate_Revoked:
|
||||
case GNUPG_No_CRL_Known:
|
||||
case GNUPG_CRL_Too_Old:
|
||||
case GNUPG_No_Policy_Match:
|
||||
case GNUPG_Certificate_Expired:
|
||||
rc = ASSUAN_Bad_Certificate;
|
||||
break;
|
||||
case GNUPG_Bad_Certificate_Chain: rc = ASSUAN_Bad_Certificate_Chain; break;
|
||||
case GNUPG_Missing_Certificate: rc = ASSUAN_Missing_Certificate; break;
|
||||
case GNUPG_No_Data: rc = ASSUAN_No_Data_Available; break;
|
||||
case GNUPG_Bad_Signature: rc = ASSUAN_Bad_Signature; break;
|
||||
case GNUPG_Not_Implemented: rc = ASSUAN_Not_Implemented; break;
|
||||
case GNUPG_No_Agent: rc = ASSUAN_No_Agent; break;
|
||||
case GNUPG_Agent_Error: rc = ASSUAN_Agent_Error; break;
|
||||
case GNUPG_No_Public_Key: rc = ASSUAN_No_Public_Key; break;
|
||||
case GNUPG_No_Secret_Key: rc = ASSUAN_No_Secret_Key; break;
|
||||
case GNUPG_Invalid_Data: rc = ASSUAN_Invalid_Data; break;
|
||||
case GNUPG_Invalid_Name: rc = ASSUAN_Invalid_Name; break;
|
||||
case GNUPG_Not_Trusted: rc = ASSUAN_Not_Trusted; break;
|
||||
case GNUPG_Canceled: rc = ASSUAN_Canceled; break;
|
||||
case GNUPG_Invalid_Index: rc = ASSUAN_Invalid_Index; break;
|
||||
|
||||
case GNUPG_Card_Error:
|
||||
case GNUPG_Card_Reset:
|
||||
rc = ASSUAN_Card_Error;
|
||||
break;
|
||||
case GNUPG_Card_Removed:
|
||||
case GNUPG_Card_Not_Present:
|
||||
rc = ASSUAN_Card_Not_Present;
|
||||
break;
|
||||
case GNUPG_Invalid_Card: rc = ASSUAN_Invalid_Card; break;
|
||||
case GNUPG_No_PKCS15_App: rc = ASSUAN_No_PKCS15_App; break;
|
||||
case GNUPG_Not_Confirmed: rc = ASSUAN_Not_Confirmed; break;
|
||||
case GNUPG_Invalid_Id: rc = ASSUAN_Invalid_Id; break;
|
||||
|
||||
case GNUPG_Bad_PIN:
|
||||
case GNUPG_Bad_Passphrase:
|
||||
rc = ASSUAN_No_Secret_Key;
|
||||
break;
|
||||
|
||||
case GNUPG_Read_Error:
|
||||
case GNUPG_Write_Error:
|
||||
case GNUPG_IO_Error:
|
||||
rc = ASSUAN_Server_IO_Error;
|
||||
break;
|
||||
case GNUPG_Out_Of_Core:
|
||||
case GNUPG_Resource_Limit:
|
||||
rc = ASSUAN_Server_Resource_Problem;
|
||||
break;
|
||||
case GNUPG_Bug:
|
||||
case GNUPG_Internal_Error:
|
||||
rc = ASSUAN_Server_Bug;
|
||||
break;
|
||||
default:
|
||||
rc = ASSUAN_Server_Fault;
|
||||
break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,99 +0,0 @@
|
||||
/* mkdtemp.c - libc replacement function
|
||||
* 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
|
||||
*/
|
||||
|
||||
/* This is a replacement function for mkdtemp in case the platform
|
||||
we're building on (like mine!) doesn't have it. */
|
||||
|
||||
#include <config.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <gcrypt.h>
|
||||
|
||||
#ifdef MKDIR_TAKES_ONE_ARG
|
||||
# undef mkdir
|
||||
# define mkdir(a,b) mkdir(a)
|
||||
#endif
|
||||
|
||||
char *mkdtemp(char *template)
|
||||
{
|
||||
int attempts,idx,count=0;
|
||||
unsigned char *ch;
|
||||
|
||||
idx=strlen(template);
|
||||
|
||||
/* Walk backwards to count all the Xes */
|
||||
while(idx>0 && template[idx-1]=='X')
|
||||
{
|
||||
count++;
|
||||
idx--;
|
||||
}
|
||||
|
||||
if(count==0)
|
||||
{
|
||||
errno=EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ch=&template[idx];
|
||||
|
||||
/* Try 4 times to make the temp directory */
|
||||
for(attempts=0;attempts<4;attempts++)
|
||||
{
|
||||
int remaining=count;
|
||||
char *marker=ch;
|
||||
unsigned char *randombits;
|
||||
|
||||
idx=0;
|
||||
|
||||
/* Using really random bits is probably overkill here. The
|
||||
worst thing that can happen with a directory name collision
|
||||
is that the function will return an error. */
|
||||
|
||||
randombits = gcry_random_bytes (4*remaining, GCRY_WEAK_RANDOM);
|
||||
|
||||
while(remaining>1)
|
||||
{
|
||||
sprintf(marker,"%02X",randombits[idx++]);
|
||||
marker+=2;
|
||||
remaining-=2;
|
||||
}
|
||||
|
||||
/* Any leftover Xes? get_random_bits rounds up to full bytes,
|
||||
so this is safe. */
|
||||
if(remaining>0)
|
||||
sprintf(marker,"%X",randombits[idx]&0xF);
|
||||
|
||||
gcry_free (randombits);
|
||||
|
||||
if(mkdir(template,0700)==0)
|
||||
break;
|
||||
}
|
||||
|
||||
if(attempts==4)
|
||||
return NULL; /* keeps the errno from mkdir, whatever it is */
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
|
@ -1,72 +0,0 @@
|
||||
#!/bin/sh
|
||||
# mkerrors - Extract error strings from errors.h
|
||||
# and create C source for gnupg_strerror
|
||||
# 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
|
||||
|
||||
cat <<EOF
|
||||
/* Generated automatically by mkerrors */
|
||||
/* Do not edit! */
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include "errors.h"
|
||||
|
||||
/**
|
||||
* gnupg_strerror:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* errorcode. If this is an unknown value, a string with the value
|
||||
* is returned (Beware: it is hold in a static buffer).
|
||||
*
|
||||
* Return value: String with the error description.
|
||||
**/
|
||||
const char *
|
||||
gnupg_strerror (int err)
|
||||
{
|
||||
const char *s;
|
||||
static char buf[25];
|
||||
|
||||
switch (err)
|
||||
{
|
||||
EOF
|
||||
|
||||
awk '
|
||||
/GNUPG_No_Error/ { okay=1 }
|
||||
!okay {next}
|
||||
/}/ { exit 0 }
|
||||
/GNUPG_[A-Za-z_]*/ { print_code($1) }
|
||||
|
||||
|
||||
function print_code( s )
|
||||
{
|
||||
printf " case %s: s=\"", s ;
|
||||
gsub(/_/, " ", s );
|
||||
printf "%s\"; break;\n", tolower(substr(s,7));
|
||||
}
|
||||
'
|
||||
|
||||
cat <<EOF
|
||||
default: sprintf (buf, "ec=%d", err ); s=buf; break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
EOF
|
@ -1,67 +0,0 @@
|
||||
#!/bin/sh
|
||||
# mkerrtok - Create error tokens from errors.h
|
||||
# and the C source for gnupg_errortoken
|
||||
# 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
|
||||
|
||||
cat <<EOF
|
||||
/* Generated automatically by mkerrtok */
|
||||
/* Do not edit! */
|
||||
|
||||
/**
|
||||
* gnupg_error_token:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* errorcode. If this is an unknown value, a static string is returned.
|
||||
* This function differs from gnupg_strerror that it yields the string
|
||||
* representation of the macro which is never subject to i18n.
|
||||
*
|
||||
* Return value: String with the error token.
|
||||
**/
|
||||
const char *
|
||||
gnupg_error_token (int err)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
switch (err)
|
||||
{
|
||||
EOF
|
||||
|
||||
awk '
|
||||
/GNUPG_No_Error/ { okay=1 }
|
||||
!okay {next}
|
||||
/}/ { exit 0 }
|
||||
/GNUPG_[A-Za-z_]*/ { print_code($1) }
|
||||
|
||||
|
||||
function print_code( s )
|
||||
{
|
||||
printf " case %s: s=\"", s ;
|
||||
printf "%s\"; break;\n", substr(s,7);
|
||||
}
|
||||
'
|
||||
|
||||
cat <<EOF
|
||||
default: s = "Unknown_Error"; break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
EOF
|
226
common/signal.c
226
common/signal.c
@ -1,226 +0,0 @@
|
||||
/* signal.c - signal handling
|
||||
* Copyright (C) 1998, 1999, 2000, 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
|
||||
static volatile int caught_fatal_sig = 0;
|
||||
static volatile int caught_sigusr1 = 0;
|
||||
static void (*cleanup_fnc)(void);
|
||||
|
||||
|
||||
static void
|
||||
init_one_signal (int sig, RETSIGTYPE (*handler)(int), int check_ign )
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
# ifdef HAVE_SIGACTION
|
||||
struct sigaction oact, nact;
|
||||
|
||||
if (check_ign)
|
||||
{
|
||||
/* we don't want to change an IGN handler */
|
||||
sigaction (sig, NULL, &oact );
|
||||
if (oact.sa_handler == SIG_IGN )
|
||||
return;
|
||||
}
|
||||
|
||||
nact.sa_handler = handler;
|
||||
sigemptyset (&nact.sa_mask);
|
||||
nact.sa_flags = 0;
|
||||
sigaction ( sig, &nact, NULL);
|
||||
# else
|
||||
RETSIGTYPE (*ohandler)(int);
|
||||
|
||||
ohandler = signal (sig, handler);
|
||||
if (check_ign && ohandler == SIG_IGN)
|
||||
{
|
||||
/* Change it back if it was already set to IGN */
|
||||
signal (sig, SIG_IGN);
|
||||
}
|
||||
# endif
|
||||
#endif /*!HAVE_DOSISH_SYSTEM*/
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_signal_name( int signum )
|
||||
{
|
||||
#if defined(SYS_SIGLIST_DECLARED) && defined(NSIG)
|
||||
return (signum >= 0 && signum < NSIG) ? sys_siglist[signum] : "?";
|
||||
#else
|
||||
return "some signal";
|
||||
#endif
|
||||
}
|
||||
|
||||
static RETSIGTYPE
|
||||
got_fatal_signal (int sig)
|
||||
{
|
||||
const char *s;
|
||||
|
||||
if (caught_fatal_sig)
|
||||
raise (sig);
|
||||
caught_fatal_sig = 1;
|
||||
|
||||
if (cleanup_fnc)
|
||||
cleanup_fnc ();
|
||||
/* better don't translate these messages */
|
||||
write (2, "\n", 1 );
|
||||
s = log_get_prefix (NULL);
|
||||
if (s)
|
||||
write(2, s, strlen (s));
|
||||
write (2, ": ", 2 );
|
||||
s = get_signal_name(sig);
|
||||
write (2, s, strlen(s) );
|
||||
write (2, " caught ... exiting\n", 20);
|
||||
|
||||
/* reset action to default action and raise signal again */
|
||||
init_one_signal (sig, SIG_DFL, 0);
|
||||
/* fixme: remove_lockfiles ();*/
|
||||
#ifdef __riscos__
|
||||
close_fds ();
|
||||
#endif /* __riscos__ */
|
||||
raise( sig );
|
||||
}
|
||||
|
||||
|
||||
static RETSIGTYPE
|
||||
got_usr_signal (int sig)
|
||||
{
|
||||
caught_sigusr1 = 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gnupg_init_signals (int mode, void (*fast_cleanup)(void))
|
||||
{
|
||||
assert (!mode);
|
||||
|
||||
cleanup_fnc = fast_cleanup;
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
init_one_signal (SIGINT, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGHUP, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGTERM, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGQUIT, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGSEGV, got_fatal_signal, 1 );
|
||||
init_one_signal (SIGUSR1, got_usr_signal, 0 );
|
||||
init_one_signal (SIGPIPE, SIG_IGN, 0 );
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
gnupg_pause_on_sigusr (int which)
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
# ifdef HAVE_SIGPROCMASK
|
||||
sigset_t mask, oldmask;
|
||||
|
||||
assert (which == 1);
|
||||
sigemptyset( &mask );
|
||||
sigaddset( &mask, SIGUSR1 );
|
||||
|
||||
sigprocmask( SIG_BLOCK, &mask, &oldmask );
|
||||
while (!caught_sigusr1)
|
||||
sigsuspend (&oldmask);
|
||||
caught_sigusr1 = 0;
|
||||
sigprocmask (SIG_UNBLOCK, &mask, NULL);
|
||||
# else
|
||||
assert (which == 1);
|
||||
sighold (SIGUSR1);
|
||||
while (!caught_sigusr1)
|
||||
sigpause(SIGUSR1);
|
||||
caught_sigusr1 = 0;
|
||||
sigrelease(SIGUSR1);
|
||||
# endif /*!HAVE_SIGPROCMASK*/
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
do_block( int block )
|
||||
{
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
static int is_blocked;
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
static sigset_t oldmask;
|
||||
|
||||
if (block)
|
||||
{
|
||||
sigset_t newmask;
|
||||
|
||||
if (is_blocked)
|
||||
log_bug ("signals are already blocked\n");
|
||||
sigfillset( &newmask );
|
||||
sigprocmask( SIG_BLOCK, &newmask, &oldmask );
|
||||
is_blocked = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_blocked)
|
||||
log_bug("signals are not blocked\n");
|
||||
sigprocmask (SIG_SETMASK, &oldmask, NULL);
|
||||
is_blocked = 0;
|
||||
}
|
||||
#else /*!HAVE_SIGPROCMASK*/
|
||||
static void (*disposition[MAXSIG])();
|
||||
int sig;
|
||||
|
||||
if (block)
|
||||
{
|
||||
if (is_blocked)
|
||||
log_bug("signals are already blocked\n");
|
||||
for (sig=1; sig < MAXSIG; sig++)
|
||||
{
|
||||
disposition[sig] = sigset (sig, SIG_HOLD);
|
||||
}
|
||||
is_blocked = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!is_blocked)
|
||||
log_bug ("signals are not blocked\n");
|
||||
for (sig=1; sig < MAXSIG; sig++) {
|
||||
sigset (sig, disposition[sig]);
|
||||
}
|
||||
is_blocked = 0;
|
||||
}
|
||||
#endif /*!HAVE_SIGPROCMASK*/
|
||||
#endif /*HAVE_DOSISH_SYSTEM*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gnupg_block_all_signals ()
|
||||
{
|
||||
do_block(1);
|
||||
}
|
||||
|
||||
void
|
||||
gnupg_unblock_all_signals ()
|
||||
{
|
||||
do_block(0);
|
||||
}
|
@ -1,206 +0,0 @@
|
||||
/* sysutils.c - system helpers
|
||||
* Copyright (C) 1998, 1999, 2000, 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_STAT
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
|
||||
#include <asm/sysinfo.h>
|
||||
#include <asm/unistd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#endif
|
||||
#include "util.h"
|
||||
#include "i18n.h"
|
||||
|
||||
#include "sysutils.h"
|
||||
|
||||
#if defined(__linux__) && defined(__alpha__) && __GLIBC__ < 2
|
||||
#warning using trap_unaligned
|
||||
static int
|
||||
setsysinfo(unsigned long op, void *buffer, unsigned long size,
|
||||
int *start, void *arg, unsigned long flag)
|
||||
{
|
||||
return syscall(__NR_osf_setsysinfo, op, buffer, size, start, arg, flag);
|
||||
}
|
||||
|
||||
void
|
||||
trap_unaligned(void)
|
||||
{
|
||||
unsigned int buf[2];
|
||||
|
||||
buf[0] = SSIN_UACPROC;
|
||||
buf[1] = UAC_SIGBUS | UAC_NOPRINT;
|
||||
setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0);
|
||||
}
|
||||
#else
|
||||
void
|
||||
trap_unaligned(void)
|
||||
{ /* dummy */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
disable_core_dumps (void)
|
||||
{
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
return 0;
|
||||
#else
|
||||
#ifdef HAVE_SETRLIMIT
|
||||
struct rlimit limit;
|
||||
|
||||
limit.rlim_cur = 0;
|
||||
limit.rlim_max = 0;
|
||||
if( !setrlimit( RLIMIT_CORE, &limit ) )
|
||||
return 0;
|
||||
if( errno != EINVAL && errno != ENOSYS )
|
||||
log_fatal (_("can't disable core dumps: %s\n"), strerror(errno) );
|
||||
#endif
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return a string which is used as a kind of process ID */
|
||||
const byte *
|
||||
get_session_marker( size_t *rlen )
|
||||
{
|
||||
static byte marker[SIZEOF_UNSIGNED_LONG*2];
|
||||
static int initialized;
|
||||
|
||||
if ( !initialized ) {
|
||||
volatile ulong aa, bb; /* we really want the uninitialized value */
|
||||
ulong a, b;
|
||||
|
||||
initialized = 1;
|
||||
/* also this marker is guessable it is not easy to use this
|
||||
* for a faked control packet because an attacker does not
|
||||
* have enough control about the time the verification does
|
||||
* take place. Of course, we can add just more random but
|
||||
* than we need the random generator even for verification
|
||||
* tasks - which does not make sense. */
|
||||
a = aa ^ (ulong)getpid();
|
||||
b = bb ^ (ulong)time(NULL);
|
||||
memcpy( marker, &a, SIZEOF_UNSIGNED_LONG );
|
||||
memcpy( marker+SIZEOF_UNSIGNED_LONG, &b, SIZEOF_UNSIGNED_LONG );
|
||||
}
|
||||
*rlen = sizeof(marker);
|
||||
return marker;
|
||||
}
|
||||
|
||||
|
||||
#if 0 /* not yet needed */
|
||||
int
|
||||
check_permissions(const char *path,int extension,int checkonly)
|
||||
{
|
||||
#if defined(HAVE_STAT) && !defined(HAVE_DOSISH_SYSTEM)
|
||||
char *tmppath;
|
||||
struct stat statbuf;
|
||||
int ret=1;
|
||||
int isdir=0;
|
||||
|
||||
if(opt.no_perm_warn)
|
||||
return 0;
|
||||
|
||||
if(extension && path[0]!=DIRSEP_C)
|
||||
{
|
||||
if(strchr(path,DIRSEP_C))
|
||||
tmppath=make_filename(path,NULL);
|
||||
else
|
||||
tmppath=make_filename(GNUPG_LIBDIR,path,NULL);
|
||||
}
|
||||
else
|
||||
tmppath=m_strdup(path);
|
||||
|
||||
/* It's okay if the file doesn't exist */
|
||||
if(stat(tmppath,&statbuf)!=0)
|
||||
{
|
||||
ret=0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
isdir=S_ISDIR(statbuf.st_mode);
|
||||
|
||||
/* Per-user files must be owned by the user. Extensions must be
|
||||
owned by the user or root. */
|
||||
if((!extension && statbuf.st_uid != getuid()) ||
|
||||
(extension && statbuf.st_uid!=0 && statbuf.st_uid!=getuid()))
|
||||
{
|
||||
if(!checkonly)
|
||||
log_info(_("Warning: unsafe ownership on %s \"%s\"\n"),
|
||||
isdir?"directory":extension?"extension":"file",path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* This works for both directories and files - basically, we don't
|
||||
care what the owner permissions are, so long as the group and
|
||||
other permissions are 0 for per-user files, and non-writable for
|
||||
extensions. */
|
||||
if((extension && (statbuf.st_mode & (S_IWGRP|S_IWOTH)) !=0) ||
|
||||
(!extension && (statbuf.st_mode & (S_IRWXG|S_IRWXO)) != 0))
|
||||
{
|
||||
char *dir;
|
||||
|
||||
/* However, if the directory the directory/file is in is owned
|
||||
by the user and is 700, then this is not a problem.
|
||||
Theoretically, we could walk this test up to the root
|
||||
directory /, but for the sake of sanity, I'm stopping at one
|
||||
level down. */
|
||||
|
||||
dir= make_dirname (tmppath);
|
||||
if(stat(dir,&statbuf)==0 && statbuf.st_uid==getuid() &&
|
||||
S_ISDIR(statbuf.st_mode) && (statbuf.st_mode & (S_IRWXG|S_IRWXO))==0)
|
||||
{
|
||||
xfree (dir);
|
||||
ret=0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
m_free(dir);
|
||||
|
||||
if(!checkonly)
|
||||
log_info(_("Warning: unsafe permissions on %s \"%s\"\n"),
|
||||
isdir?"directory":extension?"extension":"file",path);
|
||||
goto end;
|
||||
}
|
||||
|
||||
ret=0;
|
||||
|
||||
end:
|
||||
m_free(tmppath);
|
||||
|
||||
return ret;
|
||||
|
||||
#endif /* HAVE_STAT && !HAVE_DOSISH_SYSTEM */
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
@ -1,30 +0,0 @@
|
||||
/* sysutils.h - System utility functions for Gnupg
|
||||
* 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 GNUPG_COMMON_SYSUTILS_H
|
||||
#define GNUPG_COMMON_SYSUTILS_H
|
||||
|
||||
void trap_unaligned (void);
|
||||
int disable_core_dumps (void);
|
||||
const unsigned char *get_session_marker (size_t *rlen);
|
||||
int check_permissions (const char *path,int extension,int checkonly);
|
||||
|
||||
|
||||
#endif /*GNUPG_COMMON_SYSUTILS_H*/
|
117
common/util.h
117
common/util.h
@ -1,117 +0,0 @@
|
||||
/* util.h - Utility functions for Gnupg
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef GNUPG_COMMON_UTIL_H
|
||||
#define GNUPG_COMMON_UTIL_H
|
||||
|
||||
#include <gcrypt.h> /* we need this for the memory function protos */
|
||||
#include <time.h> /* we need time_t */
|
||||
|
||||
/* to pass hash functions to libksba we need to cast it */
|
||||
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
|
||||
|
||||
/* get all the stuff from jnlib */
|
||||
#include "../jnlib/logging.h"
|
||||
#include "../jnlib/argparse.h"
|
||||
#include "../jnlib/stringhelp.h"
|
||||
#include "../jnlib/mischelp.h"
|
||||
#include "../jnlib/strlist.h"
|
||||
#include "../jnlib/dotlock.h"
|
||||
|
||||
/* handy malloc macros - use only them */
|
||||
#define xtrymalloc(a) gcry_malloc ((a))
|
||||
#define xtrycalloc(a,b) gcry_calloc ((a),(b))
|
||||
#define xtryrealloc(a,b) gcry_realloc ((a),(b))
|
||||
#define xtrystrdup(a) gcry_strdup ((a))
|
||||
#define xfree(a) gcry_free ((a))
|
||||
|
||||
#define xmalloc(a) gcry_xmalloc ((a))
|
||||
#define xcalloc(a,b) gcry_xcalloc ((a),(b))
|
||||
#define xrealloc(a,b) gcry_xrealloc ((a),(b))
|
||||
#define xstrdup(a) gcry_xstrdup ((a))
|
||||
|
||||
#define seterr(a) (GNUPG_ ## a)
|
||||
|
||||
/*-- maperror.c --*/
|
||||
int map_ksba_err (int err);
|
||||
int map_gcry_err (int err);
|
||||
int map_kbx_err (int err);
|
||||
int map_assuan_err (int err);
|
||||
int map_to_assuan_status (int rc);
|
||||
|
||||
/*-- gettime.c --*/
|
||||
time_t gnupg_get_time (void);
|
||||
void gnupg_set_time (time_t newtime, int freeze);
|
||||
int gnupg_faked_time_p (void);
|
||||
|
||||
/*-- signal.c --*/
|
||||
void gnupg_init_signals (int mode, void (*fast_cleanup)(void));
|
||||
void gnupg_pause_on_sigusr (int which);
|
||||
void gnupg_block_all_signals (void);
|
||||
void gnupg_unblock_all_signals (void);
|
||||
|
||||
|
||||
/*-- replacement functions from funcname.c --*/
|
||||
#if !HAVE_VASPRINTF
|
||||
#include <stdarg.h>
|
||||
int vasprintf (char **result, const char *format, va_list *args);
|
||||
int asprintf (char **result, const char *format, ...);
|
||||
#endif
|
||||
|
||||
#if !HAVE_FOPENCOOKIE
|
||||
typedef struct
|
||||
{
|
||||
ssize_t (*read)(void*,char*,size_t);
|
||||
ssize_t (*write)(void*,const char*,size_t);
|
||||
int (*seek)(void*,off_t*,int);
|
||||
int (*close)(void*);
|
||||
} _IO_cookie_io_functions_t;
|
||||
typedef _IO_cookie_io_functions_t cookie_io_functions_t;
|
||||
FILE *fopencookie (void *cookie, const char *opentype,
|
||||
cookie_io_functions_t funclist);
|
||||
#endif /*!HAVE_FOPENCOOKIE*/
|
||||
|
||||
|
||||
|
||||
/*-- some macros to replace ctype ones and avoid locale problems --*/
|
||||
#define spacep(p) (*(p) == ' ' || *(p) == '\t')
|
||||
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
|
||||
#define hexdigitp(a) (digitp (a) \
|
||||
|| (*(a) >= 'A' && *(a) <= 'F') \
|
||||
|| (*(a) >= 'a' && *(a) <= 'f'))
|
||||
/* the atoi macros assume that the buffer has only valid digits */
|
||||
#define atoi_1(p) (*(p) - '0' )
|
||||
#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
|
||||
#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
|
||||
#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 /*GNUPG_COMMON_UTIL_H*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,169 +0,0 @@
|
||||
/* Like vsprintf but provides a pointer to malloc'd storage, which must
|
||||
be freed by the caller.
|
||||
Copyright (C) 1994, 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of the libiberty library.
|
||||
Libiberty is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
Libiberty 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with libiberty; see the file COPYING.LIB. 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 <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef TEST
|
||||
int global_total_width;
|
||||
#endif
|
||||
|
||||
int
|
||||
vasprintf (char **result, const char *format, va_list *args)
|
||||
{
|
||||
const char *p = format;
|
||||
/* Add one to make sure that it is never zero, which might cause malloc
|
||||
to return NULL. */
|
||||
int total_width = strlen (format) + 1;
|
||||
va_list ap;
|
||||
|
||||
#ifdef va_copy
|
||||
va_copy (ap, args);
|
||||
#else
|
||||
#ifdef __va_copy
|
||||
__va_copy (ap, args);
|
||||
#else
|
||||
memcpy (&ap, args, sizeof (va_list));
|
||||
#endif /* __va_copy */
|
||||
#endif /* va_copy */
|
||||
|
||||
while (*p != '\0')
|
||||
{
|
||||
if (*p++ == '%')
|
||||
{
|
||||
while (strchr ("-+ #0", *p))
|
||||
++p;
|
||||
if (*p == '*')
|
||||
{
|
||||
++p;
|
||||
total_width += abs (va_arg (ap, int));
|
||||
}
|
||||
else
|
||||
total_width += strtoul (p, (char**)&p, 10);
|
||||
if (*p == '.')
|
||||
{
|
||||
++p;
|
||||
if (*p == '*')
|
||||
{
|
||||
++p;
|
||||
total_width += abs (va_arg (ap, int));
|
||||
}
|
||||
else
|
||||
total_width += strtoul (p, (char**)&p, 10);
|
||||
}
|
||||
while (strchr ("hlL", *p))
|
||||
++p;
|
||||
/* Should be big enough for any format specifier except %s
|
||||
and floats. */
|
||||
total_width += 30;
|
||||
switch (*p)
|
||||
{
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'c':
|
||||
(void) va_arg (ap, int);
|
||||
break;
|
||||
case 'f':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
(void) va_arg (ap, double);
|
||||
/* Since an ieee double can have an exponent of 307, we'll
|
||||
make the buffer wide enough to cover the gross case. */
|
||||
total_width += 307;
|
||||
break;
|
||||
case 's':
|
||||
{
|
||||
char *tmp = va_arg (ap, char *);
|
||||
if (tmp)
|
||||
total_width += strlen (tmp);
|
||||
else /* in case the vsprintf does prints a text */
|
||||
total_width += 25; /* e.g. "(null pointer reference)" */
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
case 'n':
|
||||
(void) va_arg (ap, char *);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef TEST
|
||||
global_total_width = total_width;
|
||||
#endif
|
||||
*result = malloc (total_width);
|
||||
if (*result != NULL)
|
||||
return vsprintf (*result, format, *args);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
asprintf (char **buf, const char *fmt, ...)
|
||||
{
|
||||
int status;
|
||||
va_list ap;
|
||||
|
||||
va_start (ap, fmt);
|
||||
status = vasprintf (buf, fmt, ap);
|
||||
va_end (ap);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
#ifdef TEST
|
||||
void
|
||||
checkit (const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *result;
|
||||
|
||||
va_start (args, format);
|
||||
vasprintf (&result, format, args);
|
||||
if (strlen (result) < global_total_width)
|
||||
printf ("PASS: ");
|
||||
else
|
||||
printf ("FAIL: ");
|
||||
printf ("%d %s\n", global_total_width, result);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
checkit ("%d", 0x12345678);
|
||||
checkit ("%200d", 5);
|
||||
checkit ("%.300d", 6);
|
||||
checkit ("%100.150d", 7);
|
||||
checkit ("%s", "jjjjjjjjjiiiiiiiiiiiiiiioooooooooooooooooppppppppppppaa\n\
|
||||
777777777777777777333333333333366666666666622222222222777777777777733333");
|
||||
checkit ("%f%s%d%s", 1.0, "foo", 77, "asdjffffffffffffffiiiiiiiiiiixxxxx");
|
||||
}
|
||||
#endif /* TEST */
|
102
kbx/ChangeLog
102
kbx/ChangeLog
@ -1,102 +0,0 @@
|
||||
2002-08-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_fpr_part): New.
|
||||
(has_short_kid, has_long_kid): Implemented.
|
||||
|
||||
2002-07-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-defs.h: New BLOBTYPTE_EMPTY.
|
||||
* keybox-dump.c (_keybox_dump_blob): Handle new type.
|
||||
* keybox-file.c (_keybox_read_blob): Skip over empty blobs. Store
|
||||
the file offset.
|
||||
* keybox-blob.c (_keybox_new_blob): Add new arg OFF.
|
||||
(_keybox_get_blob_fileoffset): New.
|
||||
* keybox-update.c (keybox_delete): Implemented.
|
||||
|
||||
2002-06-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-init.c (keybox_set_ephemeral): New.
|
||||
* keybox-blob.c (create_blob_header): Store epheermal flag.
|
||||
(_keybox_create_x509_blob): Pass epheermal flag on.
|
||||
* keybox-update.c (keybox_insert_cert): Ditto.
|
||||
* keybox-search.c (blob_get_blob_flags): New.
|
||||
(keybox_search): Ignore ephemeral blobs when not in ephemeral mode.
|
||||
|
||||
* keybox-dump.c (_keybox_dump_blob): Print blob flags as strings.
|
||||
|
||||
2002-02-25 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_mail): Use case-insensitive compare
|
||||
because mail addresses are in general case insensitive (well
|
||||
RFC2822 allows for case sensitive mailbox parts, but this is in
|
||||
general considired a Bad Thing). Add additional substr parameter
|
||||
to allow for substring matches within the mail address. Change
|
||||
all callers to pass this along.
|
||||
(blob_cmp_name): Likewise but do the case-insensitive search only
|
||||
in sub string mode.
|
||||
(keybox_search): Implement MAILSUB and SUBSTR mode.
|
||||
|
||||
2002-01-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (keybox_search): Allow KEYDB_SEARCH_MODE_FPR20.
|
||||
|
||||
2002-01-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_fpr): New.
|
||||
(has_fingerprint): Implemented;
|
||||
|
||||
2001-12-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-blob.c (_keybox_create_x509_blob): Skip the leading
|
||||
parenthesis of the serial number's S-exp.
|
||||
(_keybox_create_x509_blob): And fixed length calculation.
|
||||
(create_blob_header): Don't add an offset when writing the serial.
|
||||
|
||||
2001-12-18 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am (AM_CPPFLAGS): Add flags for libksba
|
||||
|
||||
* keybox-blob.c (_keybox_create_x509_blob): Use
|
||||
gcry_sexp_canon_len to get the length of the serial number.
|
||||
(_keybox_release_blob): Need to use a new serialbuf to free the memory.
|
||||
|
||||
2001-12-17 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c: Changed the way the serial number is
|
||||
represented.
|
||||
|
||||
2001-12-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_name): There is no terminating 0 stored
|
||||
for the uid; fixed length compare.
|
||||
|
||||
2001-12-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-blob.c (x509_email_kludge): New.
|
||||
(_keybox_create_x509_blob): Insert an extra email address if the
|
||||
subject's DN has an email part.
|
||||
* keybox-defs.h: Added the xtoi_2 and digitp macros.
|
||||
|
||||
2001-12-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keybox-search.c (blob_cmp_name): Kludge to allow searching for
|
||||
more than one name.
|
||||
(has_subject_or_alt): New.
|
||||
(blob_cmp_mail): New.
|
||||
(has_mail): New.
|
||||
(keybox_search): Implemented exact search and exact mail search.
|
||||
|
||||
* kbx/keybox-blob.c (_keybox_create_x509_blob): Insert alternate
|
||||
names.
|
||||
|
||||
|
||||
Copyright 2001 g10 Code GmbH
|
||||
|
||||
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.
|
||||
|
@ -1,53 +0,0 @@
|
||||
# Keybox Makefile
|
||||
# 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
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\"
|
||||
|
||||
EXTRA_DIST = mkerrors
|
||||
AM_CPPFLAGS = $(KSBA_CFLAGS) $(LIBGCRYPT_CLFAGS)
|
||||
BUILT_SOURCES = keybox-errors.c
|
||||
|
||||
noinst_LIBRARIES = libkeybox.a
|
||||
bin_PROGRAMS = kbxutil
|
||||
|
||||
common_sources = \
|
||||
keybox.h keybox-defs.h keybox-search-desc.h \
|
||||
keybox-util.c \
|
||||
keybox-errors.c \
|
||||
keybox-init.c \
|
||||
keybox-blob.c \
|
||||
keybox-file.c \
|
||||
keybox-search.c \
|
||||
keybox-update.c \
|
||||
keybox-dump.c
|
||||
|
||||
|
||||
libkeybox_a_SOURCES = $(common_sources)
|
||||
|
||||
kbxutil_SOURCES = kbxutil.c $(common_sources)
|
||||
kbxutil_LDADD = ../jnlib/libjnlib.a $(KSBA_LIBS) $(LIBGCRYPT_LIBS)
|
||||
|
||||
keybox-errors.c : keybox.h mkerrors
|
||||
$(srcdir)/mkerrors < $(srcdir)/keybox.h > keybox-errors.c
|
||||
|
||||
|
||||
|
338
kbx/kbxutil.c
338
kbx/kbxutil.c
@ -1,338 +0,0 @@
|
||||
/* kbxutil.c - The Keybox utility
|
||||
* Copyright (C) 2000, 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "../jnlib/logging.h"
|
||||
#include "../jnlib/argparse.h"
|
||||
#include "../jnlib/stringhelp.h"
|
||||
#include "../common/i18n.h"
|
||||
#include "keybox-defs.h"
|
||||
|
||||
enum cmd_and_opt_values {
|
||||
aNull = 0,
|
||||
oArmor = 'a',
|
||||
oDryRun = 'n',
|
||||
oOutput = 'o',
|
||||
oQuiet = 'q',
|
||||
oVerbose = 'v',
|
||||
|
||||
aNoSuchCmd = 500, /* force other values not to be a letter */
|
||||
aFindByFpr,
|
||||
aFindByKid,
|
||||
aFindByUid,
|
||||
|
||||
oDebug,
|
||||
oDebugAll,
|
||||
|
||||
oNoArmor,
|
||||
|
||||
|
||||
aTest
|
||||
};
|
||||
|
||||
|
||||
static ARGPARSE_OPTS opts[] = {
|
||||
{ 300, NULL, 0, N_("@Commands:\n ") },
|
||||
|
||||
{ aFindByFpr, "find-by-fpr", 0, "|FPR| find key using it's fingerprnt" },
|
||||
{ aFindByKid, "find-by-kid", 0, "|KID| find key using it's keyid" },
|
||||
{ aFindByUid, "find-by-uid", 0, "|NAME| find key by user name" },
|
||||
|
||||
{ 301, NULL, 0, N_("@\nOptions:\n ") },
|
||||
|
||||
{ oArmor, "armor", 0, N_("create ascii armored output")},
|
||||
{ oArmor, "armour", 0, "@" },
|
||||
{ oOutput, "output", 2, N_("use as output file")},
|
||||
{ oVerbose, "verbose", 0, N_("verbose") },
|
||||
{ oQuiet, "quiet", 0, N_("be somewhat more quiet") },
|
||||
{ oDryRun, "dry-run", 0, N_("do not make any changes") },
|
||||
|
||||
{ oDebug, "debug" ,4|16, N_("set debugging flags")},
|
||||
{ oDebugAll, "debug-all" ,0, N_("enable full debugging")},
|
||||
|
||||
{0} /* end of list */
|
||||
};
|
||||
|
||||
|
||||
void myexit (int rc);
|
||||
|
||||
int keybox_errors_seen = 0;
|
||||
|
||||
|
||||
static const char *
|
||||
my_strusage( int level )
|
||||
{
|
||||
const char *p;
|
||||
switch( level ) {
|
||||
case 11: p = "kbxutil (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: kbxutil [options] [files] (-h for help)");
|
||||
break;
|
||||
case 41: p =
|
||||
_("Syntax: kbxutil [options] [files]\n"
|
||||
"list, export, import Keybox data\n");
|
||||
break;
|
||||
|
||||
|
||||
default: p = NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
i18n_init(void)
|
||||
{
|
||||
#ifdef USE_SIMPLE_GETTEXT
|
||||
set_gettext_file( PACKAGE );
|
||||
#else
|
||||
#ifdef ENABLE_NLS
|
||||
#ifdef HAVE_LC_MESSAGES
|
||||
setlocale( LC_TIME, "" );
|
||||
setlocale( LC_MESSAGES, "" );
|
||||
#else
|
||||
setlocale( LC_ALL, "" );
|
||||
#endif
|
||||
bindtextdomain( PACKAGE, LOCALEDIR );
|
||||
textdomain( PACKAGE );
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/* static void */
|
||||
/* wrong_args( const char *text ) */
|
||||
/* { */
|
||||
/* log_error("usage: kbxutil %s\n", text); */
|
||||
/* myexit ( 1 ); */
|
||||
/* } */
|
||||
|
||||
|
||||
#if 0
|
||||
static int
|
||||
hextobyte( const byte *s )
|
||||
{
|
||||
int c;
|
||||
|
||||
if( *s >= '0' && *s <= '9' )
|
||||
c = 16 * (*s - '0');
|
||||
else if( *s >= 'A' && *s <= 'F' )
|
||||
c = 16 * (10 + *s - 'A');
|
||||
else if( *s >= 'a' && *s <= 'f' )
|
||||
c = 16 * (10 + *s - 'a');
|
||||
else
|
||||
return -1;
|
||||
s++;
|
||||
if( *s >= '0' && *s <= '9' )
|
||||
c += *s - '0';
|
||||
else if( *s >= 'A' && *s <= 'F' )
|
||||
c += 10 + *s - 'A';
|
||||
else if( *s >= 'a' && *s <= 'f' )
|
||||
c += 10 + *s - 'a';
|
||||
else
|
||||
return -1;
|
||||
return c;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static char *
|
||||
format_fingerprint ( const char *s )
|
||||
{
|
||||
int i, c;
|
||||
byte fpr[20];
|
||||
|
||||
for (i=0; i < 20 && *s; ) {
|
||||
if ( *s == ' ' || *s == '\t' ) {
|
||||
s++;
|
||||
continue;
|
||||
}
|
||||
c = hextobyte(s);
|
||||
if (c == -1) {
|
||||
return NULL;
|
||||
}
|
||||
fpr[i++] = c;
|
||||
s += 2;
|
||||
}
|
||||
return gcry_xstrdup ( fpr );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
static int
|
||||
format_keyid ( const char *s, u32 *kid )
|
||||
{
|
||||
char helpbuf[9];
|
||||
switch ( strlen ( s ) ) {
|
||||
case 8:
|
||||
kid[0] = 0;
|
||||
kid[1] = strtoul( s, NULL, 16 );
|
||||
return 10;
|
||||
|
||||
case 16:
|
||||
mem2str( helpbuf, s, 9 );
|
||||
kid[0] = strtoul( helpbuf, NULL, 16 );
|
||||
kid[1] = strtoul( s+8, NULL, 16 );
|
||||
return 11;
|
||||
}
|
||||
return 0; /* error */
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
int
|
||||
main( int argc, char **argv )
|
||||
{
|
||||
ARGPARSE_ARGS pargs;
|
||||
enum cmd_and_opt_values cmd = 0;
|
||||
|
||||
set_strusage( my_strusage );
|
||||
/*log_set_name("kbxutil"); fixme */
|
||||
#if 0
|
||||
/* check that the libraries are suitable. Do it here because
|
||||
* the option parse may need services of the library */
|
||||
if ( !gcry_check_version ( "1.1.4" ) )
|
||||
{
|
||||
log_fatal(_("libgcrypt is too old (need %s, have %s)\n"),
|
||||
"1.1.4", gcry_check_version(NULL) );
|
||||
}
|
||||
#endif
|
||||
|
||||
/*create_dotlock(NULL); register locking cleanup */
|
||||
i18n_init();
|
||||
|
||||
/* We need to use the gcry malloc function because jnlib does use them */
|
||||
keybox_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
|
||||
ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free );
|
||||
|
||||
|
||||
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++;*/
|
||||
/*gcry_control( GCRYCTL_SET_VERBOSITY, (int)opt.verbose );*/
|
||||
break;
|
||||
case oDebug:
|
||||
/*opt.debug |= pargs.r.ret_ulong; */
|
||||
break;
|
||||
case oDebugAll:
|
||||
/*opt.debug = ~0;*/
|
||||
break;
|
||||
|
||||
case aFindByFpr:
|
||||
case aFindByKid:
|
||||
case aFindByUid:
|
||||
cmd = pargs.r_opt;
|
||||
break;
|
||||
|
||||
default:
|
||||
pargs.err = 2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (log_get_errorcount(0) )
|
||||
myexit(2);
|
||||
|
||||
if (!cmd)
|
||||
{ /* default is to list a KBX file */
|
||||
if (!argc)
|
||||
_keybox_dump_file (NULL, stdout);
|
||||
else
|
||||
{
|
||||
for (; argc; argc--, argv++)
|
||||
_keybox_dump_file (*argv, stdout);
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
else if ( cmd == aFindByFpr ) {
|
||||
char *fpr;
|
||||
if ( argc != 2 )
|
||||
wrong_args ("kbxfile foingerprint");
|
||||
fpr = format_fingerprint ( argv[1] );
|
||||
if ( !fpr )
|
||||
log_error ("invalid formatted fingerprint\n");
|
||||
else {
|
||||
kbxfile_search_by_fpr ( argv[0], fpr );
|
||||
gcry_free ( fpr );
|
||||
}
|
||||
}
|
||||
else if ( cmd == aFindByKid ) {
|
||||
u32 kid[2];
|
||||
int mode;
|
||||
|
||||
if ( argc != 2 )
|
||||
wrong_args ("kbxfile short-or-long-keyid");
|
||||
mode = format_keyid ( argv[1], kid );
|
||||
if ( !mode )
|
||||
log_error ("invalid formatted keyID\n");
|
||||
else {
|
||||
kbxfile_search_by_kid ( argv[0], kid, mode );
|
||||
}
|
||||
}
|
||||
else if ( cmd == aFindByUid ) {
|
||||
if ( argc != 2 )
|
||||
wrong_args ("kbxfile userID");
|
||||
kbxfile_search_by_uid ( argv[0], argv[1] );
|
||||
}
|
||||
#endif
|
||||
else
|
||||
log_error ("unsupported action\n");
|
||||
|
||||
myexit(0);
|
||||
return 8; /*NEVER REACHED*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
myexit( int rc )
|
||||
{
|
||||
/* 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 ); */
|
||||
rc = rc? rc : log_get_errorcount(0)? 2 :
|
||||
keybox_errors_seen? 1 : 0;
|
||||
exit(rc );
|
||||
}
|
||||
|
||||
|
1007
kbx/keybox-blob.c
1007
kbx/keybox-blob.c
File diff suppressed because it is too large
Load Diff
@ -1,179 +0,0 @@
|
||||
/* keybox-defs.h - interal Keybox defintions
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef KEYBOX_DEFS_H
|
||||
#define KEYBOX_DEFS_H 1
|
||||
|
||||
#include <sys/types.h> /* off_t */
|
||||
#include "keybox.h"
|
||||
|
||||
#ifndef HAVE_BYTE_TYPEDEF
|
||||
typedef unsigned char byte; /* fixme */
|
||||
#endif
|
||||
#ifndef HAVE_U16_TYPEDEF
|
||||
typedef unsigned short u16; /* fixme */
|
||||
#endif
|
||||
#ifndef HAVE_U32_TYPEDEF
|
||||
typedef unsigned int u32; /* fixme */
|
||||
#endif
|
||||
|
||||
enum {
|
||||
BLOBTYPE_EMPTY = 0,
|
||||
BLOBTYPE_HEADER = 1,
|
||||
BLOBTYPE_PGP = 2,
|
||||
BLOBTYPE_X509 = 3
|
||||
};
|
||||
|
||||
|
||||
typedef struct keyboxblob *KEYBOXBLOB;
|
||||
|
||||
|
||||
typedef struct keybox_name *KB_NAME;
|
||||
typedef struct keybox_name const * CONST_KB_NAME;
|
||||
struct keybox_name {
|
||||
struct keybox_name *next;
|
||||
int secret;
|
||||
/*DOTLOCK lockhd;*/
|
||||
int is_locked;
|
||||
int did_full_scan;
|
||||
char fname[1];
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct keybox_handle {
|
||||
CONST_KB_NAME kb;
|
||||
int secret; /* this is for a secret keybox */
|
||||
FILE *fp;
|
||||
int eof;
|
||||
int error;
|
||||
int ephemeral;
|
||||
struct {
|
||||
KEYBOXBLOB blob;
|
||||
off_t offset;
|
||||
size_t pk_no;
|
||||
size_t uid_no;
|
||||
unsigned int n_packets; /*used for delete and update*/
|
||||
} found;
|
||||
struct {
|
||||
char *name;
|
||||
char *pattern;
|
||||
} word_match;
|
||||
};
|
||||
|
||||
|
||||
/* Don't know whether this is needed: */
|
||||
/* static struct { */
|
||||
/* const char *homedir; */
|
||||
/* int dry_run; */
|
||||
/* int quiet; */
|
||||
/* int verbose; */
|
||||
/* int preserve_permissions; */
|
||||
/* } keybox_opt; */
|
||||
|
||||
|
||||
/*-- keybox-blob.c --*/
|
||||
#ifdef KEYBOX_WITH_OPENPGP
|
||||
/* fixme */
|
||||
#endif /*KEYBOX_WITH_OPENPGP*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
int _keybox_create_x509_blob (KEYBOXBLOB *r_blob, KsbaCert cert,
|
||||
unsigned char *sha1_digest, int as_ephemeral);
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
||||
int _keybox_new_blob (KEYBOXBLOB *r_blob, char *image, size_t imagelen,
|
||||
off_t off);
|
||||
void _keybox_release_blob (KEYBOXBLOB blob);
|
||||
const char *_keybox_get_blob_image (KEYBOXBLOB blob, size_t *n);
|
||||
off_t _keybox_get_blob_fileoffset (KEYBOXBLOB blob);
|
||||
|
||||
/*-- keybox-file.c --*/
|
||||
int _keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp);
|
||||
int _keybox_write_blob (KEYBOXBLOB blob, FILE *fp);
|
||||
|
||||
/*-- keybox-dump.c --*/
|
||||
int _keybox_dump_blob (KEYBOXBLOB blob, FILE *fp);
|
||||
int _keybox_dump_file (const char *filename, FILE *outfp);
|
||||
|
||||
|
||||
/*-- keybox-util.c --*/
|
||||
void *_keybox_malloc (size_t n);
|
||||
void *_keybox_calloc (size_t n, size_t m);
|
||||
void *_keybox_realloc (void *p, size_t n);
|
||||
void _keybox_free (void *p);
|
||||
|
||||
#define xtrymalloc(a) _keybox_malloc ((a))
|
||||
#define xtrycalloc(a,b) _keybox_calloc ((a),(b))
|
||||
#define xtryrealloc(a,b) _keybox_realloc((a),(b))
|
||||
#define xfree(a) _keybox_free ((a))
|
||||
|
||||
|
||||
#define DIM(v) (sizeof(v)/sizeof((v)[0]))
|
||||
#define DIMof(type,member) DIM(((type *)0)->member)
|
||||
#ifndef STR
|
||||
#define STR(v) #v
|
||||
#endif
|
||||
#define STR2(v) STR(v)
|
||||
|
||||
/*
|
||||
a couple of handy macros
|
||||
*/
|
||||
|
||||
#define return_if_fail(expr) do { \
|
||||
if (!(expr)) { \
|
||||
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
|
||||
__FILE__, __LINE__, #expr ); \
|
||||
return; \
|
||||
} } while (0)
|
||||
#define return_null_if_fail(expr) do { \
|
||||
if (!(expr)) { \
|
||||
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
|
||||
__FILE__, __LINE__, #expr ); \
|
||||
return NULL; \
|
||||
} } while (0)
|
||||
#define return_val_if_fail(expr,val) do { \
|
||||
if (!(expr)) { \
|
||||
fprintf (stderr, "%s:%d: assertion `%s' failed\n", \
|
||||
__FILE__, __LINE__, #expr ); \
|
||||
return (val); \
|
||||
} } while (0)
|
||||
#define never_reached() do { \
|
||||
fprintf (stderr, "%s:%d: oops; should never get here\n", \
|
||||
__FILE__, __LINE__ ); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* some macros to replace ctype ones and avoid locale problems */
|
||||
#define digitp(p) (*(p) >= '0' && *(p) <= '9')
|
||||
#define hexdigitp(a) (digitp (a) \
|
||||
|| (*(a) >= 'A' && *(a) <= 'F') \
|
||||
|| (*(a) >= 'a' && *(a) <= 'f'))
|
||||
/* the atoi macros assume that the buffer has only valid digits */
|
||||
#define atoi_1(p) (*(p) - '0' )
|
||||
#define atoi_2(p) ((atoi_1(p) * 10) + atoi_1((p)+1))
|
||||
#define atoi_4(p) ((atoi_2(p) * 100) + atoi_2((p)+2))
|
||||
#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 /*KEYBOX_DEFS_H*/
|
||||
|
||||
|
@ -1,346 +0,0 @@
|
||||
/* keybox-dump.c - Debug helpers
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
static ulong
|
||||
get32 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 24;
|
||||
a |= buffer[1] << 16;
|
||||
a |= buffer[2] << 8;
|
||||
a |= buffer[3];
|
||||
return a;
|
||||
}
|
||||
|
||||
static ulong
|
||||
get16 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 8;
|
||||
a |= buffer[1];
|
||||
return a;
|
||||
}
|
||||
|
||||
void
|
||||
print_string (FILE *fp, const byte *p, size_t n, int delim)
|
||||
{
|
||||
for ( ; n; n--, p++ )
|
||||
{
|
||||
if (*p < 0x20 || (*p >= 0x7f && *p < 0xa0) || *p == delim)
|
||||
{
|
||||
putc('\\', fp);
|
||||
if( *p == '\n' )
|
||||
putc('n', fp);
|
||||
else if( *p == '\r' )
|
||||
putc('r', fp);
|
||||
else if( *p == '\f' )
|
||||
putc('f', fp);
|
||||
else if( *p == '\v' )
|
||||
putc('v', fp);
|
||||
else if( *p == '\b' )
|
||||
putc('b', fp);
|
||||
else if( !*p )
|
||||
putc('0', fp);
|
||||
else
|
||||
fprintf(fp, "x%02x", *p );
|
||||
}
|
||||
else
|
||||
putc(*p, fp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
dump_header_blob (const byte *buffer, size_t length, FILE *fp)
|
||||
{
|
||||
fprintf (fp, "Version: %d\n", buffer[5]);
|
||||
if ( memcmp (buffer+8, "KBXf", 4))
|
||||
fprintf (fp, "[Error: invalid magic number]\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Dump one block to FP */
|
||||
int
|
||||
_keybox_dump_blob (KEYBOXBLOB blob, FILE *fp)
|
||||
{
|
||||
const byte *buffer;
|
||||
size_t length;
|
||||
int type;
|
||||
ulong n, nkeys, keyinfolen;
|
||||
ulong nuids, uidinfolen;
|
||||
ulong nsigs, siginfolen;
|
||||
ulong rawdata_off, rawdata_len;
|
||||
ulong nserial;
|
||||
const byte *p;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
|
||||
if (length < 40)
|
||||
{
|
||||
fprintf (fp, "[blob too short]\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = get32( buffer );
|
||||
if (n > length)
|
||||
fprintf (fp, "[blob larger than length - output truncated]\n");
|
||||
else
|
||||
length = n; /* ignore the rest */
|
||||
|
||||
fprintf (fp, "Length: %lu\n", n );
|
||||
type = buffer[4];
|
||||
switch (type)
|
||||
{
|
||||
case BLOBTYPE_EMPTY:
|
||||
fprintf (fp, "Type: Empty\n");
|
||||
return 0;
|
||||
|
||||
case BLOBTYPE_HEADER:
|
||||
fprintf (fp, "Type: Header\n");
|
||||
return dump_header_blob (buffer, length, fp);
|
||||
case BLOBTYPE_PGP:
|
||||
fprintf (fp, "Type: OpenPGP\n");
|
||||
break;
|
||||
case BLOBTYPE_X509:
|
||||
fprintf (fp, "Type: X.509\n");
|
||||
break;
|
||||
default:
|
||||
fprintf (fp, "Type: %d\n", type);
|
||||
fprintf (fp, "[can't dump this blob type]\n");
|
||||
return 0;
|
||||
}
|
||||
fprintf (fp, "Version: %d\n", buffer[5]);
|
||||
|
||||
n = get16 (buffer + 6);
|
||||
fprintf( fp, "Blob-Flags: %04lX", n);
|
||||
if (n)
|
||||
{
|
||||
int any = 0;
|
||||
|
||||
fputs (" (", fp);
|
||||
if ((n & 1))
|
||||
{
|
||||
fputs ("secret", fp);
|
||||
any++;
|
||||
}
|
||||
if ((n & 2))
|
||||
{
|
||||
if (any)
|
||||
putc (',', fp);
|
||||
fputs ("ephemeral", fp);
|
||||
any++;
|
||||
}
|
||||
putc (')', fp);
|
||||
}
|
||||
putc ('\n', fp);
|
||||
|
||||
rawdata_off = get32 (buffer + 8);
|
||||
rawdata_len = get32 (buffer + 12);
|
||||
|
||||
fprintf( fp, "Data-Offset: %lu\n", rawdata_off );
|
||||
fprintf( fp, "Data-Length: %lu\n", rawdata_len );
|
||||
|
||||
nkeys = get16 (buffer + 16);
|
||||
fprintf (fp, "Key-Count: %lu\n", nkeys );
|
||||
if (!nkeys)
|
||||
fprintf (fp, "[Error: no keys]\n");
|
||||
if (nkeys > 1 && type == BLOBTYPE_X509)
|
||||
fprintf (fp, "[Error: only one key allowed for X509]\n");
|
||||
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
fprintf (fp, "Key-Info-Length: %lu\n", keyinfolen);
|
||||
/* fixme: check bounds */
|
||||
p = buffer + 20;
|
||||
for (n=0; n < nkeys; n++, p += keyinfolen)
|
||||
{
|
||||
int i;
|
||||
ulong kidoff, kflags;
|
||||
|
||||
fprintf (fp, "Key-Fpr[%lu]: ", n );
|
||||
for (i=0; i < 20; i++ )
|
||||
fprintf (fp, "%02X", p[i]);
|
||||
kidoff = get32 (p + 20);
|
||||
fprintf (fp, "\nKey-Kid-Off[%lu]: %lu\n", n, kidoff );
|
||||
fprintf (fp, "Key-Kid[%lu]: ", n );
|
||||
/* fixme: check bounds */
|
||||
for (i=0; i < 8; i++ )
|
||||
fprintf (fp, "%02X", buffer[kidoff+i] );
|
||||
kflags = get16 (p + 24 );
|
||||
fprintf( fp, "\nKey-Flags[%lu]: %04lX\n", n, kflags);
|
||||
}
|
||||
|
||||
/* serial number */
|
||||
fputs ("Serial-No: ", fp);
|
||||
nserial = get16 (p);
|
||||
p += 2;
|
||||
if (!nserial)
|
||||
fputs ("none", fp);
|
||||
else
|
||||
{
|
||||
for (; nserial; nserial--, p++)
|
||||
fprintf (fp, "%02X", *p);
|
||||
}
|
||||
putc ('\n', fp);
|
||||
|
||||
/* user IDs */
|
||||
nuids = get16 (p);
|
||||
fprintf (fp, "Uid-Count: %lu\n", nuids );
|
||||
uidinfolen = get16 (p + 2);
|
||||
fprintf (fp, "Uid-Info-Length: %lu\n", uidinfolen);
|
||||
/* fixme: check bounds */
|
||||
p += 4;
|
||||
for (n=0; n < nuids; n++, p += uidinfolen)
|
||||
{
|
||||
ulong uidoff, uidlen, uflags;
|
||||
|
||||
uidoff = get32( p );
|
||||
uidlen = get32( p+4 );
|
||||
if (type == BLOBTYPE_X509 && !n)
|
||||
{
|
||||
fprintf (fp, "Issuer-Off: %lu\n", uidoff );
|
||||
fprintf (fp, "Issuer-Len: %lu\n", uidlen );
|
||||
fprintf (fp, "Issuer: \"");
|
||||
}
|
||||
else if (type == BLOBTYPE_X509 && n == 1)
|
||||
{
|
||||
fprintf (fp, "Subject-Off: %lu\n", uidoff );
|
||||
fprintf (fp, "Subject-Len: %lu\n", uidlen );
|
||||
fprintf (fp, "Subject: \"");
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (fp, "Uid-Off[%lu]: %lu\n", n, uidoff );
|
||||
fprintf (fp, "Uid-Len[%lu]: %lu\n", n, uidlen );
|
||||
fprintf (fp, "Uid[%lu]: \"", n );
|
||||
}
|
||||
print_string (fp, buffer+uidoff, uidlen, '\"');
|
||||
fputs ("\"\n", fp);
|
||||
uflags = get16 (p + 8);
|
||||
if (type == BLOBTYPE_X509 && !n)
|
||||
{
|
||||
fprintf (fp, "Issuer-Flags: %04lX\n", uflags );
|
||||
fprintf (fp, "Issuer-Validity: %d\n", p[10] );
|
||||
}
|
||||
else if (type == BLOBTYPE_X509 && n == 1)
|
||||
{
|
||||
fprintf (fp, "Subject-Flags: %04lX\n", uflags );
|
||||
fprintf (fp, "Subject-Validity: %d\n", p[10] );
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf (fp, "Uid-Flags[%lu]: %04lX\n", n, uflags );
|
||||
fprintf (fp, "Uid-Validity[%lu]: %d\n", n, p[10] );
|
||||
}
|
||||
}
|
||||
|
||||
nsigs = get16 (p);
|
||||
fprintf (fp, "Sig-Count: %lu\n", nsigs );
|
||||
siginfolen = get16 (p + 2);
|
||||
fprintf (fp, "Sig-Info-Length: %lu\n", siginfolen );
|
||||
/* fixme: check bounds */
|
||||
p += 4;
|
||||
for (n=0; n < nsigs; n++, p += siginfolen)
|
||||
{
|
||||
ulong sflags;
|
||||
|
||||
sflags = get32 (p);
|
||||
fprintf (fp, "Sig-Expire[%lu]: ", n );
|
||||
if (!sflags)
|
||||
fputs ("[not checked]", fp);
|
||||
else if (sflags == 1 )
|
||||
fputs ("[missing key]", fp);
|
||||
else if (sflags == 2 )
|
||||
fputs ("[bad signature]", fp);
|
||||
else if (sflags < 0x10000000)
|
||||
fprintf (fp, "[bad flag %0lx]", sflags);
|
||||
else if (sflags == 0xffffffff)
|
||||
fputs ("0", fp );
|
||||
else
|
||||
fputs ("a time"/*strtimestamp( sflags )*/, fp );
|
||||
putc ('\n', fp );
|
||||
}
|
||||
|
||||
fprintf (fp, "Ownertrust: %d\n", p[0] );
|
||||
fprintf (fp, "All-Validity: %d\n", p[1] );
|
||||
p += 4;
|
||||
n = get32 (p); p += 4;
|
||||
fprintf (fp, "Recheck-After: %s\n", /*n? strtimestamp(n) :*/ "0" );
|
||||
n = get32 (p ); p += 4;
|
||||
fprintf( fp, "Latest-Timestamp: %s\n", "0"/*strtimestamp(n)*/ );
|
||||
n = get32 (p ); p += 4;
|
||||
fprintf (fp, "Created-At: %s\n", "0"/*strtimestamp(n)*/ );
|
||||
n = get32 (p ); p += 4;
|
||||
fprintf (fp, "Reserved-Space: %lu\n", n );
|
||||
|
||||
/* check that the keyblock is at the correct offset and other bounds */
|
||||
/*fprintf (fp, "Blob-Checksum: [MD5-hash]\n");*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
_keybox_dump_file (const char *filename, FILE *outfp)
|
||||
{
|
||||
FILE *fp;
|
||||
KEYBOXBLOB blob;
|
||||
int rc;
|
||||
unsigned long count = 0;
|
||||
|
||||
if (!filename)
|
||||
{
|
||||
filename = "-";
|
||||
fp = stdin;
|
||||
}
|
||||
else
|
||||
fp = fopen (filename, "rb");
|
||||
if (!fp)
|
||||
{
|
||||
fprintf (outfp, "can't open `%s': %s\n", filename, strerror(errno));
|
||||
return KEYBOX_File_Error;
|
||||
}
|
||||
|
||||
while ( !(rc = _keybox_read_blob (&blob, fp)) )
|
||||
{
|
||||
fprintf (outfp, "BEGIN-RECORD: %lu\n", count );
|
||||
_keybox_dump_blob (blob, outfp);
|
||||
_keybox_release_blob (blob);
|
||||
fprintf (outfp, "END-RECORD\n");
|
||||
count++;
|
||||
}
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
if (rc)
|
||||
fprintf (outfp, "error reading `%s': %s\n", filename,
|
||||
rc == KEYBOX_Read_Error? keybox_strerror(rc):strerror (errno));
|
||||
|
||||
if (fp != stdin)
|
||||
fclose (fp);
|
||||
return rc;
|
||||
}
|
@ -1,47 +0,0 @@
|
||||
/* Generated automatically by mkerrors */
|
||||
/* Do not edit! */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "keybox-defs.h"
|
||||
|
||||
/**
|
||||
* keybox_strerror:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* errorcode. If this is an unknown value, a string with the value
|
||||
* is returned (Beware: it is hold in a static buffer).
|
||||
*
|
||||
* Return value: String with the error description.
|
||||
**/
|
||||
const char *
|
||||
keybox_strerror (KeyboxError err)
|
||||
{
|
||||
const char *s;
|
||||
static char buf[25];
|
||||
|
||||
switch (err)
|
||||
{
|
||||
case KEYBOX_No_Error: s="no error"; break;
|
||||
case KEYBOX_General_Error: s="general error"; break;
|
||||
case KEYBOX_Out_Of_Core: s="out of core"; break;
|
||||
case KEYBOX_Invalid_Value: s="invalid value"; break;
|
||||
case KEYBOX_Timeout: s="timeout"; break;
|
||||
case KEYBOX_Read_Error: s="read error"; break;
|
||||
case KEYBOX_Write_Error: s="write error"; break;
|
||||
case KEYBOX_File_Error: s="file error"; break;
|
||||
case KEYBOX_Blob_Too_Short: s="blob too short"; break;
|
||||
case KEYBOX_Blob_Too_Large: s="blob too large"; break;
|
||||
case KEYBOX_Invalid_Handle: s="invalid handle"; break;
|
||||
case KEYBOX_File_Create_Error: s="file create error"; break;
|
||||
case KEYBOX_File_Open_Error: s="file open error"; break;
|
||||
case KEYBOX_File_Close_Error: s="file close error"; break;
|
||||
case KEYBOX_Nothing_Found: s="nothing found"; break;
|
||||
case KEYBOX_Wrong_Blob_Type: s="wrong blob type"; break;
|
||||
case KEYBOX_Missing_Value: s="missing value"; break;
|
||||
default: sprintf (buf, "ec=%d", err ); s=buf; break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
@ -1,102 +0,0 @@
|
||||
/* keybox-file.c - file oeprations
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
/* Read a block at the current postion and return it in r_blob.
|
||||
r_blob may be NULL to simply skip the current block */
|
||||
int
|
||||
_keybox_read_blob (KEYBOXBLOB *r_blob, FILE *fp)
|
||||
{
|
||||
char *image;
|
||||
size_t imagelen = 0;
|
||||
int c1, c2, c3, c4, type;
|
||||
int rc;
|
||||
off_t off;
|
||||
|
||||
again:
|
||||
*r_blob = NULL;
|
||||
off = ftello (fp);
|
||||
if (off == (off_t)-1)
|
||||
return KEYBOX_Read_Error;
|
||||
|
||||
if ((c1 = getc (fp)) == EOF
|
||||
|| (c2 = getc (fp)) == EOF
|
||||
|| (c3 = getc (fp)) == EOF
|
||||
|| (c4 = getc (fp)) == EOF
|
||||
|| (type = getc (fp)) == EOF)
|
||||
{
|
||||
if ( c1 == EOF && !ferror (fp) )
|
||||
return -1; /* eof */
|
||||
return KEYBOX_Read_Error;
|
||||
}
|
||||
|
||||
imagelen = (c1 << 24) | (c2 << 16) | (c3 << 8 ) | c4;
|
||||
if (imagelen > 500000) /* sanity check */
|
||||
return KEYBOX_Blob_Too_Large;
|
||||
|
||||
if (imagelen < 5)
|
||||
return KEYBOX_Blob_Too_Short;
|
||||
|
||||
if (!type)
|
||||
{
|
||||
/* special treatment for empty blobs. */
|
||||
if (fseek (fp, imagelen-5, SEEK_CUR))
|
||||
return KEYBOX_Read_Error;
|
||||
goto again;
|
||||
}
|
||||
|
||||
image = xtrymalloc (imagelen);
|
||||
if (!image)
|
||||
return KEYBOX_Out_Of_Core;
|
||||
|
||||
image[0] = c1; image[1] = c2; image[2] = c3; image[3] = c4; image[4] = type;
|
||||
if (fread (image+5, imagelen-5, 1, fp) != 1)
|
||||
{
|
||||
xfree (image);
|
||||
return KEYBOX_Read_Error;
|
||||
}
|
||||
|
||||
rc = r_blob? _keybox_new_blob (r_blob, image, imagelen, off) : 0;
|
||||
if (rc || !r_blob)
|
||||
xfree (image);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Write the block to the current file position */
|
||||
int
|
||||
_keybox_write_blob (KEYBOXBLOB blob, FILE *fp)
|
||||
{
|
||||
const char *image;
|
||||
size_t length;
|
||||
|
||||
image = _keybox_get_blob_image (blob, &length);
|
||||
if (fwrite (image, length, 1, fp) != 1)
|
||||
{
|
||||
return KEYBOX_Write_Error;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,127 +0,0 @@
|
||||
/* keybox-init.c - Initalization of the library
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
#define compare_filenames strcmp
|
||||
|
||||
static KB_NAME kb_names;
|
||||
|
||||
|
||||
/*
|
||||
Register a filename for plain keybox files. Returns a pointer to be
|
||||
used to create a handles etc or NULL to indicate that it has already
|
||||
been registered */
|
||||
void *
|
||||
keybox_register_file (const char *fname, int secret)
|
||||
{
|
||||
KB_NAME kr;
|
||||
|
||||
for (kr=kb_names; kr; kr = kr->next)
|
||||
{
|
||||
if ( !compare_filenames (kr->fname, fname) )
|
||||
return NULL; /* already registered */
|
||||
}
|
||||
|
||||
kr = xtrymalloc (sizeof *kr + strlen (fname));
|
||||
if (!kr)
|
||||
return NULL;
|
||||
strcpy (kr->fname, fname);
|
||||
kr->secret = !!secret;
|
||||
/* kr->lockhd = NULL;*/
|
||||
kr->is_locked = 0;
|
||||
kr->did_full_scan = 0;
|
||||
/* keep a list of all issued pointers */
|
||||
kr->next = kb_names;
|
||||
kb_names = kr;
|
||||
|
||||
/* create the offset table the first time a function here is used */
|
||||
/* if (!kb_offtbl) */
|
||||
/* kb_offtbl = new_offset_hash_table (); */
|
||||
|
||||
return kr;
|
||||
}
|
||||
|
||||
int
|
||||
keybox_is_writable (void *token)
|
||||
{
|
||||
KB_NAME r = token;
|
||||
|
||||
return r? !access (r->fname, W_OK) : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create a new handle for the resource associated with TOKEN. SECRET
|
||||
is just a cross-check.
|
||||
|
||||
The returned handle must be released using keybox_release (). */
|
||||
KEYBOX_HANDLE
|
||||
keybox_new (void *token, int secret)
|
||||
{
|
||||
KEYBOX_HANDLE hd;
|
||||
KB_NAME resource = token;
|
||||
|
||||
assert (resource && !resource->secret == !secret);
|
||||
hd = xtrycalloc (1, sizeof *hd);
|
||||
if (hd)
|
||||
{
|
||||
hd->kb = resource;
|
||||
hd->secret = !!secret;
|
||||
}
|
||||
return hd;
|
||||
}
|
||||
|
||||
void
|
||||
keybox_release (KEYBOX_HANDLE hd)
|
||||
{
|
||||
if (!hd)
|
||||
return;
|
||||
_keybox_release_blob (hd->found.blob);
|
||||
xfree (hd->word_match.name);
|
||||
xfree (hd->word_match.pattern);
|
||||
xfree (hd);
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
keybox_get_resource_name (KEYBOX_HANDLE hd)
|
||||
{
|
||||
if (!hd || !hd->kb)
|
||||
return NULL;
|
||||
return hd->kb->fname;
|
||||
}
|
||||
|
||||
int
|
||||
keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes)
|
||||
{
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Handle;
|
||||
hd->ephemeral = yes;
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,72 +0,0 @@
|
||||
/* keybox-search-desc.h - Keybox serch description
|
||||
* 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
|
||||
*/
|
||||
|
||||
/*
|
||||
This file is a temporary kludge until we can come up with solution
|
||||
to share this description between keybox and the application
|
||||
specific keydb
|
||||
*/
|
||||
|
||||
#ifndef KEYBOX_SEARCH_DESC_H
|
||||
#define KEYBOX_SEARCH_DESC_H 1
|
||||
|
||||
typedef enum {
|
||||
KEYDB_SEARCH_MODE_NONE,
|
||||
KEYDB_SEARCH_MODE_EXACT,
|
||||
KEYDB_SEARCH_MODE_SUBSTR,
|
||||
KEYDB_SEARCH_MODE_MAIL,
|
||||
KEYDB_SEARCH_MODE_MAILSUB,
|
||||
KEYDB_SEARCH_MODE_MAILEND,
|
||||
KEYDB_SEARCH_MODE_WORDS,
|
||||
KEYDB_SEARCH_MODE_SHORT_KID,
|
||||
KEYDB_SEARCH_MODE_LONG_KID,
|
||||
KEYDB_SEARCH_MODE_FPR16,
|
||||
KEYDB_SEARCH_MODE_FPR20,
|
||||
KEYDB_SEARCH_MODE_FPR,
|
||||
KEYDB_SEARCH_MODE_ISSUER,
|
||||
KEYDB_SEARCH_MODE_ISSUER_SN,
|
||||
KEYDB_SEARCH_MODE_SN,
|
||||
KEYDB_SEARCH_MODE_SUBJECT,
|
||||
KEYDB_SEARCH_MODE_FIRST,
|
||||
KEYDB_SEARCH_MODE_NEXT
|
||||
} KeydbSearchMode;
|
||||
|
||||
struct keydb_search_desc {
|
||||
KeydbSearchMode mode;
|
||||
int (*skipfnc)(void *,void*); /* used to be: void*, u32* */
|
||||
void *skipfncvalue;
|
||||
const unsigned char *sn;
|
||||
int snlen; /* -1 := sn is a hex string */
|
||||
union {
|
||||
const char *name;
|
||||
unsigned char fpr[24];
|
||||
unsigned char kid[8];
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
struct keydb_search_desc;
|
||||
typedef struct keydb_search_desc KEYDB_SEARCH_DESC;
|
||||
|
||||
typedef struct keydb_search_desc KEYBOX_SEARCH_DESC;
|
||||
|
||||
|
||||
|
||||
#endif /*KEYBOX_SEARCH_DESC_H*/
|
@ -1,810 +0,0 @@
|
||||
/* keybox-search.c - Search 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "../jnlib/stringhelp.h" /* ascii_xxxx() */
|
||||
#include "keybox-defs.h"
|
||||
|
||||
#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))
|
||||
|
||||
struct sn_array_s {
|
||||
int snlen;
|
||||
unsigned char *sn;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static ulong
|
||||
get32 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 24;
|
||||
a |= buffer[1] << 16;
|
||||
a |= buffer[2] << 8;
|
||||
a |= buffer[3];
|
||||
return a;
|
||||
}
|
||||
|
||||
static ulong
|
||||
get16 (const byte *buffer)
|
||||
{
|
||||
ulong a;
|
||||
a = *buffer << 8;
|
||||
a |= buffer[1];
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
blob_get_type (KEYBOXBLOB blob)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return -1; /* blob too short */
|
||||
|
||||
return buffer[4];
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
blob_get_blob_flags (KEYBOXBLOB blob)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 8)
|
||||
return 0; /* oops */
|
||||
|
||||
return get16 (buffer + 6);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
blob_cmp_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
size_t nserial;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20 + keyinfolen*nkeys;
|
||||
if (pos+2 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/*serial*/
|
||||
nserial = get16 (buffer+pos);
|
||||
off = pos + 2;
|
||||
if (off+nserial > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
return nserial == snlen && !memcmp (buffer+off, sn, snlen);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
blob_cmp_fpr (KEYBOXBLOB blob, const unsigned char *fpr)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
int idx;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20;
|
||||
if (pos + keyinfolen*nkeys > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
for (idx=0; idx < nkeys; idx++)
|
||||
{
|
||||
off = pos + idx*keyinfolen;
|
||||
if (!memcmp (buffer + off, fpr, 20))
|
||||
return 1; /* found */
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
static int
|
||||
blob_cmp_fpr_part (KEYBOXBLOB blob, const unsigned char *fpr,
|
||||
int fproff, int fprlen)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off;
|
||||
size_t nkeys, keyinfolen;
|
||||
int idx;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20;
|
||||
if (pos + keyinfolen*nkeys > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
for (idx=0; idx < nkeys; idx++)
|
||||
{
|
||||
off = pos + idx*keyinfolen;
|
||||
if (!memcmp (buffer + off + fproff, fpr, fprlen))
|
||||
return 1; /* found */
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
blob_cmp_name (KEYBOXBLOB blob, int idx,
|
||||
const char *name, size_t namelen, int substr)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off, len;
|
||||
size_t nkeys, keyinfolen;
|
||||
size_t nuids, uidinfolen;
|
||||
size_t nserial;
|
||||
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20 + keyinfolen*nkeys;
|
||||
if (pos+2 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/*serial*/
|
||||
nserial = get16 (buffer+pos);
|
||||
pos += 2 + nserial;
|
||||
if (pos+4 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/* user ids*/
|
||||
nuids = get16 (buffer + pos); pos += 2;
|
||||
uidinfolen = get16 (buffer + pos); pos += 2;
|
||||
if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
|
||||
return 0; /* invalid blob */
|
||||
if (pos + uidinfolen*nuids > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
if (idx < 0)
|
||||
{ /* compare all names starting with that (negated) index */
|
||||
idx = -idx;
|
||||
|
||||
for ( ;idx < nuids; idx++)
|
||||
{
|
||||
size_t mypos = pos;
|
||||
|
||||
mypos += idx*uidinfolen;
|
||||
off = get32 (buffer+mypos);
|
||||
len = get32 (buffer+mypos+4);
|
||||
if (off+len > length)
|
||||
return 0; /* error: better stop here out of bounds */
|
||||
if (len < 2)
|
||||
continue; /* empty name or 0 not stored */
|
||||
len--;
|
||||
if (substr)
|
||||
{
|
||||
if (ascii_memcasemem (buffer+off, len, name, namelen))
|
||||
return 1; /* found */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len == namelen && !memcmp (buffer+off, name, len))
|
||||
return 1; /* found */
|
||||
}
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (idx > nuids)
|
||||
return 0; /* no user ID with that idx */
|
||||
pos += idx*uidinfolen;
|
||||
off = get32 (buffer+pos);
|
||||
len = get32 (buffer+pos+4);
|
||||
if (off+len > length)
|
||||
return 0; /* out of bounds */
|
||||
if (len < 1)
|
||||
return 0; /* empty name */
|
||||
|
||||
if (substr)
|
||||
{
|
||||
return !!ascii_memcasemem (buffer+off, len, name, namelen);
|
||||
}
|
||||
else
|
||||
{
|
||||
return len == namelen && !memcmp (buffer+off, name, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* compare all email addresses of the subject. With SUBSTR given as
|
||||
True a substring search is done in the mail address */
|
||||
static int
|
||||
blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t pos, off, len;
|
||||
size_t nkeys, keyinfolen;
|
||||
size_t nuids, uidinfolen;
|
||||
size_t nserial;
|
||||
int idx;
|
||||
|
||||
/* fixme: this code is common to blob_cmp_mail */
|
||||
buffer = _keybox_get_blob_image (blob, &length);
|
||||
if (length < 40)
|
||||
return 0; /* blob too short */
|
||||
|
||||
/*keys*/
|
||||
nkeys = get16 (buffer + 16);
|
||||
keyinfolen = get16 (buffer + 18 );
|
||||
if (keyinfolen < 28)
|
||||
return 0; /* invalid blob */
|
||||
pos = 20 + keyinfolen*nkeys;
|
||||
if (pos+2 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/*serial*/
|
||||
nserial = get16 (buffer+pos);
|
||||
pos += 2 + nserial;
|
||||
if (pos+4 > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
/* user ids*/
|
||||
nuids = get16 (buffer + pos); pos += 2;
|
||||
uidinfolen = get16 (buffer + pos); pos += 2;
|
||||
if (uidinfolen < 12 /* should add a: || nuidinfolen > MAX_UIDINFOLEN */)
|
||||
return 0; /* invalid blob */
|
||||
if (pos + uidinfolen*nuids > length)
|
||||
return 0; /* out of bounds */
|
||||
|
||||
if (namelen < 1)
|
||||
return 0;
|
||||
|
||||
for (idx=1 ;idx < nuids; idx++)
|
||||
{
|
||||
size_t mypos = pos;
|
||||
|
||||
mypos += idx*uidinfolen;
|
||||
off = get32 (buffer+mypos);
|
||||
len = get32 (buffer+mypos+4);
|
||||
if (off+len > length)
|
||||
return 0; /* error: better stop here out of bounds */
|
||||
if (len < 2 || buffer[off] != '<')
|
||||
continue; /* empty name or trailing 0 not stored */
|
||||
len--; /* one back */
|
||||
if ( len < 3 || buffer[off+len] != '>')
|
||||
continue; /* not a proper email address */
|
||||
len--;
|
||||
if (substr)
|
||||
{
|
||||
if (ascii_memcasemem (buffer+off+1, len, name, namelen))
|
||||
return 1; /* found */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
|
||||
return 1; /* found */
|
||||
}
|
||||
}
|
||||
return 0; /* not found */
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
The has_foo functions are used as helpers for search
|
||||
*/
|
||||
static int
|
||||
has_short_kid (KEYBOXBLOB blob, const unsigned char *kid)
|
||||
{
|
||||
return blob_cmp_fpr_part (blob, kid+4, 16, 4);
|
||||
}
|
||||
|
||||
static int
|
||||
has_long_kid (KEYBOXBLOB blob, const unsigned char *kid)
|
||||
{
|
||||
return blob_cmp_fpr_part (blob, kid, 12, 8);
|
||||
}
|
||||
|
||||
static int
|
||||
has_fingerprint (KEYBOXBLOB blob, const unsigned char *fpr)
|
||||
{
|
||||
return blob_cmp_fpr (blob, fpr);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
has_issuer (KEYBOXBLOB blob, const char *name)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
return blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
has_issuer_sn (KEYBOXBLOB blob, const char *name,
|
||||
const unsigned char *sn, int snlen)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
return_val_if_fail (sn, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
|
||||
return (blob_cmp_sn (blob, sn, snlen)
|
||||
&& blob_cmp_name (blob, 0 /* issuer */, name, namelen, 0));
|
||||
}
|
||||
|
||||
static int
|
||||
has_sn (KEYBOXBLOB blob, const unsigned char *sn, int snlen)
|
||||
{
|
||||
return_val_if_fail (sn, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
return blob_cmp_sn (blob, sn, snlen);
|
||||
}
|
||||
|
||||
static int
|
||||
has_subject (KEYBOXBLOB blob, const char *name)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
return blob_cmp_name (blob, 1 /* subject */, name, namelen, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
has_subject_or_alt (KEYBOXBLOB blob, const char *name, int substr)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
return blob_cmp_name (blob, -1 /* all subject names*/, name,
|
||||
namelen, substr);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
has_mail (KEYBOXBLOB blob, const char *name, int substr)
|
||||
{
|
||||
size_t namelen;
|
||||
|
||||
return_val_if_fail (name, 0);
|
||||
|
||||
if (blob_get_type (blob) != BLOBTYPE_X509)
|
||||
return 0;
|
||||
|
||||
namelen = strlen (name);
|
||||
if (namelen && name[namelen-1] == '>')
|
||||
namelen--;
|
||||
return blob_cmp_mail (blob, name, namelen, substr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
release_sn_array (struct sn_array_s *array, size_t size)
|
||||
{
|
||||
size_t n;
|
||||
|
||||
for (n=0; n < size; n++)
|
||||
xfree (array[n].sn);
|
||||
xfree (array);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
The search API
|
||||
|
||||
*/
|
||||
|
||||
int
|
||||
keybox_search_reset (KEYBOX_HANDLE hd)
|
||||
{
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Value;
|
||||
|
||||
if (hd->found.blob)
|
||||
{
|
||||
_keybox_release_blob (hd->found.blob);
|
||||
hd->found.blob = NULL;
|
||||
}
|
||||
|
||||
if (hd->fp)
|
||||
{
|
||||
fclose (hd->fp);
|
||||
hd->fp = NULL;
|
||||
}
|
||||
hd->error = 0;
|
||||
hd->eof = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Note: When in ephemeral mode the search function does visit all
|
||||
blobs but in standard mode, blobs flagged as ephemeral are ignored. */
|
||||
int
|
||||
keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc)
|
||||
{
|
||||
int rc;
|
||||
size_t n;
|
||||
int need_words, any_skip;
|
||||
KEYBOXBLOB blob = NULL;
|
||||
struct sn_array_s *sn_array = NULL;
|
||||
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Value;
|
||||
|
||||
/* clear last found result */
|
||||
if (hd->found.blob)
|
||||
{
|
||||
_keybox_release_blob (hd->found.blob);
|
||||
hd->found.blob = NULL;
|
||||
}
|
||||
|
||||
if (hd->error)
|
||||
return hd->error; /* still in error state */
|
||||
if (hd->eof)
|
||||
return -1; /* still EOF */
|
||||
|
||||
/* figure out what information we need */
|
||||
need_words = any_skip = 0;
|
||||
for (n=0; n < ndesc; n++)
|
||||
{
|
||||
switch (desc[n].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_WORDS:
|
||||
need_words = 1;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FIRST:
|
||||
/* always restart the search in this mode */
|
||||
keybox_search_reset (hd);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (desc[n].skipfnc)
|
||||
any_skip = 1;
|
||||
if (desc[n].snlen == -1 && !sn_array)
|
||||
{
|
||||
sn_array = xtrycalloc (ndesc, sizeof *sn_array);
|
||||
if (!sn_array)
|
||||
return (hd->error = KEYBOX_Out_Of_Core);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hd->fp)
|
||||
{
|
||||
hd->fp = fopen (hd->kb->fname, "rb");
|
||||
if (!hd->fp)
|
||||
{
|
||||
xfree (sn_array);
|
||||
return (hd->error = KEYBOX_File_Open_Error);
|
||||
}
|
||||
}
|
||||
|
||||
/* kludge: we need to convert an SN given as hexstring to it's
|
||||
binary representation - in some cases we are not able to store it
|
||||
in the search descriptor, because due to its usgae it is not
|
||||
possible to free allocated memory */
|
||||
if (sn_array)
|
||||
{
|
||||
const unsigned char *s;
|
||||
int i, odd;
|
||||
size_t snlen;
|
||||
|
||||
for (n=0; n < ndesc; n++)
|
||||
{
|
||||
if (!desc[n].sn)
|
||||
;
|
||||
else if (desc[n].snlen == -1)
|
||||
{
|
||||
unsigned char *sn;
|
||||
|
||||
s = desc[n].sn;
|
||||
for (i=0; *s && *s != '/'; s++, i++)
|
||||
;
|
||||
odd = (i & 1);
|
||||
snlen = (i+1)/2;
|
||||
sn_array[n].sn = xtrymalloc (snlen);
|
||||
if (!sn_array[n].sn)
|
||||
{
|
||||
release_sn_array (sn_array, n);
|
||||
return (hd->error = KEYBOX_Out_Of_Core);
|
||||
}
|
||||
sn_array[n].snlen = snlen;
|
||||
sn = sn_array[n].sn;
|
||||
s = desc[n].sn;
|
||||
if (odd)
|
||||
{
|
||||
*sn++ = xtoi_1 (s);
|
||||
s++;
|
||||
}
|
||||
for (; *s && *s != '/'; s += 2)
|
||||
*sn++ = xtoi_2 (s);
|
||||
}
|
||||
else
|
||||
{
|
||||
const unsigned char *sn;
|
||||
|
||||
sn = desc[n].sn;
|
||||
snlen = desc[n].snlen;
|
||||
sn_array[n].sn = xtrymalloc (snlen);
|
||||
if (!sn_array[n].sn)
|
||||
{
|
||||
release_sn_array (sn_array, n);
|
||||
return (hd->error = KEYBOX_Out_Of_Core);
|
||||
}
|
||||
sn_array[n].snlen = snlen;
|
||||
memcpy (sn_array[n].sn, sn, snlen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (;;)
|
||||
{
|
||||
unsigned int blobflags;
|
||||
|
||||
_keybox_release_blob (blob); blob = NULL;
|
||||
rc = _keybox_read_blob (&blob, hd->fp);
|
||||
if (rc)
|
||||
break;
|
||||
|
||||
blobflags = blob_get_blob_flags (blob);
|
||||
if (!hd->ephemeral && (blobflags & 2))
|
||||
continue; /* not in ephemeral mode but blob is flagged ephemeral */
|
||||
|
||||
for (n=0; n < ndesc; n++)
|
||||
{
|
||||
switch (desc[n].mode)
|
||||
{
|
||||
case KEYDB_SEARCH_MODE_NONE:
|
||||
never_reached ();
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_EXACT:
|
||||
if (has_subject_or_alt (blob, desc[n].u.name, 0))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_MAIL:
|
||||
if (has_mail (blob, desc[n].u.name, 0))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_MAILSUB:
|
||||
if (has_mail (blob, desc[n].u.name, 1))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SUBSTR:
|
||||
if (has_subject_or_alt (blob, desc[n].u.name, 1))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_MAILEND:
|
||||
case KEYDB_SEARCH_MODE_WORDS:
|
||||
never_reached (); /* not yet implemented */
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_ISSUER:
|
||||
if (has_issuer (blob, desc[n].u.name))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_ISSUER_SN:
|
||||
if (has_issuer_sn (blob, desc[n].u.name,
|
||||
sn_array? sn_array[n].sn : desc[n].sn,
|
||||
sn_array? sn_array[n].snlen : desc[n].snlen))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SN:
|
||||
if (has_sn (blob, sn_array? sn_array[n].sn : desc[n].sn,
|
||||
sn_array? sn_array[n].snlen : desc[n].snlen))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SUBJECT:
|
||||
if (has_subject (blob, desc[n].u.name))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_SHORT_KID:
|
||||
if (has_short_kid (blob, desc[n].u.kid))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_LONG_KID:
|
||||
if (has_long_kid (blob, desc[n].u.kid))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FPR:
|
||||
case KEYDB_SEARCH_MODE_FPR20:
|
||||
if (has_fingerprint (blob, desc[n].u.fpr))
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_FIRST:
|
||||
goto found;
|
||||
break;
|
||||
case KEYDB_SEARCH_MODE_NEXT:
|
||||
goto found;
|
||||
break;
|
||||
default:
|
||||
rc = KEYBOX_Invalid_Value;
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
found:
|
||||
for (n=any_skip?0:ndesc; n < ndesc; n++)
|
||||
{
|
||||
/* if (desc[n].skipfnc */
|
||||
/* && desc[n].skipfnc (desc[n].skipfncvalue, aki)) */
|
||||
/* break; */
|
||||
}
|
||||
if (n == ndesc)
|
||||
break; /* got it */
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
hd->found.blob = blob;
|
||||
}
|
||||
else if (rc == -1)
|
||||
{
|
||||
_keybox_release_blob (blob);
|
||||
hd->eof = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_keybox_release_blob (blob);
|
||||
hd->error = rc;
|
||||
}
|
||||
|
||||
if (sn_array)
|
||||
release_sn_array (sn_array, ndesc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Functions to return a certificate or a keyblock. To be used after
|
||||
a successful search operation.
|
||||
*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
/*
|
||||
Return the last found cert. Caller must free it.
|
||||
*/
|
||||
int
|
||||
keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *r_cert)
|
||||
{
|
||||
const unsigned char *buffer;
|
||||
size_t length;
|
||||
size_t cert_off, cert_len;
|
||||
KsbaReader reader = NULL;
|
||||
KsbaCert cert = NULL;
|
||||
int rc;
|
||||
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Value;
|
||||
if (!hd->found.blob)
|
||||
return KEYBOX_Nothing_Found;
|
||||
|
||||
if (blob_get_type (hd->found.blob) != BLOBTYPE_X509)
|
||||
return KEYBOX_Wrong_Blob_Type;
|
||||
|
||||
buffer = _keybox_get_blob_image (hd->found.blob, &length);
|
||||
if (length < 40)
|
||||
return KEYBOX_Blob_Too_Short;
|
||||
cert_off = get32 (buffer+8);
|
||||
cert_len = get32 (buffer+12);
|
||||
if (cert_off+cert_len > length)
|
||||
return KEYBOX_Blob_Too_Short;
|
||||
|
||||
reader = ksba_reader_new ();
|
||||
if (!reader)
|
||||
return KEYBOX_Out_Of_Core;
|
||||
rc = ksba_reader_set_mem (reader, buffer+cert_off, cert_len);
|
||||
if (rc)
|
||||
{
|
||||
ksba_reader_release (reader);
|
||||
/* fixme: need to map the error codes */
|
||||
return KEYBOX_General_Error;
|
||||
}
|
||||
|
||||
cert = ksba_cert_new ();
|
||||
if (!cert)
|
||||
{
|
||||
ksba_reader_release (reader);
|
||||
return KEYBOX_Out_Of_Core;
|
||||
}
|
||||
|
||||
rc = ksba_cert_read_der (cert, reader);
|
||||
if (rc)
|
||||
{
|
||||
ksba_cert_release (cert);
|
||||
ksba_reader_release (reader);
|
||||
/* fixme: need to map the error codes */
|
||||
return KEYBOX_General_Error;
|
||||
}
|
||||
|
||||
*r_cert = cert;
|
||||
ksba_reader_release (reader);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /*KEYBOX_WITH_X509*/
|
@ -1,433 +0,0 @@
|
||||
/* keybox-update.c - keybox update operations
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
#define EXTSEP_S "."
|
||||
|
||||
|
||||
static int
|
||||
create_tmp_file (const char *template,
|
||||
char **r_bakfname, char **r_tmpfname, FILE **r_fp)
|
||||
{
|
||||
char *bakfname, *tmpfname;
|
||||
|
||||
*r_bakfname = NULL;
|
||||
*r_tmpfname = NULL;
|
||||
|
||||
# ifdef USE_ONLY_8DOT3
|
||||
/* Here is another Windoze bug?:
|
||||
* you cant rename("pubring.kbx.tmp", "pubring.kbx");
|
||||
* but rename("pubring.kbx.tmp", "pubring.aaa");
|
||||
* works. So we replace .kbx by .bak or .tmp
|
||||
*/
|
||||
if (strlen (template) > 4
|
||||
&& !strcmp (template+strlen(template)-4, EXTSEP_S "kbx") )
|
||||
{
|
||||
bakfname = xtrymalloc (strlen (template) + 1);
|
||||
if (!bakfname)
|
||||
return KEYBOX_Out_Of_Core;
|
||||
strcpy (bakfname, template);
|
||||
strcpy (bakfname+strlen(template)-4, EXTSEP_S "bak");
|
||||
|
||||
tmpfname = xtrymalloc (strlen (template) + 1);
|
||||
if (!tmpfname)
|
||||
{
|
||||
xfree (bakfname);
|
||||
return KEYBOX_Out_Of_Core;
|
||||
}
|
||||
strcpy (tmpfname,template);
|
||||
strcpy (tmpfname + strlen (template)-4, EXTSEP_S "tmp");
|
||||
}
|
||||
else
|
||||
{ /* file does not end with kbx; hmmm */
|
||||
bakfname = xtrymalloc ( strlen (template) + 5);
|
||||
if (!bakfname)
|
||||
return KEYBOX_Out_Of_Core;
|
||||
strcpy (stpcpy (bakfname, template), EXTSEP_S "bak");
|
||||
|
||||
tmpfname = xtrymalloc ( strlen (template) + 5);
|
||||
if (!tmpfname)
|
||||
{
|
||||
xfree (bakfname);
|
||||
return KEYBOX_Out_Of_Core;
|
||||
}
|
||||
strcpy (stpcpy (tmpfname, template), EXTSEP_S "tmp");
|
||||
}
|
||||
# else /* Posix file names */
|
||||
bakfname = xtrymalloc (strlen (template) + 2);
|
||||
if (!bakfname)
|
||||
return KEYBOX_Out_Of_Core;
|
||||
strcpy (stpcpy (bakfname,template),"~");
|
||||
|
||||
tmpfname = xtrymalloc ( strlen (template) + 5);
|
||||
if (!tmpfname)
|
||||
{
|
||||
xfree (bakfname);
|
||||
return KEYBOX_Out_Of_Core;
|
||||
}
|
||||
strcpy (stpcpy (tmpfname,template), EXTSEP_S "tmp");
|
||||
# endif /* Posix filename */
|
||||
|
||||
*r_fp = fopen (tmpfname, "wb");
|
||||
if (!*r_fp)
|
||||
{
|
||||
xfree (tmpfname);
|
||||
xfree (bakfname);
|
||||
return KEYBOX_File_Create_Error;
|
||||
}
|
||||
|
||||
*r_bakfname = bakfname;
|
||||
*r_tmpfname = tmpfname;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
rename_tmp_file (const char *bakfname, const char *tmpfname,
|
||||
const char *fname, int secret )
|
||||
{
|
||||
int rc=0;
|
||||
|
||||
/* restrict the permissions for secret keyboxs */
|
||||
#ifndef HAVE_DOSISH_SYSTEM
|
||||
/* if (secret && !opt.preserve_permissions) */
|
||||
/* { */
|
||||
/* if (chmod (tmpfname, S_IRUSR | S_IWUSR) ) */
|
||||
/* { */
|
||||
/* log_debug ("chmod of `%s' failed: %s\n", */
|
||||
/* tmpfname, strerror(errno) ); */
|
||||
/* return KEYBOX_Write_File; */
|
||||
/* } */
|
||||
/* } */
|
||||
#endif
|
||||
|
||||
/* fixme: invalidate close caches (not used with stdio)*/
|
||||
/* iobuf_ioctl (NULL, 2, 0, (char*)tmpfname ); */
|
||||
/* iobuf_ioctl (NULL, 2, 0, (char*)bakfname ); */
|
||||
/* iobuf_ioctl (NULL, 2, 0, (char*)fname ); */
|
||||
|
||||
/* first make a backup file except for secret keyboxs */
|
||||
if (!secret)
|
||||
{
|
||||
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
|
||||
remove (bakfname);
|
||||
#endif
|
||||
if (rename (fname, bakfname) )
|
||||
{
|
||||
return KEYBOX_File_Error;
|
||||
}
|
||||
}
|
||||
|
||||
/* then rename the file */
|
||||
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
|
||||
remove (fname);
|
||||
#endif
|
||||
if (rename (tmpfname, fname) )
|
||||
{
|
||||
rc = KEYBOX_File_Error;
|
||||
if (secret)
|
||||
{
|
||||
/* log_info ("WARNING: 2 files with confidential" */
|
||||
/* " information exists.\n"); */
|
||||
/* log_info ("%s is the unchanged one\n", fname ); */
|
||||
/* log_info ("%s is the new one\n", tmpfname ); */
|
||||
/* log_info ("Please fix this possible security flaw\n"); */
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Perform insert/delete/update operation.
|
||||
mode 1 = insert
|
||||
2 = delete
|
||||
3 = update
|
||||
*/
|
||||
static int
|
||||
blob_filecopy (int mode, const char *fname, KEYBOXBLOB blob,
|
||||
int secret, off_t start_offset, unsigned int n_packets )
|
||||
{
|
||||
FILE *fp, *newfp;
|
||||
int rc=0;
|
||||
char *bakfname = NULL;
|
||||
char *tmpfname = NULL;
|
||||
char buffer[4096];
|
||||
int nread, nbytes;
|
||||
|
||||
/* Open the source file. Because we do a rename, we have to check the
|
||||
permissions of the file */
|
||||
if (access (fname, W_OK))
|
||||
return KEYBOX_Write_Error;
|
||||
|
||||
fp = fopen (fname, "rb");
|
||||
if (mode == 1 && !fp && errno == ENOENT)
|
||||
{ /* insert mode but file does not exist: create a new keybox file */
|
||||
newfp = fopen (fname, "wb");
|
||||
if (!newfp )
|
||||
{
|
||||
return KEYBOX_File_Create_Error;
|
||||
}
|
||||
|
||||
rc = _keybox_write_blob (blob, newfp);
|
||||
if (rc)
|
||||
{
|
||||
return rc;
|
||||
}
|
||||
if ( fclose (newfp) )
|
||||
{
|
||||
return KEYBOX_File_Create_Error;
|
||||
}
|
||||
|
||||
/* if (chmod( fname, S_IRUSR | S_IWUSR )) */
|
||||
/* { */
|
||||
/* log_debug ("%s: chmod failed: %s\n", fname, strerror(errno) ); */
|
||||
/* return KEYBOX_File_Error; */
|
||||
/* } */
|
||||
return 0; /* ready */
|
||||
}
|
||||
|
||||
if (!fp)
|
||||
{
|
||||
rc = KEYBOX_File_Open_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* create the new file */
|
||||
rc = create_tmp_file (fname, &bakfname, &tmpfname, &newfp);
|
||||
if (rc)
|
||||
{
|
||||
fclose(fp);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* prepare for insert */
|
||||
if (mode == 1)
|
||||
{
|
||||
/* copy everything to the new file */
|
||||
while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
|
||||
{
|
||||
if (fwrite (buffer, nread, 1, newfp) != 1)
|
||||
{
|
||||
rc = KEYBOX_Write_Error;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if (ferror (fp))
|
||||
{
|
||||
rc = KEYBOX_Read_Error;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* prepare for delete or update */
|
||||
if ( mode == 2 || mode == 3 )
|
||||
{
|
||||
off_t current = 0;
|
||||
|
||||
/* copy first part to the new file */
|
||||
while ( current < start_offset )
|
||||
{
|
||||
nbytes = DIM(buffer);
|
||||
if (current + nbytes > start_offset)
|
||||
nbytes = start_offset - current;
|
||||
nread = fread (buffer, 1, nbytes, fp);
|
||||
if (!fread)
|
||||
break;
|
||||
current += nread;
|
||||
|
||||
if (fwrite (buffer, nread, 1, newfp) != 1)
|
||||
{
|
||||
rc = KEYBOX_Write_Error;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if (ferror (fp))
|
||||
{
|
||||
rc = KEYBOX_Read_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* skip this blob */
|
||||
rc = _keybox_read_blob (NULL, fp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Do an insert or update */
|
||||
if ( mode == 1 || mode == 3 )
|
||||
{
|
||||
rc = _keybox_write_blob (blob, newfp);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* copy the rest of the packet for an delete or update */
|
||||
if (mode == 2 || mode == 3)
|
||||
{
|
||||
while ( (nread = fread (buffer, 1, DIM(buffer), fp)) > 0 )
|
||||
{
|
||||
if (fwrite (buffer, nread, 1, newfp) != 1)
|
||||
{
|
||||
rc = KEYBOX_Write_Error;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
if (ferror (fp))
|
||||
{
|
||||
rc = KEYBOX_Read_Error;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* close both files */
|
||||
if (fclose(fp))
|
||||
{
|
||||
rc = KEYBOX_File_Close_Error;
|
||||
fclose (newfp);
|
||||
goto leave;
|
||||
}
|
||||
if (fclose(newfp))
|
||||
{
|
||||
rc = KEYBOX_File_Close_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = rename_tmp_file (bakfname, tmpfname, fname, secret);
|
||||
|
||||
leave:
|
||||
xfree(bakfname);
|
||||
xfree(tmpfname);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
int
|
||||
keybox_insert_cert (KEYBOX_HANDLE hd, KsbaCert cert,
|
||||
unsigned char *sha1_digest)
|
||||
{
|
||||
int rc;
|
||||
const char *fname;
|
||||
KEYBOXBLOB blob;
|
||||
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Handle;
|
||||
if (!hd->kb)
|
||||
return KEYBOX_Invalid_Handle;
|
||||
fname = hd->kb->fname;
|
||||
if (!fname)
|
||||
return KEYBOX_Invalid_Handle;
|
||||
|
||||
/* close this one otherwise we will mess up the position for a next
|
||||
search. Fixme: it would be better to adjust the position after
|
||||
the write opertions. */
|
||||
if (hd->fp)
|
||||
{
|
||||
fclose (hd->fp);
|
||||
hd->fp = NULL;
|
||||
}
|
||||
|
||||
rc = _keybox_create_x509_blob (&blob, cert, sha1_digest, hd->ephemeral);
|
||||
if (!rc)
|
||||
{
|
||||
rc = blob_filecopy (1, fname, blob, hd->secret, 0, 0 );
|
||||
_keybox_release_blob (blob);
|
||||
/* if (!rc && !hd->secret && kb_offtbl) */
|
||||
/* { */
|
||||
/* update_offset_hash_table_from_kb (kb_offtbl, kb, 0); */
|
||||
/* } */
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
keybox_update_cert (KEYBOX_HANDLE hd, KsbaCert cert,
|
||||
unsigned char *sha1_digest)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
||||
|
||||
int
|
||||
keybox_delete (KEYBOX_HANDLE hd)
|
||||
{
|
||||
off_t off;
|
||||
const char *fname;
|
||||
FILE *fp;
|
||||
int rc;
|
||||
|
||||
if (!hd)
|
||||
return KEYBOX_Invalid_Value;
|
||||
if (!hd->found.blob)
|
||||
return KEYBOX_Nothing_Found;
|
||||
if (!hd->kb)
|
||||
return KEYBOX_Invalid_Handle;
|
||||
fname = hd->kb->fname;
|
||||
if (!fname)
|
||||
return KEYBOX_Invalid_Handle;
|
||||
|
||||
off = _keybox_get_blob_fileoffset (hd->found.blob);
|
||||
if (off == (off_t)-1)
|
||||
return KEYBOX_General_Error;
|
||||
off += 4;
|
||||
|
||||
if (hd->fp)
|
||||
{
|
||||
fclose (hd->fp);
|
||||
hd->fp = NULL;
|
||||
}
|
||||
|
||||
fp = fopen (hd->kb->fname, "r+b");
|
||||
if (!fp)
|
||||
return KEYBOX_File_Open_Error;
|
||||
|
||||
if (fseeko (fp, off, SEEK_SET))
|
||||
rc = KEYBOX_Write_Error;
|
||||
else if (putc (0, fp) == EOF)
|
||||
rc = KEYBOX_Write_Error;
|
||||
else
|
||||
rc = 0;
|
||||
|
||||
if (fclose (fp))
|
||||
{
|
||||
if (!rc)
|
||||
rc = KEYBOX_File_Close_Error;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
@ -1,72 +0,0 @@
|
||||
/* keybox-util.c - Utility functions for Keybox
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "keybox-defs.h"
|
||||
|
||||
|
||||
static void *(*alloc_func)(size_t n) = malloc;
|
||||
static void *(*realloc_func)(void *p, size_t n) = realloc;
|
||||
static void (*free_func)(void*) = free;
|
||||
|
||||
|
||||
|
||||
void
|
||||
keybox_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
|
||||
void *(*new_realloc_func)(void *p, size_t n),
|
||||
void (*new_free_func)(void*) )
|
||||
{
|
||||
alloc_func = new_alloc_func;
|
||||
realloc_func = new_realloc_func;
|
||||
free_func = new_free_func;
|
||||
}
|
||||
|
||||
void *
|
||||
_keybox_malloc (size_t n)
|
||||
{
|
||||
return alloc_func (n);
|
||||
}
|
||||
|
||||
void *
|
||||
_keybox_realloc (void *a, size_t n)
|
||||
{
|
||||
return realloc_func (a, n);
|
||||
}
|
||||
|
||||
void *
|
||||
_keybox_calloc (size_t n, size_t m)
|
||||
{
|
||||
void *p = _keybox_malloc (n*m);
|
||||
if (p)
|
||||
memset (p, 0, n* m);
|
||||
return p;
|
||||
}
|
||||
|
||||
void
|
||||
_keybox_free (void *p)
|
||||
{
|
||||
if (p)
|
||||
free_func (p);
|
||||
}
|
||||
|
125
kbx/keybox.h
125
kbx/keybox.h
@ -1,125 +0,0 @@
|
||||
/* keybox.h - Keybox operations
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef KEYBOX_H
|
||||
#define KEYBOX_H 1
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#if 0
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "keybox-search-desc.h"
|
||||
|
||||
#define KEYBOX_WITH_OPENPGP 1
|
||||
#define KEYBOX_WITH_X509 1
|
||||
|
||||
|
||||
#ifdef KEYBOX_WITH_OPENPGP
|
||||
# undef KEYBOX_WITH_OPENPGP
|
||||
/*#include <lib-to-handle-gpg-data-structs.h>*/
|
||||
#endif
|
||||
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
# include <ksba.h>
|
||||
#endif
|
||||
|
||||
|
||||
typedef enum {
|
||||
KEYBOX_No_Error = 0,
|
||||
KEYBOX_General_Error = 1,
|
||||
KEYBOX_Out_Of_Core = 2,
|
||||
KEYBOX_Invalid_Value = 3,
|
||||
KEYBOX_Timeout = 4,
|
||||
KEYBOX_Read_Error = 5,
|
||||
KEYBOX_Write_Error = 6,
|
||||
KEYBOX_File_Error = 7,
|
||||
KEYBOX_Blob_Too_Short = 8,
|
||||
KEYBOX_Blob_Too_Large = 9,
|
||||
KEYBOX_Invalid_Handle = 10,
|
||||
KEYBOX_File_Create_Error = 11,
|
||||
KEYBOX_File_Open_Error = 12,
|
||||
KEYBOX_File_Close_Error = 13,
|
||||
KEYBOX_Nothing_Found = 14,
|
||||
KEYBOX_Wrong_Blob_Type = 15,
|
||||
KEYBOX_Missing_Value = 16,
|
||||
} KeyboxError;
|
||||
|
||||
|
||||
|
||||
typedef struct keybox_handle *KEYBOX_HANDLE;
|
||||
|
||||
|
||||
/*-- keybox-init.c --*/
|
||||
void *keybox_register_file (const char *fname, int secret);
|
||||
int keybox_is_writable (void *token);
|
||||
|
||||
KEYBOX_HANDLE keybox_new (void *token, int secret);
|
||||
void keybox_release (KEYBOX_HANDLE hd);
|
||||
const char *keybox_get_resource_name (KEYBOX_HANDLE hd);
|
||||
int keybox_set_ephemeral (KEYBOX_HANDLE hd, int yes);
|
||||
|
||||
|
||||
/*-- keybox-search.c --*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
int keybox_get_cert (KEYBOX_HANDLE hd, KsbaCert *ret_cert);
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
||||
int keybox_search_reset (KEYBOX_HANDLE hd);
|
||||
int keybox_search (KEYBOX_HANDLE hd, KEYBOX_SEARCH_DESC *desc, size_t ndesc);
|
||||
|
||||
|
||||
/*-- keybox-update.c --*/
|
||||
#ifdef KEYBOX_WITH_X509
|
||||
int keybox_insert_cert (KEYBOX_HANDLE hd, KsbaCert cert,
|
||||
unsigned char *sha1_digest);
|
||||
int keybox_update_cert (KEYBOX_HANDLE hd, KsbaCert cert,
|
||||
unsigned char *sha1_digest);
|
||||
#endif /*KEYBOX_WITH_X509*/
|
||||
|
||||
int keybox_delete (KEYBOX_HANDLE hd);
|
||||
|
||||
|
||||
/*-- --*/
|
||||
|
||||
#if 0
|
||||
int keybox_lock (KEYBOX_HANDLE hd, int yes);
|
||||
int keybox_get_keyblock (KEYBOX_HANDLE hd, KBNODE *ret_kb);
|
||||
int keybox_locate_writable (KEYBOX_HANDLE hd);
|
||||
int keybox_search_reset (KEYBOX_HANDLE hd);
|
||||
int keybox_search (KEYBOX_HANDLE hd, KEYDB_SEARCH_DESC *desc, size_t ndesc);
|
||||
int keybox_rebuild_cache (void *);
|
||||
#endif
|
||||
|
||||
|
||||
/*-- keybox-util.c --*/
|
||||
void keybox_set_malloc_hooks ( void *(*new_alloc_func)(size_t n),
|
||||
void *(*new_realloc_func)(void *p, size_t n),
|
||||
void (*new_free_func)(void*) );
|
||||
|
||||
/*-- keybox-errors.c (built) --*/
|
||||
const char *keybox_strerror (KeyboxError err);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /*KEYBOX_H*/
|
71
kbx/mkerrors
71
kbx/mkerrors
@ -1,71 +0,0 @@
|
||||
#!/bin/sh
|
||||
# mkerrors - Extract error strings from assuan.h
|
||||
# and create C source for assuan_strerror
|
||||
# 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
|
||||
|
||||
cat <<EOF
|
||||
/* Generated automatically by mkerrors */
|
||||
/* Do not edit! */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "keybox-defs.h"
|
||||
|
||||
/**
|
||||
* keybox_strerror:
|
||||
* @err: Error code
|
||||
*
|
||||
* This function returns a textual representaion of the given
|
||||
* errorcode. If this is an unknown value, a string with the value
|
||||
* is returned (Beware: it is hold in a static buffer).
|
||||
*
|
||||
* Return value: String with the error description.
|
||||
**/
|
||||
const char *
|
||||
keybox_strerror (KeyboxError err)
|
||||
{
|
||||
const char *s;
|
||||
static char buf[25];
|
||||
|
||||
switch (err)
|
||||
{
|
||||
EOF
|
||||
|
||||
awk '
|
||||
/KEYBOX_No_Error/ { okay=1 }
|
||||
!okay {next}
|
||||
/}/ { exit 0 }
|
||||
/KEYBOX_[A-Za-z_]*/ { print_code($1) }
|
||||
|
||||
|
||||
function print_code( s )
|
||||
{
|
||||
printf " case %s: s=\"", s ;
|
||||
gsub(/_/, " ", s );
|
||||
printf "%s\"; break;\n", tolower(substr(s,8));
|
||||
}
|
||||
'
|
||||
|
||||
cat <<EOF
|
||||
default: sprintf (buf, "ec=%d", err ); s=buf; break;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
EOF
|
@ -1,91 +0,0 @@
|
||||
2002-08-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* scdaemon.c (main): New option --daemon so that the program is
|
||||
not accidently started in the background.
|
||||
|
||||
2002-08-16 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* scdaemon.c: Include i18n.h.
|
||||
|
||||
* card-common.h (struct p15_private_s): Forward declaration. Add
|
||||
it to card_ctx_s.
|
||||
* card.c (card_close): Make sure private data is released.
|
||||
(card_enum_certs): New.
|
||||
* card-p15.c (p15_release_private_data): New.
|
||||
(init_private_data): New to work around an OpenSC weirdness.
|
||||
(p15_enum_keypairs): Do an OpenSC get_objects only once.
|
||||
(p15_enum_certs): New.
|
||||
(card_p15_bind): Bind new function.
|
||||
* command.c (cmd_learn): Return information about the certificates.
|
||||
|
||||
2002-08-09 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* card.c (card_get_serial_and_stamp): Use the tokeinfo serial
|
||||
number as a fallback. Add a special prefix for serial numbers.
|
||||
|
||||
2002-07-30 Werner Koch <wk@gnupg.org>
|
||||
|
||||
Changes to cope with OpenSC 0.7.0:
|
||||
|
||||
* card.c: Removed the check for the packed opensc version.
|
||||
Changed include file names of opensc.
|
||||
(map_sc_err): Adjusted error codes for new opensc version.
|
||||
* card-p15.c: Changed include filename of opensc.
|
||||
* card-dinsig.c: Ditto.
|
||||
|
||||
* card-p15.c (p15_decipher): Add flags argument to OpenSC call.
|
||||
|
||||
2002-07-24 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* card.c (find_simple_tlv, find_iccsn): New.
|
||||
(card_get_serial_and_stamp): Improved serial number parser.
|
||||
|
||||
2002-06-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* scdaemon.c (main): Use GNUPG_DEFAULT_HOMEDIR constant.
|
||||
|
||||
2002-06-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* card-dinsig.c: Documented some stuff from the DIN norm.
|
||||
|
||||
2002-04-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* command.c (cmd_pksign, cmd_pkdecrypt): Use a copy of the key ID.
|
||||
|
||||
2002-04-12 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* scdaemon.c: New option --debug-sc N.
|
||||
* card.c (card_open): set it here.
|
||||
|
||||
* card-p15.c (p15_prepare_key): Factored out common code from ...
|
||||
(p15_sign, p15_decipher): here and made the decryption work the
|
||||
regular way.
|
||||
|
||||
2002-04-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* card.c (card_open): Return immediately when no reader is available.
|
||||
|
||||
2002-03-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* card.c (card_open, card_close): Adjusted for changes in OpenSC.
|
||||
|
||||
2002-03-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* card-p15.c, card-dinsig.c, card-common.h: New.
|
||||
* card.c: Factored most code out to the new modules, so that we
|
||||
can better support different types of card applications.
|
||||
|
||||
2002-01-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* scdaemon.c scdaemon.h, command.c: New. Based on the code from
|
||||
the gpg-agent.
|
||||
|
||||
Copyright 2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is free software; as a special exception the author gives
|
||||
unlimited permission to copy and/or distribute it, with or without
|
||||
modifications, as long as this notice is preserved.
|
||||
|
||||
This file is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
|
||||
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
@ -1,42 +0,0 @@
|
||||
# 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
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\"
|
||||
|
||||
bin_PROGRAMS = scdaemon
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/common $(OPENSC_CFLAGS) $(LIBGCRYPT_CFLAGS) \
|
||||
$(KSBA_CFLAGS)
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
scdaemon_SOURCES = \
|
||||
scdaemon.c scdaemon.h \
|
||||
command.c card.c \
|
||||
card-common.h \
|
||||
card-p15.c card-dinsig.c
|
||||
|
||||
scdaemon_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a \
|
||||
../common/libcommon.a \
|
||||
$(OPENSC_LIBS) $(LIBGCRYPT_LIBS) $(KSBA_LIBS)
|
||||
|
||||
|
||||
|
||||
|
@ -1,73 +0,0 @@
|
||||
/* card-common.h - Common declarations for all card types
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef CARD_COMMON_H
|
||||
#define CARD_COMMON_H
|
||||
|
||||
/* Declaration of private data structure used by card-p15.c */
|
||||
struct p15private_s;
|
||||
|
||||
|
||||
struct card_ctx_s {
|
||||
int reader; /* used reader */
|
||||
struct sc_context *ctx;
|
||||
struct sc_card *scard;
|
||||
struct sc_pkcs15_card *p15card; /* only if there is a pkcs15 application */
|
||||
struct p15private_s *p15priv; /* private data used by card-p15.c */
|
||||
|
||||
struct {
|
||||
int initialized; /* the card has been initialied and the function
|
||||
pointers may be used. However for
|
||||
unsupported operations the particular
|
||||
function pointer is set to NULL */
|
||||
|
||||
int (*enum_keypairs) (CARD card, int idx,
|
||||
unsigned char *keygrip, char **keyid);
|
||||
int (*enum_certs) (CARD card, int idx, char **certid, int *certtype);
|
||||
int (*read_cert) (CARD card, const char *certidstr,
|
||||
unsigned char **cert, size_t *ncert);
|
||||
int (*sign) (CARD card,
|
||||
const char *keyidstr, int hashalgo,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
void **outdata, size_t *outdatalen );
|
||||
int (*decipher) (CARD card, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
void **outdata, size_t *outdatalen);
|
||||
} fnc;
|
||||
|
||||
};
|
||||
|
||||
/*-- card.c --*/
|
||||
int map_sc_err (int rc);
|
||||
int card_help_get_keygrip (KsbaCert cert, unsigned char *array);
|
||||
|
||||
/*-- card-15.c --*/
|
||||
void p15_release_private_data (CARD card);
|
||||
|
||||
/* constructors */
|
||||
void card_p15_bind (CARD card);
|
||||
void card_dinsig_bind (CARD card);
|
||||
|
||||
|
||||
#endif /*CARD_COMMON_H*/
|
@ -1,256 +0,0 @@
|
||||
/* card-dinsig.c - German signature law (DINSIG) functions
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/* The German signature law and its bylaw (SigG and SigV) is currently
|
||||
used with an interface specification described in DIN V 66291-1.
|
||||
The AID to be used is: 'D27600006601'.
|
||||
|
||||
The file IDs for certificates utilize the generic format:
|
||||
Cxyz
|
||||
C being the hex digit 'C' (12).
|
||||
x being the service indicator:
|
||||
'0' := SigG conform digital signature.
|
||||
'1' := entity authentication.
|
||||
'2' := key encipherment.
|
||||
'3' := data encipherment.
|
||||
'4' := key agreement.
|
||||
other values are reserved for future use.
|
||||
y being the security environment number using '0' for cards
|
||||
not supporting a SE number.
|
||||
z being the certificate type:
|
||||
'0' := C.CH (base certificate of ard holder) or C.ICC.
|
||||
'1' .. '7' := C.CH (business or professional certificate
|
||||
of card holder.
|
||||
'8' .. 'D' := C.CA (certificate of a CA issue by the Root-CA).
|
||||
'E' := C.RCA (self certified certificate of the Root-CA).
|
||||
'F' := reserved.
|
||||
|
||||
The file IDs used by default are:
|
||||
'1F00' EF.SSD (security service descriptor). [o,o]
|
||||
'2F02' EF.GDO (global data objects) [m,m]
|
||||
'A000' EF.PROT (signature log). Cyclic file with 20 records of 53 byte.
|
||||
Read and update after user authentication. [o,o]
|
||||
'B000' EF.PK.RCA.DS (public keys of Root-CA). Size is 512b or size
|
||||
of keys. [m (unless a 'C00E' is present),m]
|
||||
'B001' EF.PK.CA.DS (public keys of CAs). Size is 512b or size
|
||||
of keys. [o,o]
|
||||
'C00n' EF.C.CH.DS (digital signature certificate of card holder)
|
||||
with n := 0 .. 7. Size is 2k or size of cert. Read and
|
||||
update allowed after user authentication. [m,m]
|
||||
'C00m' EF.C.CA.DS (digital signature certificate of CA)
|
||||
with m := 8 .. E. Size is 1k or size of cert. Read always
|
||||
allowed, update after uder authentication. [o,o]
|
||||
'C100' EF.C.ICC.AUT (AUT certificate of ICC) [o,m]
|
||||
'C108' EF.C.CA.AUT (AUT certificate of CA) [o,m]
|
||||
'D000' EF.DM (display message) [-,m]
|
||||
|
||||
The letters in brackets indicate optional or mandatory files: The
|
||||
first for card terminals under full control and the second for
|
||||
"business" card terminals.
|
||||
|
||||
FIXME: Needs a lot more explanation.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <opensc/pkcs15.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "scdaemon.h"
|
||||
#include "card-common.h"
|
||||
|
||||
static int dinsig_read_cert (CARD card, const char *certidstr,
|
||||
unsigned char **cert, size_t *ncert);
|
||||
|
||||
|
||||
|
||||
/* See card.c for interface description. Frankly we don't do any real
|
||||
enumeration but just check whether the well know files are
|
||||
available. */
|
||||
static int
|
||||
dinsig_enum_keypairs (CARD card, int idx,
|
||||
unsigned char *keygrip, char **keyid)
|
||||
{
|
||||
int rc;
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
KsbaError krc;
|
||||
KsbaCert cert;
|
||||
|
||||
/* fixme: We should locate the application via the EF(DIR) and not
|
||||
assume a Netkey card */
|
||||
if (!idx)
|
||||
rc = dinsig_read_cert (card, "DINSIG-DF01.C000", &buf, &buflen);
|
||||
else if (idx == 1)
|
||||
rc = dinsig_read_cert (card, "DINSIG-DF01.C200", &buf, &buflen);
|
||||
else
|
||||
rc = -1;
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
cert = ksba_cert_new ();
|
||||
if (!cert)
|
||||
{
|
||||
xfree (buf);
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
|
||||
krc = ksba_cert_init_from_mem (cert, buf, buflen);
|
||||
xfree (buf);
|
||||
if (krc)
|
||||
{
|
||||
log_error ("failed to parse the certificate at idx %d: %s\n",
|
||||
idx, ksba_strerror (krc));
|
||||
ksba_cert_release (cert);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
if (card_help_get_keygrip (cert, keygrip))
|
||||
{
|
||||
log_error ("failed to calculate the keygrip at index %d\n", idx);
|
||||
ksba_cert_release (cert);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
ksba_cert_release (cert);
|
||||
|
||||
/* return the iD */
|
||||
if (keyid)
|
||||
{
|
||||
*keyid = xtrymalloc (17);
|
||||
if (!*keyid)
|
||||
return GNUPG_Out_Of_Core;
|
||||
if (!idx)
|
||||
strcpy (*keyid, "DINSIG-DF01.C000");
|
||||
else
|
||||
strcpy (*keyid, "DINSIG-DF01.C200");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* See card.c for interface description */
|
||||
static int
|
||||
dinsig_read_cert (CARD card, const char *certidstr,
|
||||
unsigned char **cert, size_t *ncert)
|
||||
{
|
||||
int rc;
|
||||
struct sc_path path;
|
||||
struct sc_file *file;
|
||||
unsigned char *buf;
|
||||
int buflen;
|
||||
|
||||
if (!strcmp (certidstr, "DINSIG-DF01.C000"))
|
||||
sc_format_path ("3F00DF01C000", &path);
|
||||
else if (!strcmp (certidstr, "DINSIG-DF01.C200"))
|
||||
sc_format_path ("3F00DF01C200", &path);
|
||||
else
|
||||
return GNUPG_Invalid_Id;
|
||||
|
||||
rc = sc_select_file (card->scard, &path, &file);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
|
||||
return map_sc_err (rc);
|
||||
}
|
||||
if (file->type != SC_FILE_TYPE_WORKING_EF
|
||||
|| file->ef_structure != SC_FILE_EF_TRANSPARENT)
|
||||
{
|
||||
log_error ("wrong type or structure of certificate EF\n");
|
||||
sc_file_free (file);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
if (file->size < 20) /* check against a somewhat arbitrary length */
|
||||
{
|
||||
log_error ("certificate EF too short\n");
|
||||
sc_file_free (file);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
buf = xtrymalloc (file->size);
|
||||
if (!buf)
|
||||
{
|
||||
sc_file_free (file);
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
|
||||
rc = sc_read_binary (card->scard, 0, buf, file->size, 0);
|
||||
if (rc >= 0 && rc != file->size)
|
||||
{
|
||||
log_error ("short read on certificate EF\n");
|
||||
sc_file_free (file);
|
||||
xfree (buf);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
sc_file_free (file);
|
||||
if (rc < 0)
|
||||
{
|
||||
log_error ("error reading certificate EF: %s\n", sc_strerror (rc));
|
||||
xfree (buf);
|
||||
return map_sc_err (rc);
|
||||
}
|
||||
buflen = rc;
|
||||
|
||||
/* The object is not a plain certificate but wrapped into id-at
|
||||
userCertificate - fixme: we should check the specs and decided
|
||||
whether libksba should support it */
|
||||
if (buflen > 9 && buf[0] == 0x30 && buf[4] == 6 && buf[5] == 3
|
||||
&& buf[6] == 0x55 && buf[7] == 4 && buf[8] == 0x24)
|
||||
{
|
||||
/* We have to strip the padding. Although this is a good idea
|
||||
anyway, we have to do it due to a KSBA problem; KSBA does not
|
||||
work correct when the buffer is larger than the ASN.1
|
||||
structure and the certificates here are padded with FF. So
|
||||
as a workaround we look at the outer structure to get the
|
||||
size of the entire thing and adjust the buflen. We can only
|
||||
do this when there is a 2 byte length field */
|
||||
size_t seqlen;
|
||||
if (buf[1] == 0x82)
|
||||
{
|
||||
seqlen = ((buf[2] << 8) | buf[3]) + 4;
|
||||
if (seqlen < buflen)
|
||||
buflen = seqlen;
|
||||
}
|
||||
memmove (buf, buf+9, buflen-9);
|
||||
buflen -= 9;
|
||||
}
|
||||
|
||||
*cert = buf;
|
||||
*ncert = buflen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Bind our operations to the card */
|
||||
void
|
||||
card_dinsig_bind (CARD card)
|
||||
{
|
||||
card->fnc.enum_keypairs = dinsig_enum_keypairs;
|
||||
card->fnc.read_cert = dinsig_read_cert;
|
||||
|
||||
}
|
498
scd/card-p15.c
498
scd/card-p15.c
@ -1,498 +0,0 @@
|
||||
/* card-p15.c - PKCS-15 based card access
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <opensc/pkcs15.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "scdaemon.h"
|
||||
#include "card-common.h"
|
||||
|
||||
|
||||
struct p15private_s {
|
||||
int n_prkey_rsa_objs;
|
||||
struct sc_pkcs15_object *prkey_rsa_objs[32];
|
||||
int n_cert_objs;
|
||||
struct sc_pkcs15_object *cert_objs[32];
|
||||
};
|
||||
|
||||
|
||||
/* Allocate private data. */
|
||||
static int
|
||||
init_private_data (CARD card)
|
||||
{
|
||||
struct p15private_s *priv;
|
||||
int rc;
|
||||
|
||||
if (card->p15priv)
|
||||
return 0; /* already done. */
|
||||
|
||||
priv = xtrycalloc (1, sizeof *priv);
|
||||
if (!priv)
|
||||
return GNUPG_Out_Of_Core;
|
||||
|
||||
/* OpenSC (0.7.0) is a bit strange in that the get_objects functions
|
||||
tries to be a bit too clever and implicitly does an enumeration
|
||||
which eventually leads to the fact that every call to this
|
||||
fucntion returns one more macthing object. The old code in
|
||||
p15_enum_keypairs assume that it would alwyas return the same
|
||||
numer of objects and used this to figure out what the last object
|
||||
enumerated is. We now do an enum_objects just once and keep it
|
||||
in the private data. */
|
||||
rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_PRKEY_RSA,
|
||||
priv->prkey_rsa_objs,
|
||||
DIM (priv->prkey_rsa_objs));
|
||||
if (rc < 0)
|
||||
{
|
||||
log_error ("private keys enumeration failed: %s\n", sc_strerror (rc));
|
||||
xfree (priv);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
priv->n_prkey_rsa_objs = rc;
|
||||
|
||||
/* Read all certificate objects. */
|
||||
rc = sc_pkcs15_get_objects (card->p15card, SC_PKCS15_TYPE_CERT_X509,
|
||||
priv->cert_objs,
|
||||
DIM (priv->cert_objs));
|
||||
if (rc < 0)
|
||||
{
|
||||
log_error ("private keys enumeration failed: %s\n", sc_strerror (rc));
|
||||
xfree (priv);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
priv->n_cert_objs = rc;
|
||||
|
||||
card->p15priv = priv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Release private data used in this module. */
|
||||
void
|
||||
p15_release_private_data (CARD card)
|
||||
{
|
||||
if (!card->p15priv)
|
||||
return;
|
||||
xfree (card->p15priv);
|
||||
card->p15priv = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* See card.c for interface description */
|
||||
static int
|
||||
p15_enum_keypairs (CARD card, int idx,
|
||||
unsigned char *keygrip, char **keyid)
|
||||
{
|
||||
int rc;
|
||||
KsbaError krc;
|
||||
struct p15private_s *priv;
|
||||
struct sc_pkcs15_object *tmpobj;
|
||||
int nobjs;
|
||||
struct sc_pkcs15_prkey_info *pinfo;
|
||||
struct sc_pkcs15_cert_info *certinfo;
|
||||
struct sc_pkcs15_cert *certder;
|
||||
KsbaCert cert;
|
||||
|
||||
rc = init_private_data (card);
|
||||
if (rc)
|
||||
return rc;
|
||||
priv = card->p15priv;
|
||||
nobjs = priv->n_prkey_rsa_objs;
|
||||
rc = 0;
|
||||
if (idx >= nobjs)
|
||||
return -1;
|
||||
pinfo = priv->prkey_rsa_objs[idx]->data;
|
||||
|
||||
/* now we need to read the certificate so that we can calculate the
|
||||
keygrip */
|
||||
rc = sc_pkcs15_find_cert_by_id (card->p15card, &pinfo->id, &tmpobj);
|
||||
if (rc)
|
||||
{
|
||||
log_info ("certificate for private key %d not found: %s\n",
|
||||
idx, sc_strerror (rc));
|
||||
/* note, that we return the ID anyway */
|
||||
rc = GNUPG_Missing_Certificate;
|
||||
goto return_keyid;
|
||||
}
|
||||
certinfo = tmpobj->data;
|
||||
rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
|
||||
if (rc)
|
||||
{
|
||||
log_info ("failed to read certificate for private key %d: %s\n",
|
||||
idx, sc_strerror (rc));
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
|
||||
cert = ksba_cert_new ();
|
||||
if (!cert)
|
||||
{
|
||||
sc_pkcs15_free_certificate (certder);
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
krc = ksba_cert_init_from_mem (cert, certder->data, certder->data_len);
|
||||
sc_pkcs15_free_certificate (certder);
|
||||
if (krc)
|
||||
{
|
||||
log_error ("failed to parse the certificate for private key %d: %s\n",
|
||||
idx, ksba_strerror (krc));
|
||||
ksba_cert_release (cert);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
if (card_help_get_keygrip (cert, keygrip))
|
||||
{
|
||||
log_error ("failed to calculate the keygrip of private key %d\n", idx);
|
||||
ksba_cert_release (cert);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
ksba_cert_release (cert);
|
||||
|
||||
rc = 0;
|
||||
return_keyid:
|
||||
if (keyid)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
*keyid = p = xtrymalloc (9+pinfo->id.len*2+1);
|
||||
if (!*keyid)
|
||||
return GNUPG_Out_Of_Core;
|
||||
p = stpcpy (p, "P15-5015.");
|
||||
for (i=0; i < pinfo->id.len; i++, p += 2)
|
||||
sprintf (p, "%02X", pinfo->id.value[i]);
|
||||
*p = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* See card.c for interface description */
|
||||
static int
|
||||
p15_enum_certs (CARD card, int idx, char **certid, int *type)
|
||||
{
|
||||
int rc;
|
||||
struct p15private_s *priv;
|
||||
struct sc_pkcs15_object *obj;
|
||||
struct sc_pkcs15_cert_info *cinfo;
|
||||
int nobjs;
|
||||
|
||||
rc = init_private_data (card);
|
||||
if (rc)
|
||||
return rc;
|
||||
priv = card->p15priv;
|
||||
nobjs = priv->n_cert_objs;
|
||||
rc = 0;
|
||||
if (idx >= nobjs)
|
||||
return -1;
|
||||
obj = priv->cert_objs[idx];
|
||||
cinfo = obj->data;
|
||||
|
||||
if (certid)
|
||||
{
|
||||
char *p;
|
||||
int i;
|
||||
|
||||
*certid = p = xtrymalloc (9+cinfo->id.len*2+1);
|
||||
if (!*certid)
|
||||
return GNUPG_Out_Of_Core;
|
||||
p = stpcpy (p, "P15-5015.");
|
||||
for (i=0; i < cinfo->id.len; i++, p += 2)
|
||||
sprintf (p, "%02X", cinfo->id.value[i]);
|
||||
*p = 0;
|
||||
}
|
||||
if (type)
|
||||
{
|
||||
if (!obj->df)
|
||||
*type = 0; /* unknown */
|
||||
else if (obj->df->type == SC_PKCS15_CDF)
|
||||
*type = 100;
|
||||
else if (obj->df->type == SC_PKCS15_CDF_TRUSTED)
|
||||
*type = 101;
|
||||
else if (obj->df->type == SC_PKCS15_CDF_USEFUL)
|
||||
*type = 102;
|
||||
else
|
||||
*type = 0; /* error -> unknown */
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
idstr_to_id (const char *idstr, struct sc_pkcs15_id *id)
|
||||
{
|
||||
const char *s;
|
||||
int n;
|
||||
|
||||
/* For now we only support the standard DF */
|
||||
if (strncmp (idstr, "P15-5015.", 9) )
|
||||
return GNUPG_Invalid_Id;
|
||||
for (s=idstr+9, n=0; hexdigitp (s); s++, n++)
|
||||
;
|
||||
if (*s || (n&1))
|
||||
return GNUPG_Invalid_Id; /* invalid or odd number of digits */
|
||||
n /= 2;
|
||||
if (!n || n > SC_PKCS15_MAX_ID_SIZE)
|
||||
return GNUPG_Invalid_Id; /* empty or too large */
|
||||
for (s=idstr+9, n=0; *s; s += 2, n++)
|
||||
id->value[n] = xtoi_2 (s);
|
||||
id->len = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* See card.c for interface description */
|
||||
static int
|
||||
p15_read_cert (CARD card, const char *certidstr,
|
||||
unsigned char **cert, size_t *ncert)
|
||||
{
|
||||
struct sc_pkcs15_object *tmpobj;
|
||||
struct sc_pkcs15_id certid;
|
||||
struct sc_pkcs15_cert_info *certinfo;
|
||||
struct sc_pkcs15_cert *certder;
|
||||
int rc;
|
||||
|
||||
if (!card || !certidstr || !cert || !ncert)
|
||||
return GNUPG_Invalid_Value;
|
||||
if (!card->p15card)
|
||||
return GNUPG_No_PKCS15_App;
|
||||
|
||||
rc = idstr_to_id (certidstr, &certid);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = sc_pkcs15_find_cert_by_id (card->p15card, &certid, &tmpobj);
|
||||
if (rc)
|
||||
{
|
||||
log_info ("certificate '%s' not found: %s\n",
|
||||
certidstr, sc_strerror (rc));
|
||||
return -1;
|
||||
}
|
||||
certinfo = tmpobj->data;
|
||||
rc = sc_pkcs15_read_certificate (card->p15card, certinfo, &certder);
|
||||
if (rc)
|
||||
{
|
||||
log_info ("failed to read certificate '%s': %s\n",
|
||||
certidstr, sc_strerror (rc));
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
|
||||
*cert = xtrymalloc (certder->data_len);
|
||||
if (!*cert)
|
||||
{
|
||||
sc_pkcs15_free_certificate (certder);
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
memcpy (*cert, certder->data, certder->data_len);
|
||||
*ncert = certder->data_len;
|
||||
sc_pkcs15_free_certificate (certder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
p15_prepare_key (CARD card, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg, struct sc_pkcs15_object **r_keyobj)
|
||||
{
|
||||
struct sc_pkcs15_id keyid;
|
||||
struct sc_pkcs15_pin_info *pin;
|
||||
struct sc_pkcs15_object *keyobj, *pinobj;
|
||||
char *pinvalue;
|
||||
int rc;
|
||||
|
||||
rc = idstr_to_id (keyidstr, &keyid);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = sc_pkcs15_find_prkey_by_id (card->p15card, &keyid, &keyobj);
|
||||
if (rc < 0)
|
||||
{
|
||||
log_error ("private key not found: %s\n", sc_strerror(rc));
|
||||
return GNUPG_No_Secret_Key;
|
||||
}
|
||||
|
||||
rc = sc_pkcs15_find_pin_by_auth_id (card->p15card,
|
||||
&keyobj->auth_id, &pinobj);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to find PIN by auth ID: %s\n", sc_strerror (rc));
|
||||
return GNUPG_Bad_PIN_Method;
|
||||
}
|
||||
pin = pinobj->data;
|
||||
|
||||
/* Fixme: pack this into a verification loop */
|
||||
/* Fixme: we might want to pass pin->min_length and
|
||||
pin->stored_length */
|
||||
rc = pincb (pincb_arg, pinobj->label, &pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_info ("PIN callback returned error: %s\n", gnupg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = sc_pkcs15_verify_pin (card->p15card, pin,
|
||||
pinvalue, strlen (pinvalue));
|
||||
xfree (pinvalue);
|
||||
if (rc)
|
||||
{
|
||||
log_info ("PIN verification failed: %s\n", sc_strerror (rc));
|
||||
return GNUPG_Bad_PIN;
|
||||
}
|
||||
|
||||
/* fixme: check wheter we need to release KEYOBJ in case of an error */
|
||||
*r_keyobj = keyobj;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* See card.c for interface description */
|
||||
static int
|
||||
p15_sign (CARD card, const char *keyidstr, int hashalgo,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
void **outdata, size_t *outdatalen )
|
||||
{
|
||||
unsigned int cryptflags;
|
||||
struct sc_pkcs15_object *keyobj;
|
||||
int rc;
|
||||
unsigned char *outbuf = NULL;
|
||||
size_t outbuflen;
|
||||
|
||||
if (hashalgo != GCRY_MD_SHA1)
|
||||
return GNUPG_Unsupported_Algorithm;
|
||||
|
||||
rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
cryptflags = SC_ALGORITHM_RSA_PAD_PKCS1;
|
||||
|
||||
outbuflen = 1024;
|
||||
outbuf = xtrymalloc (outbuflen);
|
||||
if (!outbuf)
|
||||
return GNUPG_Out_Of_Core;
|
||||
|
||||
rc = sc_pkcs15_compute_signature (card->p15card, keyobj,
|
||||
cryptflags,
|
||||
indata, indatalen,
|
||||
outbuf, outbuflen );
|
||||
if (rc < 0)
|
||||
{
|
||||
log_error ("failed to create signature: %s\n", sc_strerror (rc));
|
||||
rc = GNUPG_Card_Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
*outdatalen = rc;
|
||||
*outdata = outbuf;
|
||||
outbuf = NULL;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
xfree (outbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* See card.c for description */
|
||||
static int
|
||||
p15_decipher (CARD card, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
void **outdata, size_t *outdatalen )
|
||||
{
|
||||
struct sc_pkcs15_object *keyobj;
|
||||
int rc;
|
||||
unsigned char *outbuf = NULL;
|
||||
size_t outbuflen;
|
||||
|
||||
rc = p15_prepare_key (card, keyidstr, pincb, pincb_arg, &keyobj);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (card && card->scard && card->scard->driver
|
||||
&& !strcasecmp (card->scard->driver->short_name, "tcos"))
|
||||
{
|
||||
/* very ugly hack to force the use of a local key. We need this
|
||||
until we have fixed the initialization code for TCOS cards */
|
||||
struct sc_pkcs15_prkey_info *prkey = keyobj->data;
|
||||
if ( !(prkey->key_reference & 0x80))
|
||||
{
|
||||
prkey->key_reference |= 0x80;
|
||||
log_debug ("using TCOS hack to force the use of local keys\n");
|
||||
}
|
||||
if (*keyidstr && keyidstr[strlen(keyidstr)-1] == '6')
|
||||
{
|
||||
prkey->key_reference |= 1;
|
||||
log_debug ("warning: using even more TCOS hacks\n");
|
||||
}
|
||||
}
|
||||
|
||||
outbuflen = indatalen < 256? 256 : indatalen;
|
||||
outbuf = xtrymalloc (outbuflen);
|
||||
if (!outbuf)
|
||||
return GNUPG_Out_Of_Core;
|
||||
|
||||
rc = sc_pkcs15_decipher (card->p15card, keyobj,
|
||||
0,
|
||||
indata, indatalen,
|
||||
outbuf, outbuflen);
|
||||
if (rc < 0)
|
||||
{
|
||||
log_error ("failed to decipher the data: %s\n", sc_strerror (rc));
|
||||
rc = GNUPG_Card_Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
*outdatalen = rc;
|
||||
*outdata = outbuf;
|
||||
outbuf = NULL;
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
xfree (outbuf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Bind our operations to the card */
|
||||
void
|
||||
card_p15_bind (CARD card)
|
||||
{
|
||||
card->fnc.enum_keypairs = p15_enum_keypairs;
|
||||
card->fnc.enum_certs = p15_enum_certs;
|
||||
card->fnc.read_cert = p15_read_cert;
|
||||
card->fnc.sign = p15_sign;
|
||||
card->fnc.decipher = p15_decipher;
|
||||
}
|
540
scd/card.c
540
scd/card.c
@ -1,540 +0,0 @@
|
||||
/* card.c - SCdaemon card functions
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <opensc/pkcs15.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "scdaemon.h"
|
||||
#include "card-common.h"
|
||||
|
||||
/* Map the SC error codes to the GNUPG ones */
|
||||
int
|
||||
map_sc_err (int rc)
|
||||
{
|
||||
switch (rc)
|
||||
{
|
||||
case 0: rc = 0; break;
|
||||
case SC_ERROR_NOT_SUPPORTED: rc = GNUPG_Not_Supported; break;
|
||||
case SC_ERROR_PKCS15_APP_NOT_FOUND: rc = GNUPG_No_PKCS15_App; break;
|
||||
case SC_ERROR_OUT_OF_MEMORY: rc = GNUPG_Out_Of_Core; break;
|
||||
case SC_ERROR_CARD_NOT_PRESENT: rc = GNUPG_Card_Not_Present; break;
|
||||
case SC_ERROR_CARD_REMOVED: rc = GNUPG_Card_Removed; break;
|
||||
case SC_ERROR_INVALID_CARD: rc = GNUPG_Invalid_Card; break;
|
||||
default: rc = GNUPG_Card_Error; break;
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Get the keygrip from CERT, return 0 on success */
|
||||
int
|
||||
card_help_get_keygrip (KsbaCert cert, unsigned char *array)
|
||||
{
|
||||
GCRY_SEXP s_pkey;
|
||||
int rc;
|
||||
KsbaSexp p;
|
||||
size_t n;
|
||||
|
||||
p = ksba_cert_get_public_key (cert);
|
||||
if (!p)
|
||||
return -1; /* oops */
|
||||
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
|
||||
if (!n)
|
||||
return -1; /* libksba did not return a proper S-expression */
|
||||
rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
|
||||
xfree (p);
|
||||
if (rc)
|
||||
return -1; /* can't parse that S-expression */
|
||||
array = gcry_pk_get_keygrip (s_pkey, array);
|
||||
gcry_sexp_release (s_pkey);
|
||||
if (!array)
|
||||
return -1; /* failed to calculate the keygrip */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Create a new context for the card and figures out some basic
|
||||
information of the card. Detects whgether a PKCS_15 application is
|
||||
stored.
|
||||
|
||||
Common errors: GNUPG_Card_Not_Present */
|
||||
int
|
||||
card_open (CARD *rcard)
|
||||
{
|
||||
CARD card;
|
||||
int rc;
|
||||
|
||||
card = xtrycalloc (1, sizeof *card);
|
||||
if (!card)
|
||||
return GNUPG_Out_Of_Core;
|
||||
card->reader = 0;
|
||||
|
||||
rc = sc_establish_context (&card->ctx, "scdaemon");
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to establish SC context: %s\n", sc_strerror (rc));
|
||||
rc = map_sc_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
if (card->reader >= card->ctx->reader_count)
|
||||
{
|
||||
log_error ("no card reader available\n");
|
||||
rc = GNUPG_Card_Error;
|
||||
goto leave;
|
||||
}
|
||||
card->ctx->error_file = log_get_stream ();
|
||||
card->ctx->debug = opt.debug_sc;
|
||||
card->ctx->debug_file = log_get_stream ();
|
||||
|
||||
if (sc_detect_card_presence (card->ctx->reader[card->reader], 0) != 1)
|
||||
{
|
||||
rc = GNUPG_Card_Not_Present;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = sc_connect_card (card->ctx->reader[card->reader], 0, &card->scard);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to connect card in reader %d: %s\n",
|
||||
card->reader, sc_strerror (rc));
|
||||
rc = map_sc_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
if (opt.verbose)
|
||||
log_info ("connected to card in reader %d using driver `%s'\n",
|
||||
card->reader, card->scard->driver->name);
|
||||
|
||||
rc = sc_lock (card->scard);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't lock card in reader %d: %s\n",
|
||||
card->reader, sc_strerror (rc));
|
||||
rc = map_sc_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
leave:
|
||||
if (rc)
|
||||
card_close (card);
|
||||
else
|
||||
*rcard = card;
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Close a card and release all resources */
|
||||
void
|
||||
card_close (CARD card)
|
||||
{
|
||||
if (card)
|
||||
{
|
||||
if (card->p15card)
|
||||
{
|
||||
sc_pkcs15_unbind (card->p15card);
|
||||
card->p15card = NULL;
|
||||
}
|
||||
if (card->p15priv)
|
||||
p15_release_private_data (card);
|
||||
if (card->scard)
|
||||
{
|
||||
sc_unlock (card->scard);
|
||||
sc_disconnect_card (card->scard, 0);
|
||||
card->scard = NULL;
|
||||
}
|
||||
if (card->ctx)
|
||||
{
|
||||
sc_release_context (card->ctx);
|
||||
card->ctx = NULL;
|
||||
}
|
||||
xfree (card);
|
||||
}
|
||||
}
|
||||
|
||||
/* Locate a simple TLV encoded data object in BUFFER of LENGTH and
|
||||
return a pointer to value as well as its length in NBYTES. Return
|
||||
NULL if it was not found. Note, that the function does not check
|
||||
whether the value fits into the provided buffer. */
|
||||
static const char *
|
||||
find_simple_tlv (const unsigned char *buffer, size_t length,
|
||||
int tag, size_t *nbytes)
|
||||
{
|
||||
const char *s = buffer;
|
||||
size_t n = length;
|
||||
size_t len;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
buffer = s;
|
||||
if (n < 2)
|
||||
return NULL; /* buffer too short for tag and length. */
|
||||
len = s[1];
|
||||
s += 2; n -= 2;
|
||||
if (len == 255)
|
||||
{
|
||||
if (n < 2)
|
||||
return NULL; /* we expected 2 more bytes with the length. */
|
||||
len = (s[0] << 8) | s[1];
|
||||
s += 2; n -= 2;
|
||||
}
|
||||
if (*buffer == tag)
|
||||
{
|
||||
*nbytes = len;
|
||||
return s;
|
||||
}
|
||||
if (len > n)
|
||||
return NULL; /* buffer too short to skip to the next tag. */
|
||||
s += len; n -= len;
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the ICC Serial Number within the provided BUFFER of LENGTH
|
||||
(which should contain the GDO file) and return it as a hex encoded
|
||||
string and allocated string in SERIAL. Return an error code when
|
||||
the ICCSN was not found. */
|
||||
static int
|
||||
find_iccsn (const unsigned char *buffer, size_t length, char **serial)
|
||||
{
|
||||
size_t n;
|
||||
const unsigned char *s;
|
||||
char *p;
|
||||
|
||||
s = find_simple_tlv (buffer, length, 0x5A, &n);
|
||||
if (!s)
|
||||
return GNUPG_Card_Error;
|
||||
length -= s - buffer;
|
||||
if (n > length)
|
||||
{
|
||||
/* Oops, it does not fit into the buffer. This is an invalid
|
||||
encoding (or the buffer is too short. However, I have some
|
||||
test cards with such an invalid encoding and therefore I use
|
||||
this ugly workaround to return something I can further
|
||||
experiment with. */
|
||||
if (n == 0x0D && length+1 == n)
|
||||
{
|
||||
log_debug ("enabling BMI testcard workaround\n");
|
||||
n--;
|
||||
}
|
||||
else
|
||||
return GNUPG_Card_Error; /* Bad encoding; does not fit into buffer. */
|
||||
}
|
||||
if (!n)
|
||||
return GNUPG_Card_Error; /* Well, that is too short. */
|
||||
|
||||
*serial = p = xtrymalloc (2*n+1);
|
||||
if (!*serial)
|
||||
return GNUPG_Out_Of_Core;
|
||||
for (; n; n--, p += 2, s++)
|
||||
sprintf (p, "%02X", *s);
|
||||
*p = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Retrieve the serial number and the time of the last update of the
|
||||
card. The serial number is returned as a malloced string (hex
|
||||
encoded) in SERIAL and the time of update is returned in STAMP.
|
||||
If no update time is available the returned value is 0. The serial
|
||||
is mandatory for a PKCS_15 application and an error will be
|
||||
returned if this value is not availbale. For non-PKCS-15 cards a
|
||||
serial number is constructed by other means. Caller must free
|
||||
SERIAL unless the function returns an error. */
|
||||
int
|
||||
card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp)
|
||||
{
|
||||
int rc;
|
||||
struct sc_path path;
|
||||
struct sc_file *file;
|
||||
unsigned char buf[256];
|
||||
int buflen;
|
||||
|
||||
if (!card || !serial || !stamp)
|
||||
return GNUPG_Invalid_Value;
|
||||
|
||||
*serial = NULL;
|
||||
*stamp = 0; /* not available */
|
||||
|
||||
if (!card->fnc.initialized)
|
||||
{
|
||||
card->fnc.initialized = 1;
|
||||
/* The first use of this card tries to figure out the type of the card
|
||||
and sets up the function pointers. */
|
||||
rc = sc_pkcs15_bind (card->scard, &card->p15card);
|
||||
if (rc)
|
||||
{
|
||||
if (rc != SC_ERROR_PKCS15_APP_NOT_FOUND)
|
||||
log_error ("binding of existing PKCS-15 failed in reader %d: %s\n",
|
||||
card->reader, sc_strerror (rc));
|
||||
card->p15card = NULL;
|
||||
rc = 0;
|
||||
}
|
||||
if (card->p15card)
|
||||
card_p15_bind (card);
|
||||
else
|
||||
card_dinsig_bind (card);
|
||||
card->fnc.initialized = 1;
|
||||
}
|
||||
|
||||
|
||||
/* We should lookup the iso 7812-1 and 8583-3 - argh ISO
|
||||
practice is suppressing innovation - IETF rules! So we
|
||||
always get the serialnumber from the 2F02 GDO file. */
|
||||
/* FIXME: in case we can't parse the 2F02 EF and we have a P15 card,
|
||||
we should get the serial number from the respective P15 file */
|
||||
sc_format_path ("3F002F02", &path);
|
||||
rc = sc_select_file (card->scard, &path, &file);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("sc_select_file failed: %s\n", sc_strerror (rc));
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
if (file->type != SC_FILE_TYPE_WORKING_EF
|
||||
|| file->ef_structure != SC_FILE_EF_TRANSPARENT)
|
||||
{
|
||||
log_error ("wrong type or structure of GDO file\n");
|
||||
sc_file_free (file);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
|
||||
if (!file->size || file->size >= DIM(buf) )
|
||||
{ /* FIXME: Use a real parser */
|
||||
log_error ("unsupported size of GDO file (%d)\n", file->size);
|
||||
sc_file_free (file);
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
buflen = file->size;
|
||||
|
||||
rc = sc_read_binary (card->scard, 0, buf, buflen, 0);
|
||||
sc_file_free (file);
|
||||
if (rc < 0)
|
||||
{
|
||||
log_error ("error reading GDO file: %s\n", sc_strerror (rc));
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
if (rc != buflen)
|
||||
{
|
||||
log_error ("short read on GDO file\n");
|
||||
return GNUPG_Card_Error;
|
||||
}
|
||||
|
||||
rc = find_iccsn (buf, buflen, serial);
|
||||
if (rc == GNUPG_Card_Error)
|
||||
log_error ("invalid structure of GDO file\n");
|
||||
if (!rc && card->p15card && !strcmp (*serial, "D27600000000000000000000"))
|
||||
{ /* This is a German card with a silly serial number. Try to get
|
||||
the serial number from the EF(TokenInfo). We indicate such a
|
||||
serial number by the using the prefix: "FF0100". */
|
||||
const char *efser = card->p15card->serial_number;
|
||||
char *p;
|
||||
|
||||
if (!efser)
|
||||
efser = "";
|
||||
|
||||
xfree (*serial);
|
||||
*serial = NULL;
|
||||
p = xtrymalloc (strlen (efser) + 7);
|
||||
if (!p)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
strcpy (p, "FF0100");
|
||||
strcpy (p+6, efser);
|
||||
*serial = p;
|
||||
}
|
||||
}
|
||||
else if (!rc && **serial == 'F' && (*serial)[1] == 'F')
|
||||
{ /* The serial number starts with our special prefix. This
|
||||
requires that we put our default prefix "FF0000" in front. */
|
||||
char *p = xtrymalloc (strlen (*serial) + 7);
|
||||
if (!p)
|
||||
{
|
||||
xfree (*serial);
|
||||
*serial = NULL;
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy (p, "FF0000");
|
||||
strcpy (p+6, *serial);
|
||||
xfree (*serial);
|
||||
*serial = p;
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Enumerate all keypairs on the card and return the Keygrip as well
|
||||
as the internal identification of the key. KEYGRIP must be a
|
||||
caller provided buffer with a size of 20 bytes which will receive
|
||||
the KEYGRIP of the keypair. If KEYID is not NULL, it returns the
|
||||
ID field of the key in allocated memory; this is a string without
|
||||
spaces. The function returns -1 when all keys have been
|
||||
enumerated. Note that the error GNUPG_Missing_Certificate may be
|
||||
returned if there is just the private key but no public key (ie.e a
|
||||
certificate) available. Applications might want to continue
|
||||
enumerating after this error.*/
|
||||
int
|
||||
card_enum_keypairs (CARD card, int idx,
|
||||
unsigned char *keygrip,
|
||||
char **keyid)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (keyid)
|
||||
*keyid = NULL;
|
||||
|
||||
if (!card || !keygrip)
|
||||
return GNUPG_Invalid_Value;
|
||||
if (idx < 0)
|
||||
return GNUPG_Invalid_Index;
|
||||
if (!card->fnc.initialized)
|
||||
return GNUPG_Card_Not_Initialized;
|
||||
if (!card->fnc.enum_keypairs)
|
||||
return GNUPG_Unsupported_Operation;
|
||||
rc = card->fnc.enum_keypairs (card, idx, keygrip, keyid);
|
||||
if (opt.verbose)
|
||||
log_info ("card operation enum_keypairs result: %s\n",
|
||||
gnupg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Enumerate all trusted certificates available on the card, return
|
||||
their ID in CERT and the type in CERTTYPE. Types of certificates
|
||||
are:
|
||||
0 := Unknown
|
||||
100 := Regular X.509 cert
|
||||
101 := Trusted X.509 cert
|
||||
102 := Useful X.509 cert
|
||||
*/
|
||||
int
|
||||
card_enum_certs (CARD card, int idx, char **certid, int *certtype)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (certid)
|
||||
*certid = NULL;
|
||||
|
||||
if (!card)
|
||||
return GNUPG_Invalid_Value;
|
||||
if (idx < 0)
|
||||
return GNUPG_Invalid_Index;
|
||||
if (!card->fnc.initialized)
|
||||
return GNUPG_Card_Not_Initialized;
|
||||
if (!card->fnc.enum_certs)
|
||||
return GNUPG_Unsupported_Operation;
|
||||
rc = card->fnc.enum_certs (card, idx, certid, certtype);
|
||||
if (opt.verbose)
|
||||
log_info ("card operation enum_certs result: %s\n",
|
||||
gnupg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read the certificate identified by CERTIDSTR which is the
|
||||
hexadecimal encoded ID of the certificate, prefixed with the string
|
||||
"3F005015.". The certificate is return in DER encoded form in CERT
|
||||
and NCERT. */
|
||||
int
|
||||
card_read_cert (CARD card, const char *certidstr,
|
||||
unsigned char **cert, size_t *ncert)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!card || !certidstr || !cert || !ncert)
|
||||
return GNUPG_Invalid_Value;
|
||||
if (!card->fnc.initialized)
|
||||
return GNUPG_Card_Not_Initialized;
|
||||
if (!card->fnc.read_cert)
|
||||
return GNUPG_Unsupported_Operation;
|
||||
rc = card->fnc.read_cert (card, certidstr, cert, ncert);
|
||||
if (opt.verbose)
|
||||
log_info ("card operation read_cert result: %s\n", gnupg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Create the signature and return the allocated result in OUTDATA.
|
||||
If a PIN is required the PINCB will be used to ask for the PIN; it
|
||||
should return the PIN in an allocated buffer and put it into PIN. */
|
||||
int
|
||||
card_sign (CARD card, const char *keyidstr, int hashalgo,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
void **outdata, size_t *outdatalen )
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
|
||||
return GNUPG_Invalid_Value;
|
||||
if (!card->fnc.initialized)
|
||||
return GNUPG_Card_Not_Initialized;
|
||||
if (!card->fnc.sign)
|
||||
return GNUPG_Unsupported_Operation;
|
||||
rc = card->fnc.sign (card, keyidstr, hashalgo,
|
||||
pincb, pincb_arg,
|
||||
indata, indatalen,
|
||||
outdata, outdatalen);
|
||||
if (opt.verbose)
|
||||
log_info ("card operation sign result: %s\n", gnupg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Create the signature and return the allocated result in OUTDATA.
|
||||
If a PIN is required the PINCB will be used to ask for the PIN; it
|
||||
should return the PIN in an allocated buffer and put it into PIN. */
|
||||
int
|
||||
card_decipher (CARD card, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
void **outdata, size_t *outdatalen )
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!card || !indata || !indatalen || !outdata || !outdatalen || !pincb)
|
||||
return GNUPG_Invalid_Value;
|
||||
if (!card->fnc.initialized)
|
||||
return GNUPG_Card_Not_Initialized;
|
||||
if (!card->fnc.decipher)
|
||||
return GNUPG_Unsupported_Operation;
|
||||
rc = card->fnc.decipher (card, keyidstr,
|
||||
pincb, pincb_arg,
|
||||
indata, indatalen,
|
||||
outdata, outdatalen);
|
||||
if (opt.verbose)
|
||||
log_info ("card operation decipher result: %s\n", gnupg_strerror (rc));
|
||||
return rc;
|
||||
}
|
651
scd/command.c
651
scd/command.c
@ -1,651 +0,0 @@
|
||||
/* command.c - SCdaemon command handler
|
||||
* 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 <unistd.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "scdaemon.h"
|
||||
#include "../assuan/assuan.h"
|
||||
|
||||
/* maximum length aloowed as a PIN; used for INQUIRE NEEDPIN */
|
||||
#define MAXLEN_PIN 100
|
||||
|
||||
#define set_error(e,t) assuan_set_error (ctx, ASSUAN_ ## e, (t))
|
||||
|
||||
/* Data used to associate an Assuan context with local server data */
|
||||
struct server_local_s {
|
||||
ASSUAN_CONTEXT assuan_ctx;
|
||||
};
|
||||
|
||||
|
||||
/* 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)));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Note, that this reset_notify is also used for cleanup purposes. */
|
||||
static void
|
||||
reset_notify (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
|
||||
if (ctrl->card_ctx)
|
||||
{
|
||||
card_close (ctrl->card_ctx);
|
||||
ctrl->card_ctx = NULL;
|
||||
xfree (ctrl->in_data.value);
|
||||
ctrl->in_data.value = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
option_handler (ASSUAN_CONTEXT ctx, const char *key, const char *value)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* If the card has not yet been opened, do it. Note that this
|
||||
function returns an Assuan error, so don't map the error a second
|
||||
time */
|
||||
static AssuanError
|
||||
open_card (CTRL ctrl)
|
||||
{
|
||||
if (!ctrl->card_ctx)
|
||||
{
|
||||
int rc = card_open (&ctrl->card_ctx);
|
||||
if (rc)
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* SERIALNO
|
||||
|
||||
Return the serial number of the card using a status reponse. This
|
||||
functon should be used to check for the presence of a card.
|
||||
|
||||
This function is special in that it can be used to reset the card.
|
||||
Most other functions will return an error when a card change has
|
||||
been detected and the use of this function is therefore required.
|
||||
|
||||
Background: We want to keep the client clear of handling card
|
||||
changes between operations; i.e. the client can assume that all
|
||||
operations are doneon the same card unless he call this function.
|
||||
*/
|
||||
static int
|
||||
cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc = 0;
|
||||
char *serial_and_stamp;
|
||||
char *serial;
|
||||
time_t stamp;
|
||||
|
||||
if ((rc = open_card (ctrl)))
|
||||
return rc;
|
||||
|
||||
rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
|
||||
if (rc)
|
||||
return map_to_assuan_status (rc);
|
||||
rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
|
||||
xfree (serial);
|
||||
if (rc < 0)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
rc = 0;
|
||||
assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
|
||||
free (serial_and_stamp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* LEARN [--force]
|
||||
|
||||
Learn all useful information of the currently inserted card. When
|
||||
used without the force options, the command might do an INQUIRE
|
||||
like this:
|
||||
|
||||
INQUIRE KNOWNCARDP <hexstring_with_serialNumber> <timestamp>
|
||||
|
||||
The client should just send an "END" if the processing should go on
|
||||
or a "CANCEL" to force the function to terminate with a Cancel
|
||||
error message. The response of this command is a list of status
|
||||
lines formatted as this:
|
||||
|
||||
S KEYPAIRINFO <hexstring_with_keygrip> <hexstring_with_id>
|
||||
|
||||
If there is no certificate yet stored on the card a single "X" is
|
||||
returned as the keygrip. In addition to the keypair info, information
|
||||
about all certificates stored on the card is also returned:
|
||||
|
||||
S CERTINFO <certtype> <hexstring_with_id>
|
||||
|
||||
Where CERTINFO is a number indicating the type of certificate:
|
||||
0 := Unknown
|
||||
100 := Regular X.509 cert
|
||||
101 := Trusted X.509 cert
|
||||
102 := Useful X.509 cert
|
||||
|
||||
|
||||
*/
|
||||
static int
|
||||
cmd_learn (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc = 0;
|
||||
int idx;
|
||||
|
||||
if ((rc = open_card (ctrl)))
|
||||
return rc;
|
||||
|
||||
/* Unless the force option is used we try a shortcut by identifying
|
||||
the card using a serial number and inquiring the client with
|
||||
that. The client may choose to cancel the operation if he already
|
||||
knows about this card */
|
||||
{
|
||||
char *serial_and_stamp;
|
||||
char *serial;
|
||||
time_t stamp;
|
||||
|
||||
rc = card_get_serial_and_stamp (ctrl->card_ctx, &serial, &stamp);
|
||||
if (rc)
|
||||
return map_to_assuan_status (rc);
|
||||
rc = asprintf (&serial_and_stamp, "%s %lu", serial, (unsigned long)stamp);
|
||||
xfree (serial);
|
||||
if (rc < 0)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
rc = 0;
|
||||
assuan_write_status (ctx, "SERIALNO", serial_and_stamp);
|
||||
|
||||
if (!has_option (line, "--force"))
|
||||
{
|
||||
char *command;
|
||||
|
||||
rc = asprintf (&command, "KNOWNCARDP %s", serial_and_stamp);
|
||||
if (rc < 0)
|
||||
{
|
||||
free (serial_and_stamp);
|
||||
return ASSUAN_Out_Of_Core;
|
||||
}
|
||||
rc = 0;
|
||||
rc = assuan_inquire (ctx, command, NULL, NULL, 0);
|
||||
free (command); /* (must use standard free here) */
|
||||
if (rc)
|
||||
{
|
||||
if (rc != ASSUAN_Canceled)
|
||||
log_error ("inquire KNOWNCARDP failed: %s\n",
|
||||
assuan_strerror (rc));
|
||||
free (serial_and_stamp);
|
||||
return rc;
|
||||
}
|
||||
/* not canceled, so we have to proceeed */
|
||||
}
|
||||
free (serial_and_stamp);
|
||||
}
|
||||
|
||||
/* Return information about the certificates. */
|
||||
for (idx=0; !rc; idx++)
|
||||
{
|
||||
char *certid;
|
||||
int certtype;
|
||||
|
||||
rc = card_enum_certs (ctrl->card_ctx, idx, &certid, &certtype);
|
||||
if (!rc)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = xtrymalloc (40 + 1 + strlen (certid) + 1);
|
||||
if (!buf)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
sprintf (buf, "%d %s", certtype, certid);
|
||||
assuan_write_status (ctx, "CERTINFO", buf);
|
||||
xfree (buf);
|
||||
}
|
||||
}
|
||||
xfree (certid);
|
||||
}
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
|
||||
|
||||
/* Return information about the keys. */
|
||||
for (idx=0; !rc; idx++)
|
||||
{
|
||||
unsigned char keygrip[20];
|
||||
char *keyid;
|
||||
int no_cert = 0;
|
||||
|
||||
rc = card_enum_keypairs (ctrl->card_ctx, idx, keygrip, &keyid);
|
||||
if (rc == GNUPG_Missing_Certificate && keyid)
|
||||
{
|
||||
/* this does happen with an incomplete personalized
|
||||
card; i.e. during the time we have stored the key on the
|
||||
card but not stored the certificate; probably becuase it
|
||||
has not yet been received back from the CA. Note that we
|
||||
must release KEYID in this case. */
|
||||
rc = 0;
|
||||
no_cert = 1;
|
||||
}
|
||||
if (!rc)
|
||||
{
|
||||
char *buf, *p;
|
||||
|
||||
buf = p = xtrymalloc (40 + 1 + strlen (keyid) + 1);
|
||||
if (!buf)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
int i;
|
||||
|
||||
if (no_cert)
|
||||
*p++ = 'X';
|
||||
else
|
||||
{
|
||||
for (i=0; i < 20; i++, p += 2)
|
||||
sprintf (p, "%02X", keygrip[i]);
|
||||
}
|
||||
*p++ = ' ';
|
||||
strcpy (p, keyid);
|
||||
assuan_write_status (ctx, "KEYPAIRINFO", buf);
|
||||
xfree (buf);
|
||||
}
|
||||
}
|
||||
xfree (keyid);
|
||||
}
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
|
||||
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* READCERT <hexified_certid>
|
||||
|
||||
*/
|
||||
static int
|
||||
cmd_readcert (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
unsigned char *cert;
|
||||
size_t ncert;
|
||||
|
||||
if ((rc = open_card (ctrl)))
|
||||
return rc;
|
||||
|
||||
rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc));
|
||||
}
|
||||
if (!rc)
|
||||
{
|
||||
rc = assuan_send_data (ctx, cert, ncert);
|
||||
xfree (cert);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
|
||||
/* READKEY <hexified_certid>
|
||||
|
||||
Return the public key for the given cert or key ID as an standard
|
||||
S-Expression. */
|
||||
static int
|
||||
cmd_readkey (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
unsigned char *cert = NULL;
|
||||
size_t ncert, n;
|
||||
KsbaCert kc = NULL;
|
||||
KsbaSexp p;
|
||||
|
||||
if ((rc = open_card (ctrl)))
|
||||
return rc;
|
||||
|
||||
rc = card_read_cert (ctrl->card_ctx, line, &cert, &ncert);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("card_read_cert failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
kc = ksba_cert_new ();
|
||||
if (!kc)
|
||||
{
|
||||
xfree (cert);
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
goto leave;
|
||||
}
|
||||
rc = ksba_cert_init_from_mem (kc, cert, ncert);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to parse the certificate: %s\n", ksba_strerror (rc));
|
||||
rc = map_ksba_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
p = ksba_cert_get_public_key (kc);
|
||||
if (!p)
|
||||
{
|
||||
rc = GNUPG_No_Public_Key;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
|
||||
rc = assuan_send_data (ctx, p, n);
|
||||
rc = map_assuan_err (rc);
|
||||
xfree (p);
|
||||
|
||||
|
||||
leave:
|
||||
ksba_cert_release (kc);
|
||||
xfree (cert);
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* SETDATA <hexstring>
|
||||
|
||||
The client should use this command to tell us the data he want to
|
||||
sign. */
|
||||
static int
|
||||
cmd_setdata (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int n;
|
||||
char *p;
|
||||
unsigned char *buf;
|
||||
|
||||
/* parse the hexstring */
|
||||
for (p=line,n=0; hexdigitp (p); p++, n++)
|
||||
;
|
||||
if (*p)
|
||||
return set_error (Parameter_Error, "invalid hexstring");
|
||||
if ((n&1))
|
||||
return set_error (Parameter_Error, "odd number of digits");
|
||||
n /= 2;
|
||||
buf = xtrymalloc (n);
|
||||
if (!buf)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
|
||||
ctrl->in_data.value = buf;
|
||||
ctrl->in_data.valuelen = n;
|
||||
for (p=line, n=0; n < ctrl->in_data.valuelen; p += 2, n++)
|
||||
buf[n] = xtoi_2 (p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
pin_cb (void *opaque, const char *info, char **retstr)
|
||||
{
|
||||
ASSUAN_CONTEXT ctx = opaque;
|
||||
char *command;
|
||||
int rc;
|
||||
char *value;
|
||||
size_t valuelen;
|
||||
|
||||
*retstr = NULL;
|
||||
log_debug ("asking for PIN '%s'\n", info);
|
||||
|
||||
rc = asprintf (&command, "NEEDPIN %s", info);
|
||||
if (rc < 0)
|
||||
return GNUPG_Out_Of_Core;
|
||||
|
||||
/* FIXME: Write an inquire function which returns the result in
|
||||
secure memory */
|
||||
rc = assuan_inquire (ctx, command, &value, &valuelen, MAXLEN_PIN);
|
||||
free (command);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
|
||||
if (!valuelen || value[valuelen-1])
|
||||
{
|
||||
/* We require that the returned value is an UTF-8 string */
|
||||
xfree (value);
|
||||
return GNUPG_Invalid_Response;
|
||||
}
|
||||
*retstr = value;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* PKSIGN <hexified_id>
|
||||
|
||||
*/
|
||||
static int
|
||||
cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
void *outdata;
|
||||
size_t outdatalen;
|
||||
char *keyidstr;
|
||||
|
||||
if ((rc = open_card (ctrl)))
|
||||
return rc;
|
||||
|
||||
/* We have to use a copy of the key ID because the function may use
|
||||
the pin_cb which in turn uses the assuan line buffer and thus
|
||||
overwriting the original line with the keyid */
|
||||
keyidstr = strdup (line);
|
||||
if (!keyidstr)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
rc = card_sign (ctrl->card_ctx,
|
||||
keyidstr, GCRY_MD_SHA1,
|
||||
pin_cb, ctx,
|
||||
ctrl->in_data.value, ctrl->in_data.valuelen,
|
||||
&outdata, &outdatalen);
|
||||
free (keyidstr);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("card_sign failed: %s\n", gnupg_strerror (rc));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = assuan_send_data (ctx, outdata, outdatalen);
|
||||
xfree (outdata);
|
||||
if (rc)
|
||||
return rc; /* that is already an assuan error code */
|
||||
}
|
||||
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
/* PKDECRYPT <hexified_id>
|
||||
|
||||
*/
|
||||
static int
|
||||
cmd_pkdecrypt (ASSUAN_CONTEXT ctx, char *line)
|
||||
{
|
||||
CTRL ctrl = assuan_get_pointer (ctx);
|
||||
int rc;
|
||||
void *outdata;
|
||||
size_t outdatalen;
|
||||
char *keyidstr;
|
||||
|
||||
if ((rc = open_card (ctrl)))
|
||||
return rc;
|
||||
|
||||
keyidstr = strdup (line);
|
||||
if (!keyidstr)
|
||||
return ASSUAN_Out_Of_Core;
|
||||
rc = card_decipher (ctrl->card_ctx,
|
||||
keyidstr,
|
||||
pin_cb, ctx,
|
||||
ctrl->in_data.value, ctrl->in_data.valuelen,
|
||||
&outdata, &outdatalen);
|
||||
free (keyidstr);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("card_create_signature failed: %s\n", gnupg_strerror (rc));
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = assuan_send_data (ctx, outdata, outdatalen);
|
||||
xfree (outdata);
|
||||
if (rc)
|
||||
return rc; /* that is already an assuan error code */
|
||||
}
|
||||
|
||||
return map_to_assuan_status (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Tell the assuan library about our commands */
|
||||
static int
|
||||
register_commands (ASSUAN_CONTEXT ctx)
|
||||
{
|
||||
static struct {
|
||||
const char *name;
|
||||
int cmd_id;
|
||||
int (*handler)(ASSUAN_CONTEXT, char *line);
|
||||
} table[] = {
|
||||
{ "SERIALNO", 0, cmd_serialno },
|
||||
{ "LEARN", 0, cmd_learn },
|
||||
{ "READCERT", 0, cmd_readcert },
|
||||
{ "READKEY", 0, cmd_readkey },
|
||||
{ "SETDATA", 0, cmd_setdata },
|
||||
{ "PKSIGN", 0, cmd_pksign },
|
||||
{ "PKDECRYPT", 0,cmd_pkdecrypt },
|
||||
{ "", ASSUAN_CMD_INPUT, NULL },
|
||||
{ "", ASSUAN_CMD_OUTPUT, NULL },
|
||||
{ NULL }
|
||||
};
|
||||
int i, j, rc;
|
||||
|
||||
for (i=j=0; table[i].name; i++)
|
||||
{
|
||||
rc = assuan_register_command (ctx,
|
||||
table[i].cmd_id? table[i].cmd_id
|
||||
: (ASSUAN_CMD_USER + j++),
|
||||
table[i].name, table[i].handler);
|
||||
if (rc)
|
||||
return rc;
|
||||
}
|
||||
assuan_set_hello_line (ctx, "GNU Privacy Guard's Smartcard server ready");
|
||||
|
||||
assuan_register_reset_notify (ctx, reset_notify);
|
||||
assuan_register_option_handler (ctx, option_handler);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Startup the server. If LISTEN_FD is given as -1, this is simple
|
||||
piper server, otherwise it is a regular server */
|
||||
void
|
||||
scd_command_handler (int listen_fd)
|
||||
{
|
||||
int rc;
|
||||
ASSUAN_CONTEXT ctx;
|
||||
struct server_control_s ctrl;
|
||||
|
||||
memset (&ctrl, 0, sizeof ctrl);
|
||||
scd_init_default_ctrl (&ctrl);
|
||||
|
||||
if (listen_fd == -1)
|
||||
{
|
||||
int filedes[2];
|
||||
|
||||
filedes[0] = 0;
|
||||
filedes[1] = 1;
|
||||
rc = assuan_init_pipe_server (&ctx, filedes);
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = assuan_init_socket_server (&ctx, listen_fd);
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to initialize the server: %s\n",
|
||||
assuan_strerror(rc));
|
||||
scd_exit (2);
|
||||
}
|
||||
rc = register_commands (ctx);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to register commands with Assuan: %s\n",
|
||||
assuan_strerror(rc));
|
||||
scd_exit (2);
|
||||
}
|
||||
assuan_set_pointer (ctx, &ctrl);
|
||||
ctrl.server_local = xcalloc (1, sizeof *ctrl.server_local);
|
||||
ctrl.server_local->assuan_ctx = ctx;
|
||||
|
||||
if (DBG_ASSUAN)
|
||||
assuan_set_log_stream (ctx, log_get_stream ());
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
reset_notify (ctx); /* used for cleanup */
|
||||
|
||||
assuan_deinit_server (ctx);
|
||||
}
|
633
scd/scdaemon.c
633
scd/scdaemon.c
@ -1,633 +0,0 @@
|
||||
/* scdaemon.c - The GnuPG Smartcard Daemon
|
||||
* 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 <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>
|
||||
|
||||
#include <ksba.h>
|
||||
#include <gcrypt.h>
|
||||
|
||||
#define JNLIB_NEED_LOG_LOGV
|
||||
#include "scdaemon.h"
|
||||
#include "../assuan/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,
|
||||
oDebugSC,
|
||||
oNoGreeting,
|
||||
oNoOptions,
|
||||
oHomedir,
|
||||
oNoDetach,
|
||||
oNoGrab,
|
||||
oLogFile,
|
||||
oServer,
|
||||
oDaemon,
|
||||
oBatch,
|
||||
|
||||
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, "@"},
|
||||
{ oDebugSC, "debug-sc", 1, N_("|N|set OpenSC debug level to N")},
|
||||
{ oNoDetach, "no-detach" ,0, N_("do not detach from the console")},
|
||||
{ oLogFile, "log-file" ,2, N_("use a log file for the server")},
|
||||
|
||||
|
||||
{0}
|
||||
};
|
||||
|
||||
|
||||
static volatile int caught_fatal_sig = 0;
|
||||
|
||||
/* 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];
|
||||
|
||||
static const char *
|
||||
my_strusage (int level)
|
||||
{
|
||||
const char *p;
|
||||
switch (level)
|
||||
{
|
||||
case 11: p = "scdaemon (GnuPG)";
|
||||
break;
|
||||
case 13: p = VERSION; break;
|
||||
case 17: p = PRINTABLE_OS_NAME; break;
|
||||
case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
|
||||
break;
|
||||
case 1:
|
||||
case 40: p = _("Usage: scdaemon [options] (-h for help)");
|
||||
break;
|
||||
case 41: p = _("Syntax: scdaemon [options] [command [args]]\n"
|
||||
"Smartcard daemon for GnuPG\n");
|
||||
break;
|
||||
|
||||
default: p = NULL;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
i18n_init (void)
|
||||
{
|
||||
#ifdef USE_SIMPLE_GETTEXT
|
||||
set_gettext_file( PACKAGE );
|
||||
#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 );
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
set_strusage (my_strusage);
|
||||
gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
|
||||
/* Please note that we may running SUID(ROOT), so be very CAREFUL
|
||||
when adding any stuff between here and the call to INIT_SECMEM()
|
||||
somewhere after the option parsing */
|
||||
log_set_prefix ("scdaemon", 1|4);
|
||||
i18n_init ();
|
||||
|
||||
/* check that the libraries are suitable. Do it here because
|
||||
the option parsing may need services of the library */
|
||||
if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
|
||||
{
|
||||
log_fatal( _("libgcrypt is too old (need %s, have %s)\n"),
|
||||
NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
|
||||
}
|
||||
|
||||
ksba_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
|
||||
assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free);
|
||||
gcry_set_log_handler (my_gcry_logger, NULL);
|
||||
gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
|
||||
|
||||
may_coredump = disable_core_dumps ();
|
||||
|
||||
shell = getenv ("SHELL");
|
||||
if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") )
|
||||
csh_style = 1;
|
||||
|
||||
/* FIXME: Using this homedir option does only make sense when not
|
||||
running as a system service. We might want to check for this by
|
||||
looking at the uid or ebtter use an explict option for this */
|
||||
opt.homedir = getenv("GNUPGHOME");
|
||||
if (!opt.homedir || !*opt.homedir)
|
||||
opt.homedir = GNUPG_DEFAULT_HOMEDIR;
|
||||
|
||||
/* check whether we have a config file on the commandline */
|
||||
orig_argc = argc;
|
||||
orig_argv = argv;
|
||||
pargs.argc = &argc;
|
||||
pargs.argv = &argv;
|
||||
pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */
|
||||
while (arg_parse( &pargs, opts))
|
||||
{
|
||||
if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
|
||||
parse_debug++;
|
||||
else if (pargs.r_opt == oOptions)
|
||||
{ /* yes there is one, so we do not try the default one, but
|
||||
read the option file when it is encountered at the
|
||||
commandline */
|
||||
default_config = 0;
|
||||
}
|
||||
else if (pargs.r_opt == oNoOptions)
|
||||
default_config = 0; /* --no-options */
|
||||
else if (pargs.r_opt == oHomedir)
|
||||
opt.homedir = pargs.r.ret_str;
|
||||
}
|
||||
|
||||
/* initialize the secure memory. */
|
||||
gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
|
||||
maybe_setuid = 0;
|
||||
|
||||
/*
|
||||
Now we are working under our real uid
|
||||
*/
|
||||
|
||||
|
||||
if (default_config)
|
||||
configname = make_filename (opt.homedir, "scdaemon.conf", NULL );
|
||||
|
||||
argc = orig_argc;
|
||||
argv = orig_argv;
|
||||
pargs.argc = &argc;
|
||||
pargs.argv = &argv;
|
||||
pargs.flags= 1; /* do not remove the args */
|
||||
next_pass:
|
||||
if (configname)
|
||||
{
|
||||
configlineno = 0;
|
||||
configfp = fopen (configname, "r");
|
||||
if (!configfp)
|
||||
{
|
||||
if (default_config)
|
||||
{
|
||||
if( parse_debug )
|
||||
log_info (_("NOTE: no default option file `%s'\n"),
|
||||
configname );
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error (_("option file `%s': %s\n"),
|
||||
configname, strerror(errno) );
|
||||
exit(2);
|
||||
}
|
||||
xfree (configname);
|
||||
configname = NULL;
|
||||
}
|
||||
if (parse_debug && configname )
|
||||
log_info (_("reading options from `%s'\n"), configname );
|
||||
default_config = 0;
|
||||
}
|
||||
|
||||
while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) )
|
||||
{
|
||||
switch (pargs.r_opt)
|
||||
{
|
||||
case oQuiet: opt.quiet = 1; break;
|
||||
case oVerbose: opt.verbose++; break;
|
||||
case oBatch: opt.batch=1; break;
|
||||
|
||||
case oDebug: opt.debug |= pargs.r.ret_ulong; break;
|
||||
case oDebugAll: opt.debug = ~0; break;
|
||||
case oDebugWait: debug_wait = pargs.r.ret_int; break;
|
||||
case oDebugSC: opt.debug_sc = pargs.r.ret_int; break;
|
||||
|
||||
case oOptions:
|
||||
/* config files may not be nested (silently ignore them) */
|
||||
if (!configfp)
|
||||
{
|
||||
xfree(configname);
|
||||
configname = xstrdup(pargs.r.ret_str);
|
||||
goto next_pass;
|
||||
}
|
||||
break;
|
||||
case oNoGreeting: nogreeting = 1; break;
|
||||
case oNoVerbose: opt.verbose = 0; break;
|
||||
case oNoOptions: break; /* no-options */
|
||||
case oHomedir: opt.homedir = pargs.r.ret_str; break;
|
||||
case oNoDetach: nodetach = 1; break;
|
||||
case oLogFile: logfile = pargs.r.ret_str; break;
|
||||
case oCsh: csh_style = 1; break;
|
||||
case oSh: csh_style = 0; break;
|
||||
case oServer: pipe_server = 1; break;
|
||||
case oDaemon: is_daemon = 1; break;
|
||||
|
||||
default : pargs.err = configfp? 1:2; break;
|
||||
}
|
||||
}
|
||||
if (configfp)
|
||||
{
|
||||
fclose( configfp );
|
||||
configfp = NULL;
|
||||
xfree(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);
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
/* now start with logging to a file if this is desired */
|
||||
if (logfile)
|
||||
{
|
||||
log_set_file (logfile);
|
||||
log_set_prefix (NULL, 1|2|4);
|
||||
}
|
||||
|
||||
|
||||
if (pipe_server)
|
||||
{ /* this is the simple pipe based server */
|
||||
scd_command_handler (-1);
|
||||
}
|
||||
else if (!is_daemon)
|
||||
{
|
||||
log_info (_("please use the option `--daemon'"
|
||||
" to run the program in the background\n"));
|
||||
}
|
||||
else
|
||||
{ /* regular server mode */
|
||||
int fd;
|
||||
pid_t pid;
|
||||
int i;
|
||||
int len;
|
||||
struct sockaddr_un serv_addr;
|
||||
char *p;
|
||||
|
||||
/* fixme: if there is already a running gpg-agent we should
|
||||
share the same directory - and vice versa */
|
||||
*socket_name = 0;
|
||||
snprintf (socket_name, DIM(socket_name)-1,
|
||||
"/tmp/gpg-XXXXXX/S.scdaemon");
|
||||
socket_name[DIM(socket_name)-1] = 0;
|
||||
p = strrchr (socket_name, '/');
|
||||
if (!p)
|
||||
BUG ();
|
||||
*p = 0;;
|
||||
if (!mkdtemp(socket_name))
|
||||
{
|
||||
log_error ("can't create directory `%s': %s\n",
|
||||
socket_name, strerror(errno) );
|
||||
exit (1);
|
||||
}
|
||||
*p = '/';
|
||||
|
||||
if (strchr (socket_name, ':') )
|
||||
{
|
||||
log_error ("colons are not allowed in the socket name\n");
|
||||
exit (1);
|
||||
}
|
||||
if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path )
|
||||
{
|
||||
log_error ("name of socket to long\n");
|
||||
exit (1);
|
||||
}
|
||||
|
||||
|
||||
fd = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
{
|
||||
log_error ("can't create socket: %s\n", strerror(errno) );
|
||||
exit (1);
|
||||
}
|
||||
|
||||
memset (&serv_addr, 0, sizeof serv_addr);
|
||||
serv_addr.sun_family = AF_UNIX;
|
||||
strcpy (serv_addr.sun_path, socket_name);
|
||||
len = (offsetof (struct sockaddr_un, sun_path)
|
||||
+ strlen(serv_addr.sun_path) + 1);
|
||||
|
||||
if (bind (fd, (struct sockaddr*)&serv_addr, len) == -1)
|
||||
{
|
||||
log_error ("error binding socket to `%s': %s\n",
|
||||
serv_addr.sun_path, strerror (errno) );
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (listen (fd, 5 ) == -1)
|
||||
{
|
||||
log_error ("listen() failed: %s\n", strerror (errno));
|
||||
close (fd);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("listening on socket `%s'\n", socket_name );
|
||||
|
||||
|
||||
fflush (NULL);
|
||||
pid = fork ();
|
||||
if (pid == (pid_t)-1)
|
||||
{
|
||||
log_fatal ("fork failed: %s\n", strerror (errno) );
|
||||
exit (1);
|
||||
}
|
||||
else if (pid)
|
||||
{ /* we are the parent */
|
||||
char *infostr;
|
||||
|
||||
close (fd);
|
||||
|
||||
/* create the info string: <name>:<pid>:<protocol_version> */
|
||||
if (asprintf (&infostr, "SCDAEMON_INFO=%s:%lu:1",
|
||||
socket_name, (ulong)pid ) < 0)
|
||||
{
|
||||
log_error ("out of core\n");
|
||||
kill (pid, SIGTERM);
|
||||
exit (1);
|
||||
}
|
||||
*socket_name = 0; /* don't let cleanup() remove the socket -
|
||||
the child should do this from now on */
|
||||
if (argc)
|
||||
{ /* run the program given on the commandline */
|
||||
if (putenv (infostr))
|
||||
{
|
||||
log_error ("failed to set environment: %s\n",
|
||||
strerror (errno) );
|
||||
kill (pid, SIGTERM );
|
||||
exit (1);
|
||||
}
|
||||
execvp (argv[0], argv);
|
||||
log_error ("failed to run the command: %s\n", strerror (errno));
|
||||
kill (pid, SIGTERM);
|
||||
exit (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* print the environment string, so that the caller can use
|
||||
shell's eval to set it */
|
||||
if (csh_style)
|
||||
{
|
||||
*strchr (infostr, '=') = ' ';
|
||||
printf ( "setenv %s\n", infostr);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ( "%s; export SCDAEMON_INFO;\n", infostr);
|
||||
}
|
||||
free (infostr);
|
||||
exit (0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
} /* end parent */
|
||||
|
||||
/* this is the child */
|
||||
|
||||
/* detach from tty and put process into a new session */
|
||||
if (!nodetach )
|
||||
{ /* close stdin, stdout and stderr unless it is the log stream */
|
||||
for (i=0; i <= 2; i++)
|
||||
{
|
||||
if ( log_get_fd () != i)
|
||||
close (i);
|
||||
}
|
||||
if (setsid() == -1)
|
||||
{
|
||||
log_error ("setsid() failed: %s\n", strerror(errno) );
|
||||
cleanup ();
|
||||
exit (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* setup signals */
|
||||
{
|
||||
struct sigaction oact, nact;
|
||||
|
||||
nact.sa_handler = cleanup_sh;
|
||||
sigemptyset (&nact.sa_mask);
|
||||
nact.sa_flags = 0;
|
||||
|
||||
sigaction (SIGHUP, NULL, &oact);
|
||||
if (oact.sa_handler != SIG_IGN)
|
||||
sigaction (SIGHUP, &nact, NULL);
|
||||
sigaction( SIGTERM, NULL, &oact );
|
||||
if (oact.sa_handler != SIG_IGN)
|
||||
sigaction (SIGTERM, &nact, NULL);
|
||||
nact.sa_handler = SIG_IGN;
|
||||
sigaction (SIGPIPE, &nact, NULL);
|
||||
sigaction (SIGINT, &nact, NULL);
|
||||
}
|
||||
|
||||
if (chdir("/"))
|
||||
{
|
||||
log_error ("chdir to / failed: %s\n", strerror (errno));
|
||||
exit (1);
|
||||
}
|
||||
|
||||
scd_command_handler (fd);
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
scd_exit (int rc)
|
||||
{
|
||||
#if 0
|
||||
#warning no update_random_seed_file
|
||||
update_random_seed_file();
|
||||
#endif
|
||||
#if 0
|
||||
/* at this time a bit annoying */
|
||||
if (opt.debug & DBG_MEMSTAT_VALUE)
|
||||
{
|
||||
gcry_control( GCRYCTL_DUMP_MEMORY_STATS );
|
||||
gcry_control( GCRYCTL_DUMP_RANDOM_STATS );
|
||||
}
|
||||
if (opt.debug)
|
||||
gcry_control (GCRYCTL_DUMP_SECMEM_STATS );
|
||||
#endif
|
||||
gcry_control (GCRYCTL_TERM_SECMEM );
|
||||
rc = rc? rc : log_get_errorcount(0)? 2 : 0;
|
||||
exit (rc);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
scd_init_default_ctrl (CTRL ctrl)
|
||||
{
|
||||
|
||||
}
|
||||
|
104
scd/scdaemon.h
104
scd/scdaemon.h
@ -1,104 +0,0 @@
|
||||
/* scdaemon.h - Global definitions for the SCdaemon
|
||||
* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
#ifndef SCDAEMON_H
|
||||
#define SCDAEMON_H
|
||||
|
||||
#include <time.h>
|
||||
#include <gcrypt.h>
|
||||
#include "../common/util.h"
|
||||
#include "../common/errors.h"
|
||||
|
||||
#define MAX_DIGEST_LEN 24
|
||||
|
||||
/* A large struct name "opt" to keep global flags */
|
||||
struct {
|
||||
unsigned int debug; /* debug flags (DBG_foo_VALUE) */
|
||||
int debug_sc; /* OpenSC debug level */
|
||||
int verbose; /* verbosity level */
|
||||
int quiet; /* be as quiet as possible */
|
||||
int dry_run; /* don't change any persistent data */
|
||||
int batch; /* batch mode */
|
||||
const char *homedir; /* configuration directory name */
|
||||
} 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 card_ctx_s;
|
||||
|
||||
struct server_control_s {
|
||||
struct server_local_s *server_local;
|
||||
struct card_ctx_s *card_ctx;
|
||||
struct {
|
||||
unsigned char *value;
|
||||
int valuelen;
|
||||
} in_data; /* helper to store the value we are going to sign */
|
||||
|
||||
};
|
||||
typedef struct server_control_s *CTRL;
|
||||
typedef struct card_ctx_s *CARD;
|
||||
|
||||
/*-- scdaemon.c --*/
|
||||
void scd_exit (int rc);
|
||||
void scd_init_default_ctrl (CTRL ctrl);
|
||||
|
||||
/*-- command.c --*/
|
||||
void scd_command_handler (int);
|
||||
|
||||
/*-- card.c --*/
|
||||
int card_open (CARD *rcard);
|
||||
void card_close (CARD card);
|
||||
int card_get_serial_and_stamp (CARD card, char **serial, time_t *stamp);
|
||||
int card_enum_keypairs (CARD card, int idx,
|
||||
unsigned char *keygrip,
|
||||
char **keyid);
|
||||
int card_enum_certs (CARD card, int idx, char **certid, int *certtype);
|
||||
int card_read_cert (CARD card, const char *certidstr,
|
||||
unsigned char **cert, size_t *ncert);
|
||||
int card_sign (CARD card,
|
||||
const char *keyidstr, int hashalgo,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
void **outdata, size_t *outdatalen );
|
||||
int card_decipher (CARD card, const char *keyidstr,
|
||||
int (pincb)(void*, const char *, char **),
|
||||
void *pincb_arg,
|
||||
const void *indata, size_t indatalen,
|
||||
void **outdata, size_t *outdatalen);
|
||||
|
||||
|
||||
#endif /*SCDAEMON_H*/
|
734
sm/ChangeLog
734
sm/ChangeLog
@ -1,734 +0,0 @@
|
||||
2002-09-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c (main): Disable the internal libgcrypt locking.
|
||||
|
||||
2002-08-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* import.c (print_imported_summary): Cleaned up. Print new
|
||||
not_imported value.
|
||||
(check_and_store): Update non_imported counter.
|
||||
(print_import_problem): New.
|
||||
(check_and_store): Print error status message.
|
||||
* server.c (get_status_string): Added STATUS_IMPORT_PROBLEM.
|
||||
|
||||
2002-08-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c (main): Use the log file only in server mode.
|
||||
|
||||
* import.c (print_imported_summary): New.
|
||||
(check_and_store): Update the counters, take new argument.
|
||||
(import_one): Factored out core of gpgsm_import.
|
||||
(gpgsm_import): Print counters.
|
||||
(gpgsm_import_files): New.
|
||||
* gpgsm.c (main): Use the new function for import.
|
||||
|
||||
2002-08-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* decrypt.c (gpgsm_decrypt): Return a better error status token.
|
||||
* verify.c (gpgsm_verify): Don't error on messages with no signing
|
||||
time or no message digest. This is only the case for messages
|
||||
without any signed attributes.
|
||||
|
||||
2002-08-16 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certpath.c: Renamed to ..
|
||||
* certchain.c: this. Renamed all all other usages of "path" in the
|
||||
context of certificates to "chain".
|
||||
|
||||
* call-agent.c (learn_cb): Special treatment when the issuer
|
||||
certificate is missing.
|
||||
|
||||
2002-08-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* Makefile.am (INCLUDES): Add definition for localedir.
|
||||
|
||||
* keylist.c (list_cert_colon): Print the short fingerprint in the
|
||||
key ID field.
|
||||
* fingerprint.c (gpgsm_get_short_fingerprint): New.
|
||||
* verify.c (gpgsm_verify): Print more verbose info for a good
|
||||
signature.
|
||||
|
||||
2002-08-09 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* decrypt.c (prepare_decryption): Hack to detected already
|
||||
unpkcsedone keys.
|
||||
|
||||
* gpgsm.c (emergency_cleanup): New.
|
||||
(main): Initialize the signal handler.
|
||||
|
||||
* sign.c (gpgsm_sign): Reset the hash context for subsequent
|
||||
signers and release it at the end.
|
||||
|
||||
2002-08-05 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (cmd_signer): New command "SIGNER"
|
||||
(register_commands): Register it.
|
||||
(cmd_sign): Pass the signer list to gpgsm_sign.
|
||||
* certlist.c (gpgsm_add_to_certlist): Add SECRET argument, check
|
||||
for secret key if set and changed all callers.
|
||||
* sign.c (gpgsm_sign): New argument SIGNERLIST and implemt
|
||||
multiple signers.
|
||||
* gpgsm.c (main): Support more than one -u.
|
||||
|
||||
* server.c (cmd_recipient): Return reason code 1 for No_Public_Key
|
||||
which is actually what gets returned from add_to_certlist.
|
||||
|
||||
2002-07-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certcheck.c (gpgsm_check_cert_sig): Implement proper cleanup.
|
||||
(gpgsm_check_cms_signature): Ditto.
|
||||
|
||||
2002-07-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keydb.c (keydb_add_resource): Register a lock file.
|
||||
(lock_all, unlock_all): Implemented.
|
||||
|
||||
* delete.c: New.
|
||||
* gpgsm.c: Made --delete-key work.
|
||||
* server.c (cmd_delkeys): New.
|
||||
(register_commands): New command DELKEYS.
|
||||
|
||||
* decrypt.c (gpgsm_decrypt): Print a convenience note when RC2 is
|
||||
used and a STATUS_ERROR with the algorithm oid.
|
||||
|
||||
2002-07-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (gpgsm_status2): Insert a blank between all optional
|
||||
arguments when using assuan.
|
||||
* server.c (cmd_recipient): No more need for extra blank in constants.
|
||||
* import.c (print_imported_status): Ditto.
|
||||
* gpgsm.c (main): Ditto.
|
||||
|
||||
2002-07-02 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* verify.c (gpgsm_verify): Extend the STATUS_BADSIG line with
|
||||
the fingerprint.
|
||||
|
||||
* certpath.c (check_cert_policy): Don't use log_error to print a
|
||||
warning.
|
||||
|
||||
* keydb.c (keydb_store_cert): Add optional ar EXISTED and changed
|
||||
all callers.
|
||||
* call-agent.c (learn_cb): Print info message only for real imports.
|
||||
|
||||
* import.c (gpgsm_import): Moved duplicated code to ...
|
||||
(check_and_store): new function. Added magic to import the entire
|
||||
chain. Print status only for real imports and moved printing code
|
||||
to ..
|
||||
(print_imported_status): New.
|
||||
|
||||
* call-dirmngr.c (gpgsm_dirmngr_isvalid): print status of dirmngr
|
||||
call in very verbose mode.
|
||||
|
||||
* gpgsm.c (main): Use the same error codes for STATUS_INV_RECP as
|
||||
with the server mode.
|
||||
|
||||
2002-06-29 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c: New option --auto-issuer-key-retrieve.
|
||||
* certpath.c (find_up): Try to retrieve an issuer key from an
|
||||
external source and from the ephemeral key DB.
|
||||
(find_up_store_certs_cb): New.
|
||||
|
||||
* keydb.c (keydb_set_ephemeral): Does now return the old
|
||||
state. Call the backend only when required.
|
||||
|
||||
* call-dirmngr.c (start_dirmngr): Use GNUPG_DEFAULT_DIRMNGR.
|
||||
(lookup_status_cb): Issue status only when CTRL is not NULL.
|
||||
(gpgsm_dirmngr_lookup): Document that CTRL is optional.
|
||||
|
||||
* call-agent.c (start_agent): Use GNUPG_DEFAULT_AGENT.
|
||||
|
||||
2002-06-28 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (cmd_recipient): Add more reason codes.
|
||||
|
||||
2002-06-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certpath.c (gpgsm_basic_cert_check): Use
|
||||
--debug-no-path-validation to also bypass this basic check.
|
||||
|
||||
* gpgsm.c (main): Use GNUPG_DEFAULT_HOMEDIR constant.
|
||||
|
||||
* call-agent.c (start_agent): Create and pass the list of FD to
|
||||
keep in the child to assuan.
|
||||
* call-dirmngr.c (start_dirmngr): Ditto.
|
||||
|
||||
2002-06-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* import.c (gpgsm_import): Print an STATUS_IMPORTED.
|
||||
|
||||
* gpgsm.c: --debug-no-path-validation does not take an argument.
|
||||
|
||||
2002-06-25 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certdump.c (print_dn_part): Always print a leading slash,
|
||||
removed NEED_DELIM arg and changed caller.
|
||||
|
||||
* export.c (gpgsm_export): Print LFs to FP and not stdout.
|
||||
(print_short_info): Ditto. Make use of gpgsm_print_name.
|
||||
|
||||
* server.c (cmd_export): Use output-fd instead of data lines; this
|
||||
was actually the specified way.
|
||||
|
||||
2002-06-24 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c: Removed duped help entry for --list-keys.
|
||||
|
||||
* gpgsm.c, gpgsm.h: New option --debug-no-path-validation.
|
||||
|
||||
* certpath.c (gpgsm_validate_path): Use it here instead of the
|
||||
debug flag hack.
|
||||
|
||||
* certpath.c (check_cert_policy): Return No_Policy_Match if the
|
||||
policy file could not be opened.
|
||||
|
||||
2002-06-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certlist.c (gpgsm_add_to_certlist): Fixed locating of a
|
||||
certificate with the required key usage.
|
||||
|
||||
* gpgsm.c (main): Fixed a segv when using --outfile without an
|
||||
argument.
|
||||
|
||||
* keylist.c (print_capabilities): Also check for non-repudiation
|
||||
and data encipherment.
|
||||
* certlist.c (cert_usage_p): Test for signing and encryption was
|
||||
swapped. Add a case for certification usage, handle
|
||||
non-repudiation and data encipherment.
|
||||
(gpgsm_cert_use_cert_p): New.
|
||||
(gpgsm_add_to_certlist): Added a CTRL argument and changed all
|
||||
callers to pass it.
|
||||
* certpath.c (gpgsm_validate_path): Use it here to print a status
|
||||
message. Added a CTRL argument and changed all callers to pass it.
|
||||
* decrypt.c (gpgsm_decrypt): Print a status message for wrong key
|
||||
usage.
|
||||
* verify.c (gpgsm_verify): Ditto.
|
||||
* keydb.c (classify_user_id): Allow a colon delimited fingerprint.
|
||||
|
||||
2002-06-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-agent.c (learn_cb): Use log_info instead of log_error on
|
||||
successful import.
|
||||
|
||||
* keydb.c (keydb_set_ephemeral): New.
|
||||
(keydb_store_cert): New are ephemeral, changed all callers.
|
||||
* keylist.c (list_external_cb): Store cert as ephemeral.
|
||||
* export.c (gpgsm_export): Kludge to export epehmeral certificates.
|
||||
|
||||
* gpgsm.c (main): New command --list-external-keys.
|
||||
|
||||
2002-06-17 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certreqgen.c (read_parameters): Improved error handling.
|
||||
(gpgsm_genkey): Print error message.
|
||||
|
||||
2002-06-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c (main): New option --log-file.
|
||||
|
||||
2002-06-12 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-dirmngr.c (lookup_status_cb): New.
|
||||
(gpgsm_dirmngr_lookup): Use the status CB. Add new arg CTRL and
|
||||
changed caller to pass it.
|
||||
|
||||
* gpgsm.c (open_fwrite): New.
|
||||
(main): Allow --output for --verify.
|
||||
|
||||
* sign.c (hash_and_copy_data): New.
|
||||
(gpgsm_sign): Implemented normal (non-detached) signatures.
|
||||
* gpgsm.c (main): Ditto.
|
||||
|
||||
* certpath.c (gpgsm_validate_path): Special error handling for
|
||||
no policy match.
|
||||
|
||||
2002-06-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (get_status_string): Add STATUS_ERROR.
|
||||
|
||||
* certpath.c (gpgsm_validate_path): Tweaked the error checking to
|
||||
return error codes in a more sensitive way.
|
||||
* verify.c (gpgsm_verify): Send status TRUST_NEVER also for a bad
|
||||
CA certificate and when the certificate has been revoked. Issue
|
||||
TRUST_FULLY even when the cert has expired. Append an error token
|
||||
to these status lines. Issue the new generic error status when a
|
||||
cert was not found and when leaving the function.
|
||||
|
||||
2002-06-04 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c (main): New command --list-sigs
|
||||
* keylist.c (list_cert_std): New. Use it whenever colon mode is
|
||||
not used.
|
||||
(list_cert_chain): New.
|
||||
|
||||
2002-05-31 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c (main): Don't print the "go ahead" message for an
|
||||
invalid command.
|
||||
|
||||
2002-05-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* import.c (gpgsm_import): Add error messages.
|
||||
|
||||
2002-05-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keylist.c (list_internal_keys): Renamed from gpgsm_list_keys.
|
||||
(list_external_keys): New.
|
||||
(gpgsm_list_keys): Dispatcher for above.
|
||||
* call-dirmngr.c (lookup_cb,pattern_from_strlist)
|
||||
(gpgsm_dirmngr_lookup): New.
|
||||
* server.c (option_handler): Handle new option --list-mode.
|
||||
(do_listkeys): Handle options and actually use the mode argument.
|
||||
(get_status_string): New code TRUNCATED.
|
||||
|
||||
* import.c (gpgsm_import): Try to identify the type of input and
|
||||
handle certs-only messages.
|
||||
|
||||
2002-05-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c: New option --faked-system-time
|
||||
* sign.c (gpgsm_sign): And use it here.
|
||||
* certpath.c (gpgsm_validate_path): Ditto.
|
||||
|
||||
2002-05-03 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certpath.c (gpgsm_validate_path): Added EXPTIME arg and changed
|
||||
all callers.
|
||||
* verify.c (gpgsm_verify): Tweaked usage of log_debug and
|
||||
log_error. Return EXPSIG status and add expiretime to VALIDSIG.
|
||||
|
||||
2002-04-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.h (DBG_AGENT,DBG_AGENT_VALUE): Replaced by DBG_ASSUAN_*.
|
||||
Changed all users.
|
||||
|
||||
* call-agent.c (start_agent): Be more silent without -v.
|
||||
* call-dirmngr.c (start_dirmngr): Ditto.
|
||||
|
||||
2002-04-25 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-agent.c (start_agent): Make copies of old locales and check
|
||||
for setlocale.
|
||||
|
||||
2002-04-25 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* call-agent.c (start_agent): Fix error handling logic so the
|
||||
locale is always correctly reset.
|
||||
|
||||
2002-04-25 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* server.c (option_handler): Accept display, ttyname, ttytype,
|
||||
lc_ctype and lc_messages options.
|
||||
* gpgsm.c (main): Allocate memory for these options.
|
||||
* gpgsm.h (struct opt): Make corresponding members non-const.
|
||||
|
||||
2002-04-24 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* gpgsm.h (struct opt): New members display, ttyname, ttytype,
|
||||
lc_ctype, lc_messages.
|
||||
* gpgsm.c (enum cmd_and_opt_values): New members oDisplay,
|
||||
oTTYname, oTTYtype, oLCctype, oLCmessages.
|
||||
(opts): New entries for these options.
|
||||
(main): Handle these new options.
|
||||
* call-agent.c (start_agent): Set the various display and tty
|
||||
parameter after resetting.
|
||||
|
||||
2002-04-18 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certreqgen.c (gpgsm_genkey): Write status output on success.
|
||||
|
||||
2002-04-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c (main): Check ksba version.
|
||||
|
||||
* certpath.c (find_up): New to use the authorithKeyIdentifier.
|
||||
Use it in all other functions to locate the signing cert..
|
||||
|
||||
2002-04-11 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certlist.c (cert_usable_p): New.
|
||||
(gpgsm_cert_use_sign_p,gpgsm_cert_use_encrypt_p): New.
|
||||
(gpgsm_cert_use_verify_p,gpgsm_cert_use_decrypt_p): New.
|
||||
(gpgsm_add_to_certlist): Check the key usage.
|
||||
* sign.c (gpgsm_sign): Ditto.
|
||||
* verify.c (gpgsm_verify): Print a message wehn an unsuitable
|
||||
certificate was used.
|
||||
* decrypt.c (gpgsm_decrypt): Ditto
|
||||
* keylist.c (print_capabilities): Determine values from the cert.
|
||||
|
||||
2002-03-28 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keylist.c (list_cert_colon): Fixed listing of crt record; the
|
||||
issuer is not at the right place. Print a chainingID.
|
||||
* certpath.c (gpgsm_walk_cert_chain): Be a bit more silent on
|
||||
common errors.
|
||||
|
||||
2002-03-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* export.c: New.
|
||||
* gpgsm.c: Add command --export.
|
||||
* server.c (cmd_export): New.
|
||||
|
||||
2002-03-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* decrypt.c (gpgsm_decrypt): Allow multiple recipients.
|
||||
|
||||
2002-03-12 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certpath.c (check_cert_policy): Print the policy list.
|
||||
|
||||
* verify.c (gpgsm_verify): Detect certs-only message.
|
||||
|
||||
2002-03-11 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* import.c (gpgsm_import): Print a notice about imported certificates
|
||||
when in verbose mode.
|
||||
|
||||
* gpgsm.c (main): Print INV_RECP status.
|
||||
* server.c (cmd_recipient): Ditto.
|
||||
|
||||
* server.c (gpgsm_status2): New. Allows for a list of strings.
|
||||
(gpgsm_status): Divert to gpgsm_status2.
|
||||
|
||||
* encrypt.c (gpgsm_encrypt): Don't use a default key when no
|
||||
recipients are given. Print a NO_RECP status.
|
||||
|
||||
2002-03-06 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (cmd_listkeys, cmd_listsecretkeys): Divert to
|
||||
(do_listkeys): new. Add pattern parsing.
|
||||
|
||||
* keylist.c (gpgsm_list_keys): Handle selection pattern.
|
||||
|
||||
* gpgsm.c: New command --learn-card
|
||||
* call-agent.c (learn_cb,gpgsm_agent_learn): New.
|
||||
|
||||
* gpgsm.c (main): Print error messages for non-implemented commands.
|
||||
|
||||
* base64.c (base64_reader_cb): Use case insensitive compare of the
|
||||
Content-Type string to detect plain base-64.
|
||||
|
||||
2002-03-05 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c, gpgsm.h: Add local_user.
|
||||
* sign.c (gpgsm_get_default_cert): New.
|
||||
(get_default_signer): Use the new function if local_user is not
|
||||
set otherwise used that value.
|
||||
* encrypt.c (get_default_recipient): Removed.
|
||||
(gpgsm_encrypt): Use gpgsm_get_default_cert.
|
||||
|
||||
* verify.c (gpgsm_verify): Better error text for a bad signature
|
||||
found by comparing the hashs.
|
||||
|
||||
2002-02-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-dirmngr.c, call-agent.c: Add 2 more arguments to all uses
|
||||
of assuan_transact.
|
||||
|
||||
2002-02-25 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (option_handler): Allow to use -2 for "send all certs
|
||||
except the root cert".
|
||||
* sign.c (add_certificate_list): Implement it here.
|
||||
* certpath.c (gpgsm_is_root_cert): New.
|
||||
|
||||
2002-02-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certpath.c (check_cert_policy): New.
|
||||
(gpgsm_validate_path): And call it from here.
|
||||
* gpgsm.c (main): New options --policy-file,
|
||||
--disable-policy-checks and --enable-policy-checks.
|
||||
* gpgsm.h (opt): Added policy_file, no_policy_checks.
|
||||
|
||||
2002-02-18 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certpath.c (gpgsm_validate_path): Ask the agent to add the
|
||||
certificate into the trusted list.
|
||||
* call-agent.c (gpgsm_agent_marktrusted): New.
|
||||
|
||||
2002-02-07 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certlist.c (gpgsm_add_to_certlist): Check that the specified
|
||||
name identifies a certificate unambiguously.
|
||||
(gpgsm_find_cert): Ditto.
|
||||
|
||||
* server.c (cmd_listkeys): Check that the data stream is available.
|
||||
(cmd_listsecretkeys): Ditto.
|
||||
(has_option): New.
|
||||
(cmd_sign): Fix ambiguousity in option recognition.
|
||||
|
||||
* gpgsm.c (main): Enable --logger-fd.
|
||||
|
||||
* encrypt.c (gpgsm_encrypt): Increased buffer size for better
|
||||
performance.
|
||||
|
||||
* call-agent.c (gpgsm_agent_pksign): Check the S-Exp received from
|
||||
the agent.
|
||||
|
||||
* keylist.c (list_cert_colon): Filter out control characters.
|
||||
|
||||
2002-02-06 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* decrypt.c (gpgsm_decrypt): Bail out after an decryption error.
|
||||
|
||||
* server.c (reset_notify): Close input and output FDs.
|
||||
(cmd_encrypt,cmd_decrypt,cmd_verify,cmd_sign.cmd_import)
|
||||
(cmd_genkey): Close the FDs and release the recipient list even in
|
||||
the error case.
|
||||
|
||||
2002-02-01 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* sign.c (gpgsm_sign): Do not release certificate twice.
|
||||
|
||||
2002-01-29 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-agent.c (gpgsm_agent_havekey): New.
|
||||
* keylist.c (list_cert_colon): New arg HAVE_SECRET, print "crs"
|
||||
when we know that the secret key is available.
|
||||
(gpgsm_list_keys): New arg MODE, check whether a secret key is
|
||||
available. Changed all callers.
|
||||
* gpgsm.c (main): New command --list-secret-keys.
|
||||
* server.c (cmd_listsecretkeys): New.
|
||||
(cmd_listkeys): Return secret keys with "crs" record.
|
||||
|
||||
2002-01-28 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certreqgen.c (create_request): Store the email address in the req.
|
||||
|
||||
2002-01-25 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c (main): Disable core dumps.
|
||||
|
||||
* sign.c (add_certificate_list): New.
|
||||
(gpgsm_sign): Add the certificates to the CMS object.
|
||||
* certpath.c (gpgsm_walk_cert_chain): New.
|
||||
* gpgsm.h (server_control_s): Add included_certs.
|
||||
* gpgsm.c: Add option --include-certs.
|
||||
(gpgsm_init_default_ctrl): New.
|
||||
(main): Call it.
|
||||
* server.c (gpgsm_server): Ditto.
|
||||
(option_handler): Support --include-certs.
|
||||
|
||||
2002-01-23 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certpath.c (gpgsm_validate_path): Print the DN of a missing issuer.
|
||||
* certdump.c (gpgsm_dump_string): New.
|
||||
(print_dn): Replaced by above.
|
||||
|
||||
2002-01-22 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certpath.c (unknown_criticals): New.
|
||||
(allowed_ca): New.
|
||||
(gpgsm_validate_path): Check validity, CA attribute, path length
|
||||
and unknown critical extensions.
|
||||
|
||||
2002-01-21 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c: Add option --enable-crl-checks.
|
||||
|
||||
* call-agent.c (start_agent): Implemented socket based access.
|
||||
* call-dirmngr.c (start_dirmngr): Ditto.
|
||||
|
||||
2002-01-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (option_handler): New.
|
||||
(gpgsm_server): Register it with assuan.
|
||||
|
||||
2002-01-19 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (gpgsm_server): Use assuan_deinit_server and setup
|
||||
assuan logging if enabled.
|
||||
* call-agent.c (inq_ciphertext_cb): Don't show the session key in
|
||||
an Assuan log file.
|
||||
|
||||
* gpgsm.c (my_strusage): Take bugreport address from configure.ac
|
||||
|
||||
2002-01-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* import.c (gpgsm_import): Just do a basic cert check before
|
||||
storing it.
|
||||
* certpath.c (gpgsm_basic_cert_check): New.
|
||||
|
||||
* keydb.c (keydb_store_cert): New.
|
||||
* import.c (store_cert): Removed and change all caller to use
|
||||
the new function.
|
||||
* verify.c (store_cert): Ditto.
|
||||
|
||||
* certlist.c (gpgsm_add_to_certlist): Validate the path
|
||||
|
||||
* certpath.c (gpgsm_validate_path): Check the trust list.
|
||||
* call-agent.c (gpgsm_agent_istrusted): New.
|
||||
|
||||
2002-01-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-dirmngr.c (inq_certificate): Changed for new interface semantic.
|
||||
* certlist.c (gpgsm_find_cert): New.
|
||||
|
||||
2002-01-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* fingerprint.c (gpgsm_get_certid): Print the serial and not the
|
||||
hash after the dot.
|
||||
|
||||
2002-01-11 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-dirmngr.c: New.
|
||||
* certpath.c (gpgsm_validate_path): Check the CRL here.
|
||||
* fingerprint.c (gpgsm_get_certid): New.
|
||||
* gpgsm.c: New options --dirmngr-program and --disable-crl-checks.
|
||||
|
||||
2002-01-10 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* base64.c (gpgsm_create_writer): Allow to set the object name
|
||||
|
||||
2002-01-08 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keydb.c (spacep): Removed because it is now in util.c
|
||||
|
||||
* server.c (cmd_genkey): New.
|
||||
* certreqgen.c: New. The parameter handling code has been taken
|
||||
from gnupg/g10/keygen.c version 1.0.6.
|
||||
* call-agent.c (gpgsm_agent_genkey): New.
|
||||
|
||||
2002-01-02 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* server.c (rc_to_assuan_status): Removed and changed all callers
|
||||
to use map_to_assuan_status.
|
||||
|
||||
2001-12-20 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* verify.c (gpgsm_verify): Implemented non-detached signature
|
||||
verification. Add OUT_FP arg, initialize a writer and changed all
|
||||
callers.
|
||||
* server.c (cmd_verify): Pass an out_fp if one has been set.
|
||||
|
||||
* base64.c (base64_reader_cb): Try to detect an S/MIME body part.
|
||||
|
||||
* certdump.c (print_sexp): Renamed to gpgsm_dump_serial, made
|
||||
global.
|
||||
(print_time): Renamed to gpgsm_dump_time, made global.
|
||||
(gpgsm_dump_serial): Take a real S-Expression as argument and
|
||||
print the first item.
|
||||
* keylist.c (list_cert_colon): Ditto.
|
||||
* keydb.c (keydb_search_issuer_sn): Ditto.
|
||||
* decrypt.c (print_integer_sexp): Removed and made callers
|
||||
use gpgsm_dump_serial.
|
||||
* verify.c (print_time): Removed, made callers use gpgsm_dump_time.
|
||||
|
||||
2001-12-19 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* call-agent.c (start_agent): Add new argument to assuan_pipe_connect.
|
||||
|
||||
2001-12-18 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* verify.c (print_integer_sexp): Renamed from print_integer and
|
||||
print the serial number according to the S-Exp rules.
|
||||
* decrypt.c (print_integer_sexp): Ditto.
|
||||
|
||||
2001-12-17 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keylist.c (list_cert_colon): Changed for new return value of
|
||||
get_serial.
|
||||
* keydb.c (keydb_search_issuer_sn): Ditto.
|
||||
* certcheck.c (gpgsm_check_cert_sig): Likewise for other S-Exp
|
||||
returingin functions.
|
||||
* fingerprint.c (gpgsm_get_keygrip): Ditto.
|
||||
* encrypt.c (encrypt_dek): Ditto
|
||||
* certcheck.c (gpgsm_check_cms_signature): Ditto
|
||||
* decrypt.c (prepare_decryption): Ditto.
|
||||
* call-agent.c (gpgsm_agent_pkdecrypt): Removed arg ciphertextlen,
|
||||
use KsbaSexp type and calculate the length.
|
||||
|
||||
* certdump.c (print_sexp): Remaned from print_integer, changed caller.
|
||||
|
||||
* Makefile.am: Use the LIBGCRYPT and LIBKSBA variables.
|
||||
|
||||
* fingerprint.c (gpgsm_get_keygrip): Use the new
|
||||
gcry_pk_get_keygrip to calculate the grip - note the algorithm and
|
||||
therefore the grip values changed.
|
||||
|
||||
2001-12-15 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* certcheck.c (gpgsm_check_cms_signature): Removed the faked-key
|
||||
kludge.
|
||||
(gpgsm_create_cms_signature): Removed the commented fake key
|
||||
code. This makes the function pretty simple.
|
||||
|
||||
* gpgsm.c (main): Renamed the default key database to "keyring.kbx".
|
||||
|
||||
* decrypt.c (gpgsm_decrypt): Write STATUS_DECRYPTION_*.
|
||||
* sign.c (gpgsm_sign): Write a STATUS_SIG_CREATED.
|
||||
|
||||
2001-12-14 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keylist.c (list_cert_colon): Kludge to show an email address
|
||||
encoded in the subject's DN.
|
||||
|
||||
* verify.c (gpgsm_verify): Add hash debug helpers
|
||||
* sign.c (gpgsm_sign): Ditto.
|
||||
|
||||
* base64.c (base64_reader_cb): Reset the linelen when we need to
|
||||
skip the line and adjusted test; I somehow forgot about DeMorgan.
|
||||
|
||||
* server.c (cmd_encrypt,cmd_decrypt,cmd_sign,cmd_verify)
|
||||
(cmd_import): Close the FDs on success.
|
||||
(close_message_fd): New.
|
||||
(input_notify): Setting autodetect_encoding to 0 after initializing
|
||||
it to 0 is pretty pointless. Easy to fix.
|
||||
|
||||
* gpgsm.c (main): New option --debug-wait n, so that it is
|
||||
possible to attach gdb when used in server mode.
|
||||
|
||||
* sign.c (get_default_signer): Use keydb_classify_name here.
|
||||
|
||||
2001-12-14 Marcus Brinkmann <marcus@g10code.de>
|
||||
|
||||
* call-agent.c (LINELENGTH): Removed.
|
||||
(gpgsm_agent_pksign): Use ASSUAN_LINELENGTH, not LINELENGTH.
|
||||
(gpgsm_agent_pkdecrypt): Likewise.
|
||||
|
||||
2001-12-13 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* keylist.c (list_cert_colon): Print alternative names of subject
|
||||
and a few other values.
|
||||
|
||||
2001-12-12 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c (main): New options --assume-{armor,base64,binary}.
|
||||
* base64.c (base64_reader_cb): Fixed non-autodetection mode.
|
||||
|
||||
2001-12-04 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* call-agent.c (read_from_agent): Check for inquire responses.
|
||||
(request_reply): Handle them using a new callback arg, changed all
|
||||
callers.
|
||||
(gpgsm_agent_pkdecrypt): New.
|
||||
|
||||
2001-11-27 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* base64.c: New. Changed all other functions to use this instead
|
||||
of direct creation of ksba_reader/writer.
|
||||
* gpgsm.c (main): Set ctrl.auto_encoding unless --no-armor is used.
|
||||
|
||||
2001-11-26 Werner Koch <wk@gnupg.org>
|
||||
|
||||
* gpgsm.c: New option --agent-program
|
||||
* call-agent.c (start_agent): Allow to override the default path
|
||||
to the agent.
|
||||
|
||||
* keydb.c (keydb_add_resource): Create keybox
|
||||
|
||||
* keylist.c (gpgsm_list_keys): Fixed non-server keylisting.
|
||||
|
||||
* server.c (rc_to_assuan_status): New. Use it for all commands.
|
||||
|
||||
|
||||
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.
|
@ -1,57 +0,0 @@
|
||||
# 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
|
||||
|
||||
## Process this file with automake to produce Makefile.in
|
||||
|
||||
localedir = $(datadir)/locale
|
||||
INCLUDES = -I../intl -DLOCALEDIR=\"$(localedir)\"
|
||||
|
||||
bin_PROGRAMS = gpgsm
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/common -I$(top_srcdir)/intl \
|
||||
$(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS)
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
gpgsm_SOURCES = \
|
||||
gpgsm.c gpgsm.h \
|
||||
misc.c \
|
||||
keydb.c keydb.h \
|
||||
server.c \
|
||||
call-agent.c \
|
||||
call-dirmngr.c \
|
||||
fingerprint.c \
|
||||
base64.c \
|
||||
certlist.c \
|
||||
certdump.c \
|
||||
certcheck.c \
|
||||
certchain.c \
|
||||
keylist.c \
|
||||
verify.c \
|
||||
sign.c \
|
||||
encrypt.c \
|
||||
decrypt.c \
|
||||
import.c \
|
||||
export.c \
|
||||
delete.c \
|
||||
certreqgen.c
|
||||
|
||||
|
||||
gpgsm_LDADD = ../jnlib/libjnlib.a ../assuan/libassuan.a ../kbx/libkeybox.a \
|
||||
../common/libcommon.a $(LIBGCRYPT_LIBS) $(KSBA_LIBS)
|
||||
|
||||
|
624
sm/base64.c
624
sm/base64.c
@ -1,624 +0,0 @@
|
||||
/* base64.c
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "i18n.h"
|
||||
|
||||
#ifdef HAVE_DOSISH_SYSTEM
|
||||
#define LF "\r\n"
|
||||
#else
|
||||
#define LF "\n"
|
||||
#endif
|
||||
|
||||
/* data used by the reader callbacks */
|
||||
struct reader_cb_parm_s {
|
||||
FILE *fp;
|
||||
unsigned char line[1024];
|
||||
int linelen;
|
||||
int readpos;
|
||||
int have_lf;
|
||||
unsigned long line_counter;
|
||||
|
||||
int autodetect; /* try to detect the input encoding */
|
||||
int assume_pem; /* assume input encoding is PEM */
|
||||
int assume_base64; /* assume input is base64 encoded */
|
||||
|
||||
int identified;
|
||||
int is_pem;
|
||||
int is_base64;
|
||||
int stop_seen;
|
||||
int might_be_smime;
|
||||
|
||||
struct {
|
||||
int idx;
|
||||
unsigned char val;
|
||||
int stop_seen;
|
||||
} base64;
|
||||
};
|
||||
|
||||
/* data used by the writer callbacks */
|
||||
struct writer_cb_parm_s {
|
||||
FILE *fp;
|
||||
const char *pem_name;
|
||||
|
||||
int wrote_begin;
|
||||
int did_finish;
|
||||
|
||||
struct {
|
||||
int idx;
|
||||
int quad_count;
|
||||
unsigned char radbuf[4];
|
||||
} base64;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* context for this module's functions */
|
||||
struct base64_context_s {
|
||||
union {
|
||||
struct reader_cb_parm_s rparm;
|
||||
struct writer_cb_parm_s wparm;
|
||||
} u;
|
||||
};
|
||||
|
||||
|
||||
/* The base-64 character list */
|
||||
static unsigned char bintoasc[64] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"0123456789+/";
|
||||
/* The reverse base-64 list */
|
||||
static unsigned char asctobin[256] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
|
||||
0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
|
||||
0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12,
|
||||
0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24,
|
||||
0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
|
||||
0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
|
||||
static int
|
||||
has_only_base64 (const unsigned char *line, int linelen)
|
||||
{
|
||||
if (linelen < 20)
|
||||
return 0;
|
||||
for (; linelen; line++, linelen--)
|
||||
{
|
||||
if (*line == '\n' || (linelen > 1 && *line == '\r' && line[1] == '\n'))
|
||||
break;
|
||||
if ( !strchr (bintoasc, *line) )
|
||||
return 0;
|
||||
}
|
||||
return 1; /* yes */
|
||||
}
|
||||
|
||||
static int
|
||||
is_empty_line (const unsigned char *line, int linelen)
|
||||
{
|
||||
if (linelen >= 2 && *line == '\r' && line[1] == '\n')
|
||||
return 1;
|
||||
if (linelen >= 1 && *line == '\n')
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
{
|
||||
struct reader_cb_parm_s *parm = cb_value;
|
||||
size_t n;
|
||||
int c, c2;
|
||||
|
||||
*nread = 0;
|
||||
if (!buffer)
|
||||
return -1; /* not supported */
|
||||
|
||||
next:
|
||||
if (!parm->linelen)
|
||||
{
|
||||
/* read an entire line or up to the size of the buffer */
|
||||
parm->line_counter++;
|
||||
parm->have_lf = 0;
|
||||
for (n=0; n < DIM(parm->line);)
|
||||
{
|
||||
c = getc (parm->fp);
|
||||
if (c == EOF)
|
||||
{
|
||||
if (ferror (parm->fp))
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
parm->line[n++] = c;
|
||||
if (c == '\n')
|
||||
{
|
||||
parm->have_lf = 1;
|
||||
/* Fixme: we need to skip overlong lines while detecting
|
||||
the dashed lines */
|
||||
break;
|
||||
}
|
||||
}
|
||||
parm->linelen = n;
|
||||
if (!n)
|
||||
return -1; /* eof */
|
||||
parm->readpos = 0;
|
||||
}
|
||||
|
||||
if (!parm->identified)
|
||||
{
|
||||
if (!parm->autodetect)
|
||||
{
|
||||
if (parm->assume_pem)
|
||||
{
|
||||
/* wait for the header line */
|
||||
parm->linelen = parm->readpos = 0;
|
||||
if (!parm->have_lf || strncmp (parm->line, "-----BEGIN ", 11)
|
||||
|| !strncmp (parm->line+11, "PGP ", 4))
|
||||
goto next;
|
||||
parm->is_pem = 1;
|
||||
}
|
||||
else if (parm->assume_base64)
|
||||
parm->is_base64 = 1;
|
||||
}
|
||||
else if (parm->line_counter == 1 && !parm->have_lf)
|
||||
{
|
||||
/* first line too long - assume DER encoding */
|
||||
parm->is_pem = 0;
|
||||
}
|
||||
else if (parm->line_counter == 1 && parm->linelen && *parm->line == 0x30)
|
||||
{
|
||||
/* the very first byte does pretty much look like a SEQUENCE tag*/
|
||||
parm->is_pem = 0;
|
||||
}
|
||||
else if ( parm->have_lf && !strncmp (parm->line, "-----BEGIN ", 11)
|
||||
&& strncmp (parm->line+11, "PGP ", 4) )
|
||||
{
|
||||
/* Fixme: we must only compare if the line really starts at
|
||||
the beginning */
|
||||
parm->is_pem = 1;
|
||||
parm->linelen = parm->readpos = 0;
|
||||
}
|
||||
else if ( parm->have_lf && parm->line_counter == 1
|
||||
&& parm->linelen >= 13
|
||||
&& !ascii_memcasecmp (parm->line, "Content-Type:", 13))
|
||||
{ /* might be a S/MIME body */
|
||||
parm->might_be_smime = 1;
|
||||
parm->linelen = parm->readpos = 0;
|
||||
goto next;
|
||||
}
|
||||
else if (parm->might_be_smime == 1
|
||||
&& is_empty_line (parm->line, parm->linelen))
|
||||
{
|
||||
parm->might_be_smime = 2;
|
||||
parm->linelen = parm->readpos = 0;
|
||||
goto next;
|
||||
}
|
||||
else if (parm->might_be_smime == 2)
|
||||
{
|
||||
parm->might_be_smime = 0;
|
||||
if ( !has_only_base64 (parm->line, parm->linelen))
|
||||
{
|
||||
parm->linelen = parm->readpos = 0;
|
||||
goto next;
|
||||
}
|
||||
parm->is_pem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
parm->linelen = parm->readpos = 0;
|
||||
goto next;
|
||||
}
|
||||
parm->identified = 1;
|
||||
parm->base64.stop_seen = 0;
|
||||
parm->base64.idx = 0;
|
||||
}
|
||||
|
||||
|
||||
n = 0;
|
||||
if (parm->is_pem || parm->is_base64)
|
||||
{
|
||||
if (parm->is_pem && parm->have_lf
|
||||
&& !strncmp (parm->line, "-----END ", 9))
|
||||
{
|
||||
parm->identified = 0;
|
||||
parm->linelen = parm->readpos = 0;
|
||||
/* let us return 0 */
|
||||
}
|
||||
else if (parm->stop_seen)
|
||||
{ /* skip the rest of the line */
|
||||
parm->linelen = parm->readpos = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int idx = parm->base64.idx;
|
||||
unsigned char val = parm->base64.val;
|
||||
|
||||
while (n < count && parm->readpos < parm->linelen )
|
||||
{
|
||||
c = parm->line[parm->readpos++];
|
||||
if (c == '\n' || c == ' ' || c == '\r' || c == '\t')
|
||||
continue;
|
||||
if (c == '=')
|
||||
{ /* pad character: stop */
|
||||
if (idx == 1)
|
||||
buffer[n++] = val;
|
||||
parm->stop_seen = 1;
|
||||
break;
|
||||
}
|
||||
if( (c = asctobin[(c2=c)]) == 255 )
|
||||
{
|
||||
log_error (_("invalid radix64 character %02x skipped\n"),
|
||||
c2);
|
||||
continue;
|
||||
}
|
||||
switch (idx)
|
||||
{
|
||||
case 0:
|
||||
val = c << 2;
|
||||
break;
|
||||
case 1:
|
||||
val |= (c>>4)&3;
|
||||
buffer[n++] = val;
|
||||
val = (c<<4)&0xf0;
|
||||
break;
|
||||
case 2:
|
||||
val |= (c>>2)&15;
|
||||
buffer[n++] = val;
|
||||
val = (c<<6)&0xc0;
|
||||
break;
|
||||
case 3:
|
||||
val |= c&0x3f;
|
||||
buffer[n++] = val;
|
||||
break;
|
||||
}
|
||||
idx = (idx+1) % 4;
|
||||
}
|
||||
if (parm->readpos == parm->linelen)
|
||||
parm->linelen = parm->readpos = 0;
|
||||
|
||||
parm->base64.idx = idx;
|
||||
parm->base64.val = val;
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* DER encoded */
|
||||
while (n < count && parm->readpos < parm->linelen)
|
||||
buffer[n++] = parm->line[parm->readpos++];
|
||||
if (parm->readpos == parm->linelen)
|
||||
parm->linelen = parm->readpos = 0;
|
||||
}
|
||||
|
||||
*nread = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int
|
||||
simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
{
|
||||
struct reader_cb_parm_s *parm = cb_value;
|
||||
size_t n;
|
||||
int c = 0;
|
||||
|
||||
*nread = 0;
|
||||
if (!buffer)
|
||||
return -1; /* not supported */
|
||||
|
||||
for (n=0; n < count; n++)
|
||||
{
|
||||
c = getc (parm->fp);
|
||||
if (c == EOF)
|
||||
{
|
||||
if ( ferror (parm->fp) )
|
||||
return -1;
|
||||
if (n)
|
||||
break; /* return what we have before an EOF */
|
||||
return -1;
|
||||
}
|
||||
*(byte *)buffer++ = c;
|
||||
}
|
||||
|
||||
*nread = n;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
static int
|
||||
base64_writer_cb (void *cb_value, const void *buffer, size_t count)
|
||||
{
|
||||
struct writer_cb_parm_s *parm = cb_value;
|
||||
unsigned char radbuf[4];
|
||||
int i, c, idx, quad_count;
|
||||
const unsigned char *p;
|
||||
FILE *fp = parm->fp;
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (!parm->wrote_begin)
|
||||
{
|
||||
if (parm->pem_name)
|
||||
{
|
||||
fputs ("-----BEGIN ", fp);
|
||||
fputs (parm->pem_name, fp);
|
||||
fputs ("-----\n", fp);
|
||||
}
|
||||
parm->wrote_begin = 1;
|
||||
parm->base64.idx = 0;
|
||||
parm->base64.quad_count = 0;
|
||||
}
|
||||
|
||||
idx = parm->base64.idx;
|
||||
quad_count = parm->base64.quad_count;
|
||||
for (i=0; i < idx; i++)
|
||||
radbuf[i] = parm->base64.radbuf[i];
|
||||
|
||||
for (p=buffer; count; p++, count--)
|
||||
{
|
||||
radbuf[idx++] = *p;
|
||||
if (idx > 2)
|
||||
{
|
||||
idx = 0;
|
||||
c = bintoasc[(*radbuf >> 2) & 077];
|
||||
putc (c, fp);
|
||||
c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1] >> 4)&017))&077];
|
||||
putc (c, fp);
|
||||
c = bintoasc[(((radbuf[1]<<2)&074)|((radbuf[2]>>6)&03))&077];
|
||||
putc (c, fp);
|
||||
c = bintoasc[radbuf[2]&077];
|
||||
putc (c, fp);
|
||||
if (++quad_count >= (64/4))
|
||||
{
|
||||
fputs (LF, fp);
|
||||
quad_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i=0; i < idx; i++)
|
||||
parm->base64.radbuf[i] = radbuf[i];
|
||||
parm->base64.idx = idx;
|
||||
parm->base64.quad_count = quad_count;
|
||||
|
||||
return ferror (fp) ? KSBA_Write_Error:0;
|
||||
}
|
||||
|
||||
static int
|
||||
base64_finish_write (struct writer_cb_parm_s *parm)
|
||||
{
|
||||
unsigned char radbuf[4];
|
||||
int i, c, idx, quad_count;
|
||||
FILE *fp = parm->fp;
|
||||
|
||||
if (!parm->wrote_begin)
|
||||
return 0; /* nothing written */
|
||||
|
||||
/* flush the base64 encoding */
|
||||
idx = parm->base64.idx;
|
||||
quad_count = parm->base64.quad_count;
|
||||
for (i=0; i < idx; i++)
|
||||
radbuf[i] = parm->base64.radbuf[i];
|
||||
|
||||
if (idx)
|
||||
{
|
||||
c = bintoasc[(*radbuf>>2)&077];
|
||||
putc (c, fp);
|
||||
if (idx == 1)
|
||||
{
|
||||
c = bintoasc[((*radbuf << 4) & 060) & 077];
|
||||
putc (c, fp);
|
||||
putc ('=', fp);
|
||||
putc ('=', fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
c = bintoasc[(((*radbuf<<4)&060)|((radbuf[1]>>4)&017))&077];
|
||||
putc (c, fp);
|
||||
c = bintoasc[((radbuf[1] << 2) & 074) & 077];
|
||||
putc (c, fp);
|
||||
putc ('=', fp);
|
||||
|
||||
}
|
||||
if (++quad_count >= (64/4))
|
||||
{
|
||||
fputs (LF, fp);
|
||||
quad_count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (quad_count)
|
||||
fputs (LF, fp);
|
||||
|
||||
if (parm->pem_name)
|
||||
{
|
||||
fputs ("-----END ", fp);
|
||||
fputs (parm->pem_name, fp);
|
||||
fputs ("-----\n", fp);
|
||||
}
|
||||
return ferror (fp)? GNUPG_Write_Error : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Create a reader for the given file descriptor. Depending on the
|
||||
control information an input decoding is automagically choosen.
|
||||
The function returns a Base64Context object which must be passed to
|
||||
the gpgme_destroy_reader function. The created KsbaReader object
|
||||
is also returned, but the caller must not call the
|
||||
ksba_reader_release function on. */
|
||||
int
|
||||
gpgsm_create_reader (Base64Context *ctx,
|
||||
CTRL ctrl, FILE *fp, KsbaReader *r_reader)
|
||||
{
|
||||
int rc;
|
||||
KsbaReader r;
|
||||
|
||||
*r_reader = NULL;
|
||||
*ctx = xtrycalloc (1, sizeof **ctx);
|
||||
if (!*ctx)
|
||||
return seterr (Out_Of_Core);
|
||||
|
||||
r = ksba_reader_new ();
|
||||
if (!r)
|
||||
{
|
||||
xfree (*ctx); *ctx = NULL;
|
||||
return seterr (Out_Of_Core);
|
||||
}
|
||||
|
||||
(*ctx)->u.rparm.fp = fp;
|
||||
if (ctrl->is_pem)
|
||||
{
|
||||
(*ctx)->u.rparm.assume_pem = 1;
|
||||
(*ctx)->u.rparm.assume_base64 = 1;
|
||||
rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
|
||||
}
|
||||
else if (ctrl->is_base64)
|
||||
{
|
||||
(*ctx)->u.rparm.assume_base64 = 1;
|
||||
rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
|
||||
}
|
||||
else if (ctrl->autodetect_encoding)
|
||||
{
|
||||
(*ctx)->u.rparm.autodetect = 1;
|
||||
rc = ksba_reader_set_cb (r, base64_reader_cb, &(*ctx)->u.rparm);
|
||||
}
|
||||
else
|
||||
rc = ksba_reader_set_cb (r, simple_reader_cb, &(*ctx)->u.rparm);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
ksba_reader_release (r);
|
||||
xfree (*ctx); *ctx = NULL;
|
||||
return map_ksba_err (rc);
|
||||
}
|
||||
|
||||
*r_reader = r;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gpgsm_destroy_reader (Base64Context ctx)
|
||||
{
|
||||
xfree (ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create a writer for the given stream. Depending on the control
|
||||
information an output encoding is automagically choosen. The
|
||||
function returns a Base64Context object which must be passed to the
|
||||
gpgme_destroy_writer function. The created KsbaWriter object is
|
||||
also returned, but the caller must not call the ksba_reader_release
|
||||
function on. */
|
||||
int
|
||||
gpgsm_create_writer (Base64Context *ctx,
|
||||
CTRL ctrl, FILE *fp, KsbaWriter *r_writer)
|
||||
{
|
||||
int rc;
|
||||
KsbaWriter w;
|
||||
|
||||
*r_writer = NULL;
|
||||
*ctx = xtrycalloc (1, sizeof **ctx);
|
||||
if (!*ctx)
|
||||
return seterr (Out_Of_Core);
|
||||
|
||||
w = ksba_writer_new ();
|
||||
if (!w)
|
||||
{
|
||||
xfree (*ctx); *ctx = NULL;
|
||||
return seterr (Out_Of_Core);
|
||||
}
|
||||
|
||||
if (ctrl->create_pem || ctrl->create_base64)
|
||||
{
|
||||
(*ctx)->u.wparm.fp = fp;
|
||||
if (ctrl->create_pem)
|
||||
(*ctx)->u.wparm.pem_name = ctrl->pem_name? ctrl->pem_name
|
||||
: "CMS OBJECT";
|
||||
rc = ksba_writer_set_cb (w, base64_writer_cb, &(*ctx)->u.wparm);
|
||||
}
|
||||
else
|
||||
rc = ksba_writer_set_file (w, fp);
|
||||
|
||||
if (rc)
|
||||
{
|
||||
ksba_writer_release (w);
|
||||
xfree (*ctx); *ctx = NULL;
|
||||
return map_ksba_err (rc);
|
||||
}
|
||||
|
||||
*r_writer = w;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
gpgsm_finish_writer (Base64Context ctx)
|
||||
{
|
||||
struct writer_cb_parm_s *parm;
|
||||
|
||||
if (!ctx)
|
||||
return GNUPG_Invalid_Value;
|
||||
parm = &ctx->u.wparm;
|
||||
if (parm->did_finish)
|
||||
return 0; /* already done */
|
||||
parm->did_finish = 1;
|
||||
if (!parm->fp)
|
||||
return 0; /* callback was not used */
|
||||
return base64_finish_write (parm);
|
||||
}
|
||||
|
||||
void
|
||||
gpgsm_destroy_writer (Base64Context ctx)
|
||||
{
|
||||
xfree (ctx);
|
||||
}
|
751
sm/call-agent.c
751
sm/call-agent.c
@ -1,751 +0,0 @@
|
||||
/* call-agent.c - divert operations to the agent
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <gcrypt.h>
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "../assuan/assuan.h"
|
||||
#include "i18n.h"
|
||||
#include "keydb.h" /* fixme: Move this to import.c */
|
||||
|
||||
static ASSUAN_CONTEXT agent_ctx = NULL;
|
||||
static int force_pipe_server = 0;
|
||||
|
||||
struct cipher_parm_s {
|
||||
ASSUAN_CONTEXT ctx;
|
||||
const char *ciphertext;
|
||||
size_t ciphertextlen;
|
||||
};
|
||||
|
||||
struct genkey_parm_s {
|
||||
ASSUAN_CONTEXT ctx;
|
||||
const char *sexp;
|
||||
size_t sexplen;
|
||||
};
|
||||
|
||||
struct learn_parm_s {
|
||||
int error;
|
||||
ASSUAN_CONTEXT ctx;
|
||||
struct membuf *data;
|
||||
};
|
||||
|
||||
struct membuf {
|
||||
size_t len;
|
||||
size_t size;
|
||||
char *buf;
|
||||
int out_of_core;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* A simple implemnation 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Try to connect to the agent via socket or fork it off and work by
|
||||
pipes. Handle the server's initial greeting */
|
||||
static int
|
||||
start_agent (void)
|
||||
{
|
||||
int rc = 0;
|
||||
char *infostr, *p;
|
||||
ASSUAN_CONTEXT ctx;
|
||||
char *dft_display = NULL;
|
||||
char *dft_ttyname = NULL;
|
||||
char *dft_ttytype = NULL;
|
||||
char *old_lc = NULL;
|
||||
char *dft_lc = NULL;
|
||||
|
||||
if (agent_ctx)
|
||||
return 0; /* fixme: We need a context for each thread or serialize
|
||||
the access to the agent (which is suitable given that
|
||||
the agent is not MT */
|
||||
|
||||
infostr = force_pipe_server? NULL : getenv ("GPG_AGENT_INFO");
|
||||
if (!infostr)
|
||||
{
|
||||
const char *pgmname;
|
||||
const char *argv[3];
|
||||
int no_close_list[3];
|
||||
int i;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info (_("no running gpg-agent - starting one\n"));
|
||||
|
||||
if (fflush (NULL))
|
||||
{
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
return seterr (Write_Error);
|
||||
}
|
||||
|
||||
if (!opt.agent_program || !*opt.agent_program)
|
||||
opt.agent_program = GNUPG_DEFAULT_AGENT;
|
||||
if ( !(pgmname = strrchr (opt.agent_program, '/')))
|
||||
pgmname = opt.agent_program;
|
||||
else
|
||||
pgmname++;
|
||||
|
||||
argv[0] = pgmname;
|
||||
argv[1] = "--server";
|
||||
argv[2] = NULL;
|
||||
|
||||
i=0;
|
||||
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 agent and perform initial handshaking */
|
||||
rc = assuan_pipe_connect (&ctx, opt.agent_program, (char**)argv,
|
||||
no_close_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
int prot;
|
||||
int pid;
|
||||
|
||||
infostr = xstrdup (infostr);
|
||||
if ( !(p = strchr (infostr, ':')) || p == infostr)
|
||||
{
|
||||
log_error (_("malformed GPG_AGENT_INFO environment variable\n"));
|
||||
xfree (infostr);
|
||||
force_pipe_server = 1;
|
||||
return start_agent ();
|
||||
}
|
||||
*p++ = 0;
|
||||
pid = atoi (p);
|
||||
while (*p && *p != ':')
|
||||
p++;
|
||||
prot = *p? atoi (p+1) : 0;
|
||||
if (prot != 1)
|
||||
{
|
||||
log_error (_("gpg-agent protocol version %d is not supported\n"),
|
||||
prot);
|
||||
xfree (infostr);
|
||||
force_pipe_server = 1;
|
||||
return start_agent ();
|
||||
}
|
||||
|
||||
rc = assuan_socket_connect (&ctx, infostr, pid);
|
||||
xfree (infostr);
|
||||
if (rc == ASSUAN_Connect_Failed)
|
||||
{
|
||||
log_error (_("can't connect to the agent - trying fall back\n"));
|
||||
force_pipe_server = 1;
|
||||
return start_agent ();
|
||||
}
|
||||
}
|
||||
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't connect to the agent: %s\n", assuan_strerror (rc));
|
||||
return seterr (No_Agent);
|
||||
}
|
||||
agent_ctx = ctx;
|
||||
|
||||
if (DBG_ASSUAN)
|
||||
log_debug ("connection to agent established\n");
|
||||
|
||||
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
|
||||
dft_display = getenv ("DISPLAY");
|
||||
if (opt.display || dft_display)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION display=%s",
|
||||
opt.display ? opt.display : dft_display) < 0)
|
||||
return GNUPG_Out_Of_Core;
|
||||
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
free (optstr);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
if (!opt.ttyname && ttyname (1))
|
||||
dft_ttyname = ttyname (1);
|
||||
if (opt.ttyname || dft_ttyname)
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttyname=%s",
|
||||
opt.ttyname ? opt.ttyname : dft_ttyname) < 0)
|
||||
return GNUPG_Out_Of_Core;
|
||||
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
free (optstr);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
dft_ttytype = getenv ("TERM");
|
||||
if (opt.ttytype || (dft_ttyname && dft_ttytype))
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION ttytype=%s",
|
||||
opt.ttyname ? opt.ttytype : dft_ttytype) < 0)
|
||||
return GNUPG_Out_Of_Core;
|
||||
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
free (optstr);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
|
||||
old_lc = setlocale (LC_CTYPE, NULL);
|
||||
if (old_lc)
|
||||
{
|
||||
old_lc = strdup (old_lc);
|
||||
if (!old_lc)
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
dft_lc = setlocale (LC_CTYPE, "");
|
||||
#endif
|
||||
if (opt.lc_ctype || (dft_ttyname && dft_lc))
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-ctype=%s",
|
||||
opt.lc_ctype ? opt.lc_ctype : dft_lc) < 0)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
free (optstr);
|
||||
if (rc)
|
||||
rc = map_assuan_err (rc);
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_SETLOCALE) && defined(LC_CTYPE)
|
||||
if (old_lc)
|
||||
{
|
||||
setlocale (LC_CTYPE, old_lc);
|
||||
free (old_lc);
|
||||
}
|
||||
#endif
|
||||
if (rc)
|
||||
return rc;
|
||||
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
|
||||
old_lc = setlocale (LC_MESSAGES, NULL);
|
||||
if (old_lc)
|
||||
{
|
||||
old_lc = strdup (old_lc);
|
||||
if (!old_lc)
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
dft_lc = setlocale (LC_MESSAGES, "");
|
||||
#endif
|
||||
if (opt.lc_messages || (dft_ttyname && dft_lc))
|
||||
{
|
||||
char *optstr;
|
||||
if (asprintf (&optstr, "OPTION lc-messages=%s",
|
||||
opt.lc_messages ? opt.lc_messages : dft_lc) < 0)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
rc = assuan_transact (agent_ctx, optstr, NULL, NULL, NULL, NULL, NULL,
|
||||
NULL);
|
||||
free (optstr);
|
||||
if (rc)
|
||||
rc = map_assuan_err (rc);
|
||||
}
|
||||
}
|
||||
#if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES)
|
||||
if (old_lc)
|
||||
{
|
||||
setlocale (LC_MESSAGES, old_lc);
|
||||
free (old_lc);
|
||||
}
|
||||
#endif
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Call the agent to do a sign operation using the key identified by
|
||||
the hex string KEYGRIP. */
|
||||
int
|
||||
gpgsm_agent_pksign (const char *keygrip,
|
||||
unsigned char *digest, size_t digestlen, int digestalgo,
|
||||
char **r_buf, size_t *r_buflen )
|
||||
{
|
||||
int rc, i;
|
||||
char *p, line[ASSUAN_LINELENGTH];
|
||||
struct membuf data;
|
||||
size_t len;
|
||||
|
||||
*r_buf = NULL;
|
||||
rc = start_agent ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (digestlen*2 + 50 > DIM(line))
|
||||
return seterr (General_Error);
|
||||
|
||||
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
|
||||
snprintf (line, DIM(line)-1, "SIGKEY %s", keygrip);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
|
||||
sprintf (line, "SETHASH %d ", digestalgo);
|
||||
p = line + strlen (line);
|
||||
for (i=0; i < digestlen ; i++, p += 2 )
|
||||
sprintf (p, "%02X", digest[i]);
|
||||
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
|
||||
init_membuf (&data, 1024);
|
||||
rc = assuan_transact (agent_ctx, "PKSIGN",
|
||||
membuf_data_cb, &data, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
{
|
||||
xfree (get_membuf (&data, &len));
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
*r_buf = get_membuf (&data, r_buflen);
|
||||
|
||||
if (!gcry_sexp_canon_len (*r_buf, *r_buflen, NULL, NULL))
|
||||
{
|
||||
xfree (*r_buf); *r_buf = NULL;
|
||||
return GNUPG_Invalid_Value;
|
||||
}
|
||||
|
||||
return *r_buf? 0 : GNUPG_Out_Of_Core;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Handle a CIPHERTEXT inquiry. Note, we only send the data,
|
||||
assuan_transact talkes care of flushing and writing the end */
|
||||
static AssuanError
|
||||
inq_ciphertext_cb (void *opaque, const char *keyword)
|
||||
{
|
||||
struct cipher_parm_s *parm = opaque;
|
||||
AssuanError rc;
|
||||
|
||||
assuan_begin_confidential (parm->ctx);
|
||||
rc = assuan_send_data (parm->ctx, parm->ciphertext, parm->ciphertextlen);
|
||||
assuan_end_confidential (parm->ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Call the agent to do a decrypt operation using the key identified by
|
||||
the hex string KEYGRIP. */
|
||||
int
|
||||
gpgsm_agent_pkdecrypt (const char *keygrip,
|
||||
KsbaConstSexp ciphertext,
|
||||
char **r_buf, size_t *r_buflen )
|
||||
{
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct membuf data;
|
||||
struct cipher_parm_s cipher_parm;
|
||||
size_t n, len;
|
||||
char *buf, *endp;
|
||||
size_t ciphertextlen;
|
||||
|
||||
if (!keygrip || strlen(keygrip) != 40 || !ciphertext || !r_buf || !r_buflen)
|
||||
return GNUPG_Invalid_Value;
|
||||
*r_buf = NULL;
|
||||
|
||||
ciphertextlen = gcry_sexp_canon_len (ciphertext, 0, NULL, NULL);
|
||||
if (!ciphertextlen)
|
||||
return GNUPG_Invalid_Value;
|
||||
|
||||
rc = start_agent ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
|
||||
assert ( DIM(line) >= 50 );
|
||||
snprintf (line, DIM(line)-1, "SETKEY %s", keygrip);
|
||||
line[DIM(line)-1] = 0;
|
||||
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
|
||||
init_membuf (&data, 1024);
|
||||
cipher_parm.ctx = agent_ctx;
|
||||
cipher_parm.ciphertext = ciphertext;
|
||||
cipher_parm.ciphertextlen = ciphertextlen;
|
||||
rc = assuan_transact (agent_ctx, "PKDECRYPT",
|
||||
membuf_data_cb, &data,
|
||||
inq_ciphertext_cb, &cipher_parm, NULL, NULL);
|
||||
if (rc)
|
||||
{
|
||||
xfree (get_membuf (&data, &len));
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
|
||||
put_membuf (&data, "", 1); /* make sure it is 0 terminated */
|
||||
buf = get_membuf (&data, &len);
|
||||
if (!buf)
|
||||
return seterr (Out_Of_Core);
|
||||
/* FIXME: We would better a return a full S-exp and not just a part */
|
||||
assert (len);
|
||||
len--; /* remove the terminating 0 */
|
||||
n = strtoul (buf, &endp, 10);
|
||||
if (!n || *endp != ':')
|
||||
return seterr (Invalid_Sexp);
|
||||
endp++;
|
||||
if (endp-buf+n > len)
|
||||
return seterr (Invalid_Sexp); /* oops len does not match internal len*/
|
||||
memmove (buf, endp, n);
|
||||
*r_buflen = n;
|
||||
*r_buf = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Handle a KEYPARMS inquiry. Note, we only send the data,
|
||||
assuan_transact takes care of flushing and writing the end */
|
||||
static AssuanError
|
||||
inq_genkey_parms (void *opaque, const char *keyword)
|
||||
{
|
||||
struct genkey_parm_s *parm = opaque;
|
||||
AssuanError rc;
|
||||
|
||||
rc = assuan_send_data (parm->ctx, parm->sexp, parm->sexplen);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Call the agent to generate a newkey */
|
||||
int
|
||||
gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey)
|
||||
{
|
||||
int rc;
|
||||
struct genkey_parm_s gk_parm;
|
||||
struct membuf data;
|
||||
size_t len;
|
||||
char *buf;
|
||||
|
||||
*r_pubkey = NULL;
|
||||
rc = start_agent ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = assuan_transact (agent_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
|
||||
init_membuf (&data, 1024);
|
||||
gk_parm.ctx = agent_ctx;
|
||||
gk_parm.sexp = keyparms;
|
||||
gk_parm.sexplen = gcry_sexp_canon_len (keyparms, 0, NULL, NULL);
|
||||
if (!gk_parm.sexplen)
|
||||
return GNUPG_Invalid_Value;
|
||||
rc = assuan_transact (agent_ctx, "GENKEY",
|
||||
membuf_data_cb, &data,
|
||||
inq_genkey_parms, &gk_parm, NULL, NULL);
|
||||
if (rc)
|
||||
{
|
||||
xfree (get_membuf (&data, &len));
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
buf = get_membuf (&data, &len);
|
||||
if (!buf)
|
||||
return GNUPG_Out_Of_Core;
|
||||
if (!gcry_sexp_canon_len (buf, len, NULL, NULL))
|
||||
{
|
||||
xfree (buf);
|
||||
return GNUPG_Invalid_Sexp;
|
||||
}
|
||||
*r_pubkey = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Ask the agent whether the certificate is in the list of trusted
|
||||
keys */
|
||||
int
|
||||
gpgsm_agent_istrusted (KsbaCert cert)
|
||||
{
|
||||
int rc;
|
||||
char *fpr;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
rc = start_agent ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
|
||||
if (!fpr)
|
||||
{
|
||||
log_error ("error getting the fingerprint\n");
|
||||
return seterr (General_Error);
|
||||
}
|
||||
|
||||
snprintf (line, DIM(line)-1, "ISTRUSTED %s", fpr);
|
||||
line[DIM(line)-1] = 0;
|
||||
xfree (fpr);
|
||||
|
||||
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
|
||||
/* Ask the agent to mark CERT as a trusted Root-CA one */
|
||||
int
|
||||
gpgsm_agent_marktrusted (KsbaCert cert)
|
||||
{
|
||||
int rc;
|
||||
char *fpr, *dn;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
rc = start_agent ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
|
||||
if (!fpr)
|
||||
{
|
||||
log_error ("error getting the fingerprint\n");
|
||||
return seterr (General_Error);
|
||||
}
|
||||
|
||||
dn = ksba_cert_get_issuer (cert, 0);
|
||||
if (!dn)
|
||||
{
|
||||
xfree (fpr);
|
||||
return seterr (General_Error);
|
||||
}
|
||||
snprintf (line, DIM(line)-1, "MARKTRUSTED %s S %s", fpr, dn);
|
||||
line[DIM(line)-1] = 0;
|
||||
ksba_free (dn);
|
||||
xfree (fpr);
|
||||
|
||||
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Ask the agent whether the a corresponding secret key is available
|
||||
for the given keygrip */
|
||||
int
|
||||
gpgsm_agent_havekey (const char *hexkeygrip)
|
||||
{
|
||||
int rc;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
|
||||
rc = start_agent ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!hexkeygrip || strlen (hexkeygrip) != 40)
|
||||
return GNUPG_Invalid_Value;
|
||||
|
||||
snprintf (line, DIM(line)-1, "HAVEKEY %s", hexkeygrip);
|
||||
line[DIM(line)-1] = 0;
|
||||
|
||||
rc = assuan_transact (agent_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
|
||||
|
||||
static AssuanError
|
||||
learn_cb (void *opaque, const void *buffer, size_t length)
|
||||
{
|
||||
struct learn_parm_s *parm = opaque;
|
||||
size_t len;
|
||||
char *buf;
|
||||
KsbaCert cert;
|
||||
int rc;
|
||||
|
||||
if (parm->error)
|
||||
return 0;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
put_membuf (parm->data, buffer, length);
|
||||
return 0;
|
||||
}
|
||||
/* END encountered - process what we have */
|
||||
buf = get_membuf (parm->data, &len);
|
||||
if (!buf)
|
||||
{
|
||||
parm->error = GNUPG_Out_Of_Core;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* FIXME: this should go into import.c */
|
||||
cert = ksba_cert_new ();
|
||||
if (!cert)
|
||||
{
|
||||
parm->error = GNUPG_Out_Of_Core;
|
||||
return 0;
|
||||
}
|
||||
rc = ksba_cert_init_from_mem (cert, buf, len);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to parse a certificate: %s\n", ksba_strerror (rc));
|
||||
ksba_cert_release (cert);
|
||||
parm->error = map_ksba_err (rc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
rc = gpgsm_basic_cert_check (cert);
|
||||
if (rc == GNUPG_Missing_Certificate)
|
||||
{ /* For later use we store it in the ephemeral database. */
|
||||
log_info ("issuer certificate missing - storing as ephemeral\n");
|
||||
keydb_store_cert (cert, 1, NULL);
|
||||
}
|
||||
else if (rc)
|
||||
log_error ("invalid certificate: %s\n", gnupg_strerror (rc));
|
||||
else
|
||||
{
|
||||
int existed;
|
||||
|
||||
if (!keydb_store_cert (cert, 0, &existed))
|
||||
{
|
||||
if (opt.verbose > 1 && existed)
|
||||
log_info ("certificate already in DB\n");
|
||||
else if (opt.verbose && !existed)
|
||||
log_info ("certificate imported\n");
|
||||
}
|
||||
}
|
||||
|
||||
ksba_cert_release (cert);
|
||||
init_membuf (parm->data, 4096);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Call the agent to learn about a smartcard */
|
||||
int
|
||||
gpgsm_agent_learn ()
|
||||
{
|
||||
int rc;
|
||||
struct learn_parm_s learn_parm;
|
||||
struct membuf data;
|
||||
size_t len;
|
||||
|
||||
rc = start_agent ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
init_membuf (&data, 4096);
|
||||
learn_parm.error = 0;
|
||||
learn_parm.ctx = agent_ctx;
|
||||
learn_parm.data = &data;
|
||||
rc = assuan_transact (agent_ctx, "LEARN --send",
|
||||
learn_cb, &learn_parm,
|
||||
NULL, NULL, NULL, NULL);
|
||||
xfree (get_membuf (&data, &len));
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return learn_parm.error;
|
||||
}
|
||||
|
@ -1,495 +0,0 @@
|
||||
/* call-dirmngr.c - communication with the dromngr
|
||||
* 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "../assuan/assuan.h"
|
||||
#include "i18n.h"
|
||||
|
||||
struct membuf {
|
||||
size_t len;
|
||||
size_t size;
|
||||
char *buf;
|
||||
int out_of_core;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static ASSUAN_CONTEXT dirmngr_ctx = NULL;
|
||||
static int force_pipe_server = 0;
|
||||
|
||||
struct inq_certificate_parm_s {
|
||||
ASSUAN_CONTEXT ctx;
|
||||
KsbaCert cert;
|
||||
};
|
||||
|
||||
struct lookup_parm_s {
|
||||
CTRL ctrl;
|
||||
ASSUAN_CONTEXT ctx;
|
||||
void (*cb)(void *, KsbaCert);
|
||||
void *cb_value;
|
||||
struct membuf data;
|
||||
int error;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Try to connect to the agent via socket or fork it off and work by
|
||||
pipes. Handle the server's initial greeting */
|
||||
static int
|
||||
start_dirmngr (void)
|
||||
{
|
||||
int rc;
|
||||
char *infostr, *p;
|
||||
ASSUAN_CONTEXT ctx;
|
||||
|
||||
if (dirmngr_ctx)
|
||||
return 0; /* fixme: We need a context for each thread or serialize
|
||||
the access to the dirmngr */
|
||||
|
||||
infostr = force_pipe_server? NULL : getenv ("DIRMNGR_INFO");
|
||||
if (!infostr)
|
||||
{
|
||||
const char *pgmname;
|
||||
const char *argv[3];
|
||||
int no_close_list[3];
|
||||
int i;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info (_("no running dirmngr - starting one\n"));
|
||||
|
||||
if (fflush (NULL))
|
||||
{
|
||||
log_error ("error flushing pending output: %s\n", strerror (errno));
|
||||
return seterr (Write_Error);
|
||||
}
|
||||
|
||||
if (!opt.dirmngr_program || !*opt.dirmngr_program)
|
||||
opt.dirmngr_program = GNUPG_DEFAULT_DIRMNGR;
|
||||
if ( !(pgmname = strrchr (opt.dirmngr_program, '/')))
|
||||
pgmname = opt.dirmngr_program;
|
||||
else
|
||||
pgmname++;
|
||||
|
||||
argv[0] = pgmname;
|
||||
argv[1] = "--server";
|
||||
argv[2] = NULL;
|
||||
|
||||
i=0;
|
||||
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 agent and perform initial handshaking */
|
||||
rc = assuan_pipe_connect (&ctx, opt.dirmngr_program, (char**)argv,
|
||||
no_close_list);
|
||||
}
|
||||
else
|
||||
{
|
||||
int prot;
|
||||
int pid;
|
||||
|
||||
infostr = xstrdup (infostr);
|
||||
if ( !(p = strchr (infostr, ':')) || p == infostr)
|
||||
{
|
||||
log_error (_("malformed DIRMNGR_INFO environment variable\n"));
|
||||
xfree (infostr);
|
||||
force_pipe_server = 1;
|
||||
return start_dirmngr ();
|
||||
}
|
||||
*p++ = 0;
|
||||
pid = atoi (p);
|
||||
while (*p && *p != ':')
|
||||
p++;
|
||||
prot = *p? atoi (p+1) : 0;
|
||||
if (prot != 1)
|
||||
{
|
||||
log_error (_("dirmngr protocol version %d is not supported\n"),
|
||||
prot);
|
||||
xfree (infostr);
|
||||
force_pipe_server = 1;
|
||||
return start_dirmngr ();
|
||||
}
|
||||
|
||||
rc = assuan_socket_connect (&ctx, infostr, pid);
|
||||
xfree (infostr);
|
||||
if (rc == ASSUAN_Connect_Failed)
|
||||
{
|
||||
log_error (_("can't connect to the dirmngr - trying fall back\n"));
|
||||
force_pipe_server = 1;
|
||||
return start_dirmngr ();
|
||||
}
|
||||
}
|
||||
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't connect to the dirmngr: %s\n", assuan_strerror (rc));
|
||||
return seterr (No_Dirmngr);
|
||||
}
|
||||
dirmngr_ctx = ctx;
|
||||
|
||||
if (DBG_ASSUAN)
|
||||
log_debug ("connection to dirmngr established\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Handle a SENDCERT inquiry. */
|
||||
static AssuanError
|
||||
inq_certificate (void *opaque, const char *line)
|
||||
{
|
||||
struct inq_certificate_parm_s *parm = opaque;
|
||||
AssuanError rc;
|
||||
const unsigned char *der;
|
||||
size_t derlen;
|
||||
|
||||
if (!(!strncmp (line, "SENDCERT", 8) && (line[8] == ' ' || !line[8])))
|
||||
{
|
||||
log_error ("unsupported inquiry `%s'\n", line);
|
||||
return ASSUAN_Inquire_Unknown;
|
||||
}
|
||||
line += 8;
|
||||
|
||||
if (!*line)
|
||||
{ /* send the current certificate */
|
||||
der = ksba_cert_get_image (parm->cert, &derlen);
|
||||
if (!der)
|
||||
rc = ASSUAN_Inquire_Error;
|
||||
else
|
||||
rc = assuan_send_data (parm->ctx, der, derlen);
|
||||
}
|
||||
else
|
||||
{ /* send the given certificate */
|
||||
int err;
|
||||
KsbaCert cert;
|
||||
|
||||
err = gpgsm_find_cert (line, &cert);
|
||||
if (err)
|
||||
{
|
||||
log_error ("certificate not found: %s\n", gnupg_strerror (err));
|
||||
rc = ASSUAN_Inquire_Error;
|
||||
}
|
||||
else
|
||||
{
|
||||
der = ksba_cert_get_image (cert, &derlen);
|
||||
if (!der)
|
||||
rc = ASSUAN_Inquire_Error;
|
||||
else
|
||||
rc = assuan_send_data (parm->ctx, der, derlen);
|
||||
ksba_cert_release (cert);
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Call the directory manager to check whether the certificate is valid
|
||||
Returns 0 for valid or usually one of the errors:
|
||||
|
||||
GNUPG_Certificate_Revoked
|
||||
GNUPG_No_CRL_Known
|
||||
GNUPG_CRL_Too_Old
|
||||
*/
|
||||
int
|
||||
gpgsm_dirmngr_isvalid (KsbaCert cert)
|
||||
{
|
||||
int rc;
|
||||
char *certid;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct inq_certificate_parm_s parm;
|
||||
|
||||
rc = start_dirmngr ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
certid = gpgsm_get_certid (cert);
|
||||
if (!certid)
|
||||
{
|
||||
log_error ("error getting the certificate ID\n");
|
||||
return seterr (General_Error);
|
||||
}
|
||||
|
||||
if (opt.verbose > 1)
|
||||
{
|
||||
char *fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
|
||||
log_info ("asking dirmngr about %s\n", fpr);
|
||||
xfree (fpr);
|
||||
}
|
||||
|
||||
parm.ctx = dirmngr_ctx;
|
||||
parm.cert = cert;
|
||||
|
||||
snprintf (line, DIM(line)-1, "ISVALID %s", certid);
|
||||
line[DIM(line)-1] = 0;
|
||||
xfree (certid);
|
||||
|
||||
rc = assuan_transact (dirmngr_ctx, line, NULL, NULL,
|
||||
inq_certificate, &parm, NULL, NULL);
|
||||
if (opt.verbose > 1)
|
||||
log_info ("response of dirmngr: %s\n", rc? assuan_strerror (rc): "okay");
|
||||
return map_assuan_err (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Lookup helpers*/
|
||||
static AssuanError
|
||||
lookup_cb (void *opaque, const void *buffer, size_t length)
|
||||
{
|
||||
struct lookup_parm_s *parm = opaque;
|
||||
size_t len;
|
||||
char *buf;
|
||||
KsbaCert cert;
|
||||
int rc;
|
||||
|
||||
if (parm->error)
|
||||
return 0;
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
put_membuf (&parm->data, buffer, length);
|
||||
return 0;
|
||||
}
|
||||
/* END encountered - process what we have */
|
||||
buf = get_membuf (&parm->data, &len);
|
||||
if (!buf)
|
||||
{
|
||||
parm->error = GNUPG_Out_Of_Core;
|
||||
return 0;
|
||||
}
|
||||
|
||||
cert = ksba_cert_new ();
|
||||
if (!cert)
|
||||
{
|
||||
parm->error = GNUPG_Out_Of_Core;
|
||||
return 0;
|
||||
}
|
||||
rc = ksba_cert_init_from_mem (cert, buf, len);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to parse a certificate: %s\n", ksba_strerror (rc));
|
||||
}
|
||||
else
|
||||
{
|
||||
parm->cb (parm->cb_value, cert);
|
||||
}
|
||||
|
||||
ksba_cert_release (cert);
|
||||
init_membuf (&parm->data, 4096);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return a properly escaped pattern from NAMES. The only error
|
||||
return is NULL to indicate a malloc failure. */
|
||||
static char *
|
||||
pattern_from_strlist (STRLIST names)
|
||||
{
|
||||
STRLIST sl;
|
||||
int n;
|
||||
const char *s;
|
||||
char *pattern, *p;
|
||||
|
||||
for (n=0, sl=names; sl; sl = sl->next)
|
||||
{
|
||||
for (s=sl->d; *s; s++, n++)
|
||||
{
|
||||
if (*s == '%' || *s == ' ' || *s == '+')
|
||||
n += 2;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
p = pattern = xtrymalloc (n+1);
|
||||
if (!pattern)
|
||||
return NULL;
|
||||
|
||||
for (n=0, sl=names; sl; sl = sl->next)
|
||||
{
|
||||
for (s=sl->d; *s; s++)
|
||||
{
|
||||
switch (*s)
|
||||
{
|
||||
case '%':
|
||||
*p++ = '%';
|
||||
*p++ = '2';
|
||||
*p++ = '5';
|
||||
break;
|
||||
case ' ':
|
||||
*p++ = '%';
|
||||
*p++ = '2';
|
||||
*p++ = '0';
|
||||
break;
|
||||
case '+':
|
||||
*p++ = '%';
|
||||
*p++ = '2';
|
||||
*p++ = 'B';
|
||||
break;
|
||||
default:
|
||||
*p++ = *s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p++ = ' ';
|
||||
}
|
||||
if (p == pattern)
|
||||
*pattern = 0; /* is empty */
|
||||
else
|
||||
p[-1] = '\0'; /* remove trailing blank */
|
||||
|
||||
return pattern;
|
||||
}
|
||||
|
||||
static AssuanError
|
||||
lookup_status_cb (void *opaque, const char *line)
|
||||
{
|
||||
struct lookup_parm_s *parm = opaque;
|
||||
|
||||
if (!strncmp (line, "TRUNCATED", 9) && (line[9]==' ' || !line[9]))
|
||||
{
|
||||
if (parm->ctrl)
|
||||
{
|
||||
for (line +=9; *line == ' '; line++)
|
||||
;
|
||||
gpgsm_status (parm->ctrl, STATUS_TRUNCATED, line);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Run the Directroy Managers lookup command using the apptern
|
||||
compiled from the strings given in NAMES. The caller must provide
|
||||
the callback CB which will be passed cert by cert. Note that CTRL
|
||||
is optional. */
|
||||
int
|
||||
gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
|
||||
void (*cb)(void*, KsbaCert), void *cb_value)
|
||||
{
|
||||
int rc;
|
||||
char *pattern;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct lookup_parm_s parm;
|
||||
size_t len;
|
||||
|
||||
rc = start_dirmngr ();
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
pattern = pattern_from_strlist (names);
|
||||
if (!pattern)
|
||||
return GNUPG_Out_Of_Core;
|
||||
snprintf (line, DIM(line)-1, "LOOKUP %s", pattern);
|
||||
line[DIM(line)-1] = 0;
|
||||
xfree (pattern);
|
||||
|
||||
parm.ctrl = ctrl;
|
||||
parm.ctx = dirmngr_ctx;
|
||||
parm.cb = cb;
|
||||
parm.cb_value = cb_value;
|
||||
parm.error = 0;
|
||||
init_membuf (&parm.data, 4096);
|
||||
|
||||
rc = assuan_transact (dirmngr_ctx, line, lookup_cb, &parm,
|
||||
NULL, NULL, lookup_status_cb, &parm);
|
||||
xfree (get_membuf (&parm.data, &len));
|
||||
if (rc)
|
||||
return map_assuan_err (rc);
|
||||
return parm.error;
|
||||
}
|
||||
|
||||
|
773
sm/certchain.c
773
sm/certchain.c
@ -1,773 +0,0 @@
|
||||
/* certchain.c - certificate chain validation
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
static int
|
||||
unknown_criticals (KsbaCert cert)
|
||||
{
|
||||
static const char *known[] = {
|
||||
"2.5.29.15", /* keyUsage */
|
||||
"2.5.29.19", /* basic Constraints */
|
||||
"2.5.29.32", /* certificatePolicies */
|
||||
NULL
|
||||
};
|
||||
int rc = 0, i, idx, crit;
|
||||
const char *oid;
|
||||
KsbaError err;
|
||||
|
||||
for (idx=0; !(err=ksba_cert_get_extension (cert, idx,
|
||||
&oid, &crit, NULL, NULL));idx++)
|
||||
{
|
||||
if (!crit)
|
||||
continue;
|
||||
for (i=0; known[i] && strcmp (known[i],oid); i++)
|
||||
;
|
||||
if (!known[i])
|
||||
{
|
||||
log_error (_("critical certificate extension %s is not supported\n"),
|
||||
oid);
|
||||
rc = GNUPG_Unsupported_Certificate;
|
||||
}
|
||||
}
|
||||
if (err && err != -1)
|
||||
rc = map_ksba_err (err);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
allowed_ca (KsbaCert cert, int *chainlen)
|
||||
{
|
||||
KsbaError err;
|
||||
int flag;
|
||||
|
||||
err = ksba_cert_is_ca (cert, &flag, chainlen);
|
||||
if (err)
|
||||
return map_ksba_err (err);
|
||||
if (!flag)
|
||||
{
|
||||
log_error (_("issuer certificate is not marked as a CA\n"));
|
||||
return GNUPG_Bad_CA_Certificate;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_cert_policy (KsbaCert cert)
|
||||
{
|
||||
KsbaError err;
|
||||
char *policies;
|
||||
FILE *fp;
|
||||
int any_critical;
|
||||
|
||||
err = ksba_cert_get_cert_policies (cert, &policies);
|
||||
if (err == KSBA_No_Data)
|
||||
return 0; /* no policy given */
|
||||
if (err)
|
||||
return map_ksba_err (err);
|
||||
|
||||
/* STRING is a line delimited list of certifiate policies as stored
|
||||
in the certificate. The line itself is colon delimited where the
|
||||
first field is the OID of the policy and the second field either
|
||||
N or C for normal or critical extension */
|
||||
|
||||
if (opt.verbose > 1)
|
||||
log_info ("certificate's policy list: %s\n", policies);
|
||||
|
||||
/* The check is very minimal but won't give false positives */
|
||||
any_critical = !!strstr (policies, ":C");
|
||||
|
||||
if (!opt.policy_file)
|
||||
{
|
||||
xfree (policies);
|
||||
if (any_critical)
|
||||
{
|
||||
log_error ("critical marked policy without configured policies\n");
|
||||
return GNUPG_No_Policy_Match;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
fp = fopen (opt.policy_file, "r");
|
||||
if (!fp)
|
||||
{
|
||||
log_error ("failed to open `%s': %s\n",
|
||||
opt.policy_file, strerror (errno));
|
||||
xfree (policies);
|
||||
return GNUPG_No_Policy_Match;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int c;
|
||||
char *p, line[256];
|
||||
char *haystack, *allowed;
|
||||
|
||||
/* read line */
|
||||
do
|
||||
{
|
||||
if (!fgets (line, DIM(line)-1, fp) )
|
||||
{
|
||||
xfree (policies);
|
||||
if (feof (fp))
|
||||
{
|
||||
fclose (fp);
|
||||
/* with no critical policies this is only a warning */
|
||||
if (!any_critical)
|
||||
{
|
||||
log_info (_("note: certificate policy not allowed\n"));
|
||||
return 0;
|
||||
}
|
||||
log_error (_("certificate policy not allowed\n"));
|
||||
return GNUPG_No_Policy_Match;
|
||||
}
|
||||
fclose (fp);
|
||||
return GNUPG_Read_Error;
|
||||
}
|
||||
|
||||
if (!*line || line[strlen(line)-1] != '\n')
|
||||
{
|
||||
/* eat until end of line */
|
||||
while ( (c=getc (fp)) != EOF && c != '\n')
|
||||
;
|
||||
fclose (fp);
|
||||
xfree (policies);
|
||||
return *line? GNUPG_Line_Too_Long: GNUPG_Incomplete_Line;
|
||||
}
|
||||
|
||||
/* Allow for empty lines and spaces */
|
||||
for (p=line; spacep (p); p++)
|
||||
;
|
||||
}
|
||||
while (!*p || *p == '\n' || *p == '#');
|
||||
|
||||
/* parse line */
|
||||
for (allowed=line; spacep (allowed); allowed++)
|
||||
;
|
||||
p = strpbrk (allowed, " :\n");
|
||||
if (!*p || p == allowed)
|
||||
{
|
||||
fclose (fp);
|
||||
xfree (policies);
|
||||
return GNUPG_Configuration_Error;
|
||||
}
|
||||
*p = 0; /* strip the rest of the line */
|
||||
/* See whether we find ALLOWED (which is an OID) in POLICIES */
|
||||
for (haystack=policies; (p=strstr (haystack, allowed)); haystack = p+1)
|
||||
{
|
||||
if ( !(p == policies || p[-1] == '\n') )
|
||||
continue; /* does not match the begin of a line */
|
||||
if (p[strlen (allowed)] != ':')
|
||||
continue; /* the length does not match */
|
||||
/* Yep - it does match so return okay */
|
||||
fclose (fp);
|
||||
xfree (policies);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
find_up_store_certs_cb (void *cb_value, KsbaCert cert)
|
||||
{
|
||||
if (keydb_store_cert (cert, 1, NULL))
|
||||
log_error ("error storing issuer certificate as ephemeral\n");
|
||||
++*(int*)cb_value;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
find_up (KEYDB_HANDLE kh, KsbaCert cert, const char *issuer)
|
||||
{
|
||||
KsbaName authid;
|
||||
KsbaSexp authidno;
|
||||
int rc = -1;
|
||||
|
||||
if (!ksba_cert_get_auth_key_id (cert, NULL, &authid, &authidno))
|
||||
{
|
||||
const char *s = ksba_name_enum (authid, 0);
|
||||
if (s && *authidno)
|
||||
{
|
||||
rc = keydb_search_issuer_sn (kh, s, authidno);
|
||||
if (rc)
|
||||
keydb_search_reset (kh);
|
||||
if (rc == -1)
|
||||
{ /* And try the ephemeral DB. */
|
||||
int old = keydb_set_ephemeral (kh, 1);
|
||||
if (!old)
|
||||
{
|
||||
rc = keydb_search_issuer_sn (kh, s, authidno);
|
||||
if (rc)
|
||||
keydb_search_reset (kh);
|
||||
}
|
||||
keydb_set_ephemeral (kh, old);
|
||||
}
|
||||
}
|
||||
ksba_name_release (authid);
|
||||
xfree (authidno);
|
||||
/* Fixme: don't know how to do dirmngr lookup with serial+issuer. */
|
||||
}
|
||||
|
||||
if (rc) /* not found via authorithyKeyIdentifier, try regular issuer name */
|
||||
rc = keydb_search_subject (kh, issuer);
|
||||
if (rc == -1)
|
||||
{
|
||||
/* Not found, lets see whether we have one in the ephemeral key DB. */
|
||||
int old = keydb_set_ephemeral (kh, 1);
|
||||
if (!old)
|
||||
{
|
||||
keydb_search_reset (kh);
|
||||
rc = keydb_search_subject (kh, issuer);
|
||||
}
|
||||
keydb_set_ephemeral (kh, old);
|
||||
}
|
||||
|
||||
if (rc == -1 && opt.auto_issuer_key_retrieve)
|
||||
{
|
||||
STRLIST names = NULL;
|
||||
int count = 0;
|
||||
char *pattern;
|
||||
const char *s;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info (_("looking up issuer at external location\n"));
|
||||
/* dirmngr is confused about unknown attributes so has a quick
|
||||
and ugly hack we locate the CN and use this and the
|
||||
following. Fixme: we should have far ebtter parsing in the
|
||||
dirmngr. */
|
||||
s = strstr (issuer, "CN=");
|
||||
if (!s || s == issuer || s[-1] != ',')
|
||||
s = issuer;
|
||||
|
||||
pattern = xtrymalloc (strlen (s)+2);
|
||||
if (!pattern)
|
||||
return GNUPG_Out_Of_Core;
|
||||
strcpy (stpcpy (pattern, "/"), s);
|
||||
add_to_strlist (&names, pattern);
|
||||
xfree (pattern);
|
||||
rc = gpgsm_dirmngr_lookup (NULL, names, find_up_store_certs_cb, &count);
|
||||
free_strlist (names);
|
||||
if (opt.verbose)
|
||||
log_info (_("number of issuers matching: %d\n"), count);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("external key lookup failed: %s\n", gnupg_strerror (rc));
|
||||
rc = -1;
|
||||
}
|
||||
else if (!count)
|
||||
rc = -1;
|
||||
else
|
||||
{
|
||||
int old;
|
||||
/* The issuers are currently stored in the ephemeral key
|
||||
DB, so we temporary switch to ephemeral mode. */
|
||||
old = keydb_set_ephemeral (kh, 1);
|
||||
keydb_search_reset (kh);
|
||||
rc = keydb_search_subject (kh, issuer);
|
||||
keydb_set_ephemeral (kh, old);
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Return the next certificate up in the chain starting at START.
|
||||
Returns -1 when there are no more certificates. */
|
||||
int
|
||||
gpgsm_walk_cert_chain (KsbaCert start, KsbaCert *r_next)
|
||||
{
|
||||
int rc = 0;
|
||||
char *issuer = NULL;
|
||||
char *subject = NULL;
|
||||
KEYDB_HANDLE kh = keydb_new (0);
|
||||
|
||||
*r_next = NULL;
|
||||
if (!kh)
|
||||
{
|
||||
log_error (_("failed to allocated keyDB handle\n"));
|
||||
rc = GNUPG_General_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
issuer = ksba_cert_get_issuer (start, 0);
|
||||
subject = ksba_cert_get_subject (start, 0);
|
||||
if (!issuer)
|
||||
{
|
||||
log_error ("no issuer found in certificate\n");
|
||||
rc = GNUPG_Bad_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
if (!subject)
|
||||
{
|
||||
log_error ("no subject found in certificate\n");
|
||||
rc = GNUPG_Bad_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!strcmp (issuer, subject))
|
||||
{
|
||||
rc = -1; /* we are at the root */
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = find_up (kh, start, issuer);
|
||||
if (rc)
|
||||
{
|
||||
/* it is quite common not to have a certificate, so better don't
|
||||
print an error here */
|
||||
if (rc != -1 && opt.verbose > 1)
|
||||
log_error ("failed to find issuer's certificate: rc=%d\n", rc);
|
||||
rc = GNUPG_Missing_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = keydb_get_cert (kh, r_next);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to get cert: rc=%d\n", rc);
|
||||
rc = GNUPG_General_Error;
|
||||
}
|
||||
|
||||
leave:
|
||||
xfree (issuer);
|
||||
xfree (subject);
|
||||
keydb_release (kh);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Check whether the CERT is a root certificate. Returns True if this
|
||||
is the case. */
|
||||
int
|
||||
gpgsm_is_root_cert (KsbaCert cert)
|
||||
{
|
||||
char *issuer;
|
||||
char *subject;
|
||||
int yes;
|
||||
|
||||
issuer = ksba_cert_get_issuer (cert, 0);
|
||||
subject = ksba_cert_get_subject (cert, 0);
|
||||
yes = (issuer && subject && !strcmp (issuer, subject));
|
||||
xfree (issuer);
|
||||
xfree (subject);
|
||||
return yes;
|
||||
}
|
||||
|
||||
|
||||
/* Validate a chain and optionally return the nearest expiration time
|
||||
in R_EXPTIME */
|
||||
int
|
||||
gpgsm_validate_chain (CTRL ctrl, KsbaCert cert, time_t *r_exptime)
|
||||
{
|
||||
int rc = 0, depth = 0, maxdepth;
|
||||
char *issuer = NULL;
|
||||
char *subject = NULL;
|
||||
KEYDB_HANDLE kh = keydb_new (0);
|
||||
KsbaCert subject_cert = NULL, issuer_cert = NULL;
|
||||
time_t current_time = gnupg_get_time ();
|
||||
time_t exptime = 0;
|
||||
int any_expired = 0;
|
||||
int any_revoked = 0;
|
||||
int any_no_crl = 0;
|
||||
int any_crl_too_old = 0;
|
||||
int any_no_policy_match = 0;
|
||||
|
||||
if (r_exptime)
|
||||
*r_exptime = 0;
|
||||
|
||||
if (opt.no_chain_validation)
|
||||
{
|
||||
log_info ("WARNING: bypassing certificate chain validation\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!kh)
|
||||
{
|
||||
log_error (_("failed to allocated keyDB handle\n"));
|
||||
rc = GNUPG_General_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (DBG_X509)
|
||||
gpgsm_dump_cert ("subject", cert);
|
||||
|
||||
subject_cert = cert;
|
||||
maxdepth = 50;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
xfree (issuer);
|
||||
xfree (subject);
|
||||
issuer = ksba_cert_get_issuer (subject_cert, 0);
|
||||
subject = ksba_cert_get_subject (subject_cert, 0);
|
||||
|
||||
if (!issuer)
|
||||
{
|
||||
log_error ("no issuer found in certificate\n");
|
||||
rc = GNUPG_Bad_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
{
|
||||
time_t not_before, not_after;
|
||||
|
||||
not_before = ksba_cert_get_validity (subject_cert, 0);
|
||||
not_after = ksba_cert_get_validity (subject_cert, 1);
|
||||
if (not_before == (time_t)(-1) || not_after == (time_t)(-1))
|
||||
{
|
||||
log_error ("certificate with invalid validity\n");
|
||||
rc = GNUPG_Bad_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (not_after)
|
||||
{
|
||||
if (!exptime)
|
||||
exptime = not_after;
|
||||
else if (not_after < exptime)
|
||||
exptime = not_after;
|
||||
}
|
||||
|
||||
if (not_before && current_time < not_before)
|
||||
{
|
||||
log_error ("certificate too young; valid from ");
|
||||
gpgsm_dump_time (not_before);
|
||||
log_printf ("\n");
|
||||
rc = GNUPG_Certificate_Too_Young;
|
||||
goto leave;
|
||||
}
|
||||
if (not_after && current_time > not_after)
|
||||
{
|
||||
log_error ("certificate has expired at ");
|
||||
gpgsm_dump_time (not_after);
|
||||
log_printf ("\n");
|
||||
any_expired = 1;
|
||||
}
|
||||
}
|
||||
|
||||
rc = unknown_criticals (subject_cert);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
if (!opt.no_policy_check)
|
||||
{
|
||||
rc = check_cert_policy (subject_cert);
|
||||
if (rc == GNUPG_No_Policy_Match)
|
||||
{
|
||||
any_no_policy_match = 1;
|
||||
rc = 1;
|
||||
}
|
||||
else if (rc)
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!opt.no_crl_check)
|
||||
{
|
||||
rc = gpgsm_dirmngr_isvalid (subject_cert);
|
||||
if (rc)
|
||||
{
|
||||
switch (rc)
|
||||
{
|
||||
case GNUPG_Certificate_Revoked:
|
||||
log_error (_("the certificate has been revoked\n"));
|
||||
any_revoked = 1;
|
||||
break;
|
||||
case GNUPG_No_CRL_Known:
|
||||
log_error (_("no CRL found for certificate\n"));
|
||||
any_no_crl = 1;
|
||||
break;
|
||||
case GNUPG_CRL_Too_Old:
|
||||
log_error (_("the available CRL is too old\n"));
|
||||
log_info (_("please make sure that the "
|
||||
"\"dirmngr\" is properly installed\n"));
|
||||
any_crl_too_old = 1;
|
||||
break;
|
||||
default:
|
||||
log_error (_("checking the CRL failed: %s\n"),
|
||||
gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (subject && !strcmp (issuer, subject))
|
||||
{
|
||||
if (gpgsm_check_cert_sig (subject_cert, subject_cert) )
|
||||
{
|
||||
log_error ("selfsigned certificate has a BAD signatures\n");
|
||||
rc = depth? GNUPG_Bad_Certificate_Chain : GNUPG_Bad_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
rc = allowed_ca (subject_cert, NULL);
|
||||
if (rc)
|
||||
goto leave;
|
||||
|
||||
rc = gpgsm_agent_istrusted (subject_cert);
|
||||
if (!rc)
|
||||
;
|
||||
else if (rc == GNUPG_Not_Trusted)
|
||||
{
|
||||
int rc2;
|
||||
|
||||
char *fpr = gpgsm_get_fingerprint_string (subject_cert,
|
||||
GCRY_MD_SHA1);
|
||||
log_info (_("root certificate is not marked trusted\n"));
|
||||
log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
|
||||
xfree (fpr);
|
||||
rc2 = gpgsm_agent_marktrusted (subject_cert);
|
||||
if (!rc2)
|
||||
{
|
||||
log_info (_("root certificate has now"
|
||||
" been marked as trusted\n"));
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
gpgsm_dump_cert ("issuer", subject_cert);
|
||||
log_info ("after checking the fingerprint, you may want "
|
||||
"to enter it manually into "
|
||||
"\"~/.gnupg-test/trustlist.txt\"\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log_error (_("checking the trust list failed: %s\n"),
|
||||
gnupg_strerror (rc));
|
||||
}
|
||||
|
||||
break; /* okay, a self-signed certicate is an end-point */
|
||||
}
|
||||
|
||||
depth++;
|
||||
if (depth > maxdepth)
|
||||
{
|
||||
log_error (_("certificate chain too long\n"));
|
||||
rc = GNUPG_Bad_Certificate_Chain;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* find the next cert up the tree */
|
||||
keydb_search_reset (kh);
|
||||
rc = find_up (kh, subject_cert, issuer);
|
||||
if (rc)
|
||||
{
|
||||
if (rc == -1)
|
||||
{
|
||||
log_info ("issuer certificate (");
|
||||
gpgsm_dump_string (issuer);
|
||||
log_printf (") not found\n");
|
||||
}
|
||||
else
|
||||
log_error ("failed to find issuer's certificate: rc=%d\n", rc);
|
||||
rc = GNUPG_Missing_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
ksba_cert_release (issuer_cert); issuer_cert = NULL;
|
||||
rc = keydb_get_cert (kh, &issuer_cert);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to get cert: rc=%d\n", rc);
|
||||
rc = GNUPG_General_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (DBG_X509)
|
||||
{
|
||||
log_debug ("got issuer's certificate:\n");
|
||||
gpgsm_dump_cert ("issuer", issuer_cert);
|
||||
}
|
||||
|
||||
if (gpgsm_check_cert_sig (issuer_cert, subject_cert) )
|
||||
{
|
||||
log_error ("certificate has a BAD signatures\n");
|
||||
rc = GNUPG_Bad_Certificate_Chain;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
{
|
||||
int chainlen;
|
||||
rc = allowed_ca (issuer_cert, &chainlen);
|
||||
if (rc)
|
||||
goto leave;
|
||||
if (chainlen >= 0 && (depth - 1) > chainlen)
|
||||
{
|
||||
log_error (_("certificate chain longer than allowed by CA (%d)\n"),
|
||||
chainlen);
|
||||
rc = GNUPG_Bad_Certificate_Chain;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
rc = gpgsm_cert_use_cert_p (issuer_cert);
|
||||
if (rc)
|
||||
{
|
||||
gpgsm_status2 (ctrl, STATUS_ERROR, "certcert.issuer.keyusage",
|
||||
gnupg_error_token (rc), NULL);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("certificate is good\n");
|
||||
|
||||
keydb_search_reset (kh);
|
||||
subject_cert = issuer_cert;
|
||||
issuer_cert = NULL;
|
||||
}
|
||||
|
||||
if (opt.no_policy_check)
|
||||
log_info ("policies not checked due to --disable-policy-checks option\n");
|
||||
if (opt.no_crl_check)
|
||||
log_info ("CRLs not checked due to --disable-crl-checks option\n");
|
||||
|
||||
if (!rc)
|
||||
{ /* If we encountered an error somewhere during the checks, set
|
||||
the error code to the most critical one */
|
||||
if (any_revoked)
|
||||
rc = GNUPG_Certificate_Revoked;
|
||||
else if (any_no_crl)
|
||||
rc = GNUPG_No_CRL_Known;
|
||||
else if (any_crl_too_old)
|
||||
rc = GNUPG_CRL_Too_Old;
|
||||
else if (any_no_policy_match)
|
||||
rc = GNUPG_No_Policy_Match;
|
||||
else if (any_expired)
|
||||
rc = GNUPG_Certificate_Expired;
|
||||
}
|
||||
|
||||
leave:
|
||||
if (r_exptime)
|
||||
*r_exptime = exptime;
|
||||
xfree (issuer);
|
||||
keydb_release (kh);
|
||||
ksba_cert_release (issuer_cert);
|
||||
if (subject_cert != cert)
|
||||
ksba_cert_release (subject_cert);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Check that the given certificate is valid but DO NOT check any
|
||||
constraints. We assume that the issuers certificate is already in
|
||||
the DB and that this one is valid; which it should be because it
|
||||
has been checked using this function. */
|
||||
int
|
||||
gpgsm_basic_cert_check (KsbaCert cert)
|
||||
{
|
||||
int rc = 0;
|
||||
char *issuer = NULL;
|
||||
char *subject = NULL;
|
||||
KEYDB_HANDLE kh = keydb_new (0);
|
||||
KsbaCert issuer_cert = NULL;
|
||||
|
||||
if (opt.no_chain_validation)
|
||||
{
|
||||
log_info ("WARNING: bypassing basic certificate checks\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!kh)
|
||||
{
|
||||
log_error (_("failed to allocated keyDB handle\n"));
|
||||
rc = GNUPG_General_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
issuer = ksba_cert_get_issuer (cert, 0);
|
||||
subject = ksba_cert_get_subject (cert, 0);
|
||||
if (!issuer)
|
||||
{
|
||||
log_error ("no issuer found in certificate\n");
|
||||
rc = GNUPG_Bad_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (subject && !strcmp (issuer, subject))
|
||||
{
|
||||
if (gpgsm_check_cert_sig (cert, cert) )
|
||||
{
|
||||
log_error ("selfsigned certificate has a BAD signatures\n");
|
||||
rc = GNUPG_Bad_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* find the next cert up the tree */
|
||||
keydb_search_reset (kh);
|
||||
rc = find_up (kh, cert, issuer);
|
||||
if (rc)
|
||||
{
|
||||
if (rc == -1)
|
||||
{
|
||||
log_info ("issuer certificate (");
|
||||
gpgsm_dump_string (issuer);
|
||||
log_printf (") not found\n");
|
||||
}
|
||||
else
|
||||
log_error ("failed to find issuer's certificate: rc=%d\n", rc);
|
||||
rc = GNUPG_Missing_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
ksba_cert_release (issuer_cert); issuer_cert = NULL;
|
||||
rc = keydb_get_cert (kh, &issuer_cert);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to get cert: rc=%d\n", rc);
|
||||
rc = GNUPG_General_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (gpgsm_check_cert_sig (issuer_cert, cert) )
|
||||
{
|
||||
log_error ("certificate has a BAD signatures\n");
|
||||
rc = GNUPG_Bad_Certificate;
|
||||
goto leave;
|
||||
}
|
||||
if (opt.verbose)
|
||||
log_info ("certificate is good\n");
|
||||
}
|
||||
|
||||
leave:
|
||||
xfree (issuer);
|
||||
keydb_release (kh);
|
||||
ksba_cert_release (issuer_cert);
|
||||
return rc;
|
||||
}
|
||||
|
289
sm/certcheck.c
289
sm/certcheck.c
@ -1,289 +0,0 @@
|
||||
/* certcheck.c - check one certificate
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
static int
|
||||
do_encode_md (GCRY_MD_HD md, int algo, unsigned int nbits,
|
||||
GCRY_MPI *r_val)
|
||||
{
|
||||
int nframe = (nbits+7) / 8;
|
||||
byte *frame;
|
||||
int i, n;
|
||||
byte asn[100];
|
||||
size_t asnlen;
|
||||
size_t len;
|
||||
|
||||
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 GNUPG_Internal_Error;
|
||||
}
|
||||
|
||||
len = gcry_md_get_algo_dlen (algo);
|
||||
|
||||
if ( len + asnlen + 4 > nframe )
|
||||
{
|
||||
log_error ("can't encode a %d bit MD into a %d bits frame\n",
|
||||
(int)(len*8), (int)nbits);
|
||||
return GNUPG_Internal_Error;
|
||||
}
|
||||
|
||||
/* We encode the MD in this way:
|
||||
*
|
||||
* 0 A PAD(n bytes) 0 ASN(asnlen bytes) MD(len bytes)
|
||||
*
|
||||
* PAD consists of FF bytes.
|
||||
*/
|
||||
frame = xtrymalloc (nframe);
|
||||
if (!frame)
|
||||
return GNUPG_Out_Of_Core;
|
||||
n = 0;
|
||||
frame[n++] = 0;
|
||||
frame[n++] = 1; /* block type */
|
||||
i = nframe - len - 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, gcry_md_read(md, algo), len ); n += len;
|
||||
assert ( n == nframe );
|
||||
if (DBG_X509)
|
||||
{
|
||||
int j;
|
||||
log_debug ("encoded hash:");
|
||||
for (j=0; j < nframe; j++)
|
||||
log_printf (" %02X", frame[j]);
|
||||
log_printf ("\n");
|
||||
}
|
||||
|
||||
gcry_mpi_scan (r_val, GCRYMPI_FMT_USG, frame, &nframe);
|
||||
xfree (frame);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Check the signature on CERT using the ISSUER-CERT. This function
|
||||
does only test the cryptographic signature and nothing else. It is
|
||||
assumed that the ISSUER_CERT is valid. */
|
||||
int
|
||||
gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert)
|
||||
{
|
||||
const char *algoid;
|
||||
GCRY_MD_HD md;
|
||||
int rc, algo;
|
||||
GCRY_MPI frame;
|
||||
KsbaSexp p;
|
||||
size_t n;
|
||||
GCRY_SEXP s_sig, s_hash, s_pkey;
|
||||
|
||||
algo = gcry_md_map_name ( (algoid=ksba_cert_get_digest_algo (cert)));
|
||||
if (!algo)
|
||||
{
|
||||
log_error ("unknown hash algorithm `%s'\n", algoid? algoid:"?");
|
||||
return GNUPG_General_Error;
|
||||
}
|
||||
md = gcry_md_open (algo, 0);
|
||||
if (!md)
|
||||
{
|
||||
log_error ("md_open failed: %s\n", gcry_strerror (-1));
|
||||
return GNUPG_General_Error;
|
||||
}
|
||||
|
||||
rc = ksba_cert_hash (cert, 1, HASH_FNC, md);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("ksba_cert_hash failed: %s\n", ksba_strerror (rc));
|
||||
gcry_md_close (md);
|
||||
return map_ksba_err (rc);
|
||||
}
|
||||
gcry_md_final (md);
|
||||
|
||||
p = ksba_cert_get_sig_val (cert);
|
||||
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
|
||||
if (!n)
|
||||
{
|
||||
log_error ("libksba did not return a proper S-Exp\n");
|
||||
gcry_md_close (md);
|
||||
ksba_free (p);
|
||||
return GNUPG_Bug;
|
||||
}
|
||||
rc = gcry_sexp_sscan ( &s_sig, NULL, p, n);
|
||||
ksba_free (p);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
|
||||
gcry_md_close (md);
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
p = ksba_cert_get_public_key (issuer_cert);
|
||||
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
|
||||
if (!n)
|
||||
{
|
||||
log_error ("libksba did not return a proper S-Exp\n");
|
||||
gcry_md_close (md);
|
||||
ksba_free (p);
|
||||
gcry_sexp_release (s_sig);
|
||||
return GNUPG_Bug;
|
||||
}
|
||||
rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
|
||||
ksba_free (p);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
|
||||
gcry_md_close (md);
|
||||
gcry_sexp_release (s_sig);
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame);
|
||||
if (rc)
|
||||
{
|
||||
gcry_md_close (md);
|
||||
gcry_sexp_release (s_sig);
|
||||
gcry_sexp_release (s_pkey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* put hash into the S-Exp s_hash */
|
||||
if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
|
||||
BUG ();
|
||||
gcry_mpi_release (frame);
|
||||
|
||||
rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
|
||||
if (DBG_CRYPTO)
|
||||
log_debug ("gcry_pk_verify: %s\n", gcry_strerror (rc));
|
||||
gcry_md_close (md);
|
||||
gcry_sexp_release (s_sig);
|
||||
gcry_sexp_release (s_hash);
|
||||
gcry_sexp_release (s_pkey);
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
gpgsm_check_cms_signature (KsbaCert cert, KsbaConstSexp sigval,
|
||||
GCRY_MD_HD md, int algo)
|
||||
{
|
||||
int rc;
|
||||
KsbaSexp p;
|
||||
GCRY_MPI frame;
|
||||
GCRY_SEXP s_sig, s_hash, s_pkey;
|
||||
size_t n;
|
||||
|
||||
n = gcry_sexp_canon_len (sigval, 0, NULL, NULL);
|
||||
if (!n)
|
||||
{
|
||||
log_error ("libksba did not return a proper S-Exp\n");
|
||||
return GNUPG_Bug;
|
||||
}
|
||||
rc = gcry_sexp_sscan (&s_sig, NULL, sigval, n);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
p = ksba_cert_get_public_key (cert);
|
||||
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
|
||||
if (!n)
|
||||
{
|
||||
log_error ("libksba did not return a proper S-Exp\n");
|
||||
ksba_free (p);
|
||||
gcry_sexp_release (s_sig);
|
||||
return GNUPG_Bug;
|
||||
}
|
||||
if (DBG_X509)
|
||||
log_printhex ("public key: ", p, n);
|
||||
|
||||
rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
|
||||
ksba_free (p);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
|
||||
gcry_sexp_release (s_sig);
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
|
||||
rc = do_encode_md (md, algo, gcry_pk_get_nbits (s_pkey), &frame);
|
||||
if (rc)
|
||||
{
|
||||
gcry_sexp_release (s_sig);
|
||||
gcry_sexp_release (s_pkey);
|
||||
return rc;
|
||||
}
|
||||
/* put hash into the S-Exp s_hash */
|
||||
if ( gcry_sexp_build (&s_hash, NULL, "%m", frame) )
|
||||
BUG ();
|
||||
gcry_mpi_release (frame);
|
||||
|
||||
|
||||
rc = gcry_pk_verify (s_sig, s_hash, s_pkey);
|
||||
if (DBG_CRYPTO)
|
||||
log_debug ("gcry_pk_verify: %s\n", gcry_strerror (rc));
|
||||
gcry_sexp_release (s_sig);
|
||||
gcry_sexp_release (s_hash);
|
||||
gcry_sexp_release (s_sig);
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int
|
||||
gpgsm_create_cms_signature (KsbaCert cert, GCRY_MD_HD md, int mdalgo,
|
||||
char **r_sigval)
|
||||
{
|
||||
int rc;
|
||||
char *grip;
|
||||
size_t siglen;
|
||||
|
||||
grip = gpgsm_get_keygrip_hexstring (cert);
|
||||
if (!grip)
|
||||
return seterr (Bad_Certificate);
|
||||
|
||||
rc = gpgsm_agent_pksign (grip, gcry_md_read(md, mdalgo),
|
||||
gcry_md_get_algo_dlen (mdalgo), mdalgo,
|
||||
r_sigval, &siglen);
|
||||
xfree (grip);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
457
sm/certdump.c
457
sm/certdump.c
@ -1,457 +0,0 @@
|
||||
/* certdump.c - Dump a certificate for debugging
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
struct dn_array_s {
|
||||
char *key;
|
||||
char *value;
|
||||
};
|
||||
|
||||
|
||||
/* print the first element of an S-Expression */
|
||||
void
|
||||
gpgsm_print_serial (FILE *fp, KsbaConstSexp p)
|
||||
{
|
||||
unsigned long n;
|
||||
KsbaConstSexp endp;
|
||||
|
||||
if (!p)
|
||||
fputs (_("none"), fp);
|
||||
else if (*p != '(')
|
||||
fputs ("[Internal error - not an S-expression]", fp);
|
||||
else
|
||||
{
|
||||
p++;
|
||||
n = strtoul (p, (char**)&endp, 10);
|
||||
p = endp;
|
||||
if (*p!=':')
|
||||
fputs ("[Internal Error - invalid S-expression]", fp);
|
||||
else
|
||||
{
|
||||
for (p++; n; n--, p++)
|
||||
fprintf (fp, "%02X", *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gpgsm_dump_serial (KsbaConstSexp p)
|
||||
{
|
||||
unsigned long n;
|
||||
KsbaConstSexp endp;
|
||||
|
||||
if (!p)
|
||||
log_printf ("none");
|
||||
else if (*p != '(')
|
||||
log_printf ("ERROR - not an S-expression");
|
||||
else
|
||||
{
|
||||
p++;
|
||||
n = strtoul (p, (char**)&endp, 10);
|
||||
p = endp;
|
||||
if (*p!=':')
|
||||
log_printf ("ERROR - invalid S-expression");
|
||||
else
|
||||
{
|
||||
for (p++; n; n--, p++)
|
||||
log_printf ("%02X", *p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gpgsm_print_time (FILE *fp, time_t t)
|
||||
{
|
||||
if (!t)
|
||||
fputs (_("none"), fp);
|
||||
else if ( t == (time_t)(-1) )
|
||||
fputs ("[Error - Invalid time]", fp);
|
||||
else
|
||||
{
|
||||
struct tm *tp;
|
||||
|
||||
tp = gmtime (&t);
|
||||
fprintf (fp, "%04d-%02d-%02d %02d:%02d:%02d Z",
|
||||
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec);
|
||||
assert (!tp->tm_isdst);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
gpgsm_dump_time (time_t t)
|
||||
{
|
||||
|
||||
if (!t)
|
||||
log_printf (_("[none]"));
|
||||
else if ( t == (time_t)(-1) )
|
||||
log_printf (_("[error]"));
|
||||
else
|
||||
{
|
||||
struct tm *tp;
|
||||
|
||||
tp = gmtime (&t);
|
||||
log_printf ("%04d-%02d-%02d %02d:%02d:%02d",
|
||||
1900+tp->tm_year, tp->tm_mon+1, tp->tm_mday,
|
||||
tp->tm_hour, tp->tm_min, tp->tm_sec);
|
||||
assert (!tp->tm_isdst);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
gpgsm_dump_string (const char *string)
|
||||
{
|
||||
|
||||
if (!string)
|
||||
log_printf ("[error]");
|
||||
else
|
||||
{
|
||||
const unsigned char *s;
|
||||
|
||||
for (s=string; *s; s++)
|
||||
{
|
||||
if (*s < ' ' || (*s >= 0x7f && *s <= 0xa0))
|
||||
break;
|
||||
}
|
||||
if (!*s && *string != '[')
|
||||
log_printf ("%s", string);
|
||||
else
|
||||
{
|
||||
log_printf ( "[ ");
|
||||
log_printhex (NULL, string, strlen (string));
|
||||
log_printf ( " ]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
gpgsm_dump_cert (const char *text, KsbaCert cert)
|
||||
{
|
||||
KsbaSexp sexp;
|
||||
unsigned char *p;
|
||||
char *dn;
|
||||
time_t t;
|
||||
|
||||
log_debug ("BEGIN Certificate `%s':\n", text? text:"");
|
||||
if (cert)
|
||||
{
|
||||
sexp = ksba_cert_get_serial (cert);
|
||||
log_debug (" serial: ");
|
||||
gpgsm_dump_serial (sexp);
|
||||
ksba_free (sexp);
|
||||
log_printf ("\n");
|
||||
|
||||
t = ksba_cert_get_validity (cert, 0);
|
||||
log_debug (" notBefore: ");
|
||||
gpgsm_dump_time (t);
|
||||
log_printf ("\n");
|
||||
t = ksba_cert_get_validity (cert, 1);
|
||||
log_debug (" notAfter: ");
|
||||
gpgsm_dump_time (t);
|
||||
log_printf ("\n");
|
||||
|
||||
dn = ksba_cert_get_issuer (cert, 0);
|
||||
log_debug (" issuer: ");
|
||||
gpgsm_dump_string (dn);
|
||||
ksba_free (dn);
|
||||
log_printf ("\n");
|
||||
|
||||
dn = ksba_cert_get_subject (cert, 0);
|
||||
log_debug (" subject: ");
|
||||
gpgsm_dump_string (dn);
|
||||
ksba_free (dn);
|
||||
log_printf ("\n");
|
||||
|
||||
log_debug (" hash algo: %s\n", ksba_cert_get_digest_algo (cert));
|
||||
|
||||
p = gpgsm_get_fingerprint_string (cert, 0);
|
||||
log_debug (" SHA1 Fingerprint: %s\n", p);
|
||||
xfree (p);
|
||||
}
|
||||
log_debug ("END Certificate\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* helper for the rfc2253 string parser */
|
||||
static const unsigned char *
|
||||
parse_dn_part (struct dn_array_s *array, const unsigned char *string)
|
||||
{
|
||||
const unsigned char *s, *s1;
|
||||
size_t n;
|
||||
unsigned char *p;
|
||||
|
||||
/* parse attributeType */
|
||||
for (s = string+1; *s && *s != '='; s++)
|
||||
;
|
||||
if (!*s)
|
||||
return NULL; /* error */
|
||||
n = s - string;
|
||||
if (!n)
|
||||
return NULL; /* empty key */
|
||||
array->key = p = xtrymalloc (n+1);
|
||||
if (!array->key)
|
||||
return NULL;
|
||||
memcpy (p, string, n);
|
||||
p[n] = 0;
|
||||
trim_trailing_spaces (p);
|
||||
if ( !strcmp (p, "1.2.840.113549.1.9.1") )
|
||||
strcpy (p, "EMail");
|
||||
string = s + 1;
|
||||
|
||||
if (*string == '#')
|
||||
{ /* hexstring */
|
||||
string++;
|
||||
for (s=string; hexdigitp (s); s++)
|
||||
s++;
|
||||
n = s - string;
|
||||
if (!n || (n & 1))
|
||||
return NULL; /* empty or odd number of digits */
|
||||
n /= 2;
|
||||
array->value = p = xtrymalloc (n+1);
|
||||
if (!p)
|
||||
return NULL;
|
||||
for (s1=string; n; s1 += 2, n--)
|
||||
*p++ = xtoi_2 (s1);
|
||||
*p = 0;
|
||||
}
|
||||
else
|
||||
{ /* regular v3 quoted string */
|
||||
for (n=0, s=string; *s; s++)
|
||||
{
|
||||
if (*s == '\\')
|
||||
{ /* pair */
|
||||
s++;
|
||||
if (*s == ',' || *s == '=' || *s == '+'
|
||||
|| *s == '<' || *s == '>' || *s == '#' || *s == ';'
|
||||
|| *s == '\\' || *s == '\"' || *s == ' ')
|
||||
n++;
|
||||
else if (hexdigitp (s) && hexdigitp (s+1))
|
||||
{
|
||||
s++;
|
||||
n++;
|
||||
}
|
||||
else
|
||||
return NULL; /* invalid escape sequence */
|
||||
}
|
||||
else if (*s == '\"')
|
||||
return NULL; /* invalid encoding */
|
||||
else if (*s == ',' || *s == '=' || *s == '+'
|
||||
|| *s == '<' || *s == '>' || *s == '#' || *s == ';' )
|
||||
break;
|
||||
else
|
||||
n++;
|
||||
}
|
||||
|
||||
array->value = p = xtrymalloc (n+1);
|
||||
if (!p)
|
||||
return NULL;
|
||||
for (s=string; n; s++, n--)
|
||||
{
|
||||
if (*s == '\\')
|
||||
{
|
||||
s++;
|
||||
if (hexdigitp (s))
|
||||
{
|
||||
*p++ = xtoi_2 (s);
|
||||
s++;
|
||||
}
|
||||
else
|
||||
*p++ = *s;
|
||||
}
|
||||
else
|
||||
*p++ = *s;
|
||||
}
|
||||
*p = 0;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
/* Parse a DN and return an array-ized one. This is not a validating
|
||||
parser and it does not support any old-stylish syntax; KSBA is
|
||||
expected to return only rfc2253 compatible strings. */
|
||||
static struct dn_array_s *
|
||||
parse_dn (const unsigned char *string)
|
||||
{
|
||||
struct dn_array_s *array;
|
||||
size_t arrayidx, arraysize;
|
||||
int i;
|
||||
|
||||
arraysize = 7; /* C,ST,L,O,OU,CN,email */
|
||||
arrayidx = 0;
|
||||
array = xtrymalloc ((arraysize+1) * sizeof *array);
|
||||
if (!array)
|
||||
return NULL;
|
||||
while (*string)
|
||||
{
|
||||
while (*string == ' ')
|
||||
string++;
|
||||
if (!*string)
|
||||
break; /* ready */
|
||||
if (arrayidx >= arraysize)
|
||||
{
|
||||
struct dn_array_s *a2;
|
||||
|
||||
arraysize += 5;
|
||||
a2 = xtryrealloc (array, (arraysize+1) * sizeof *array);
|
||||
if (!a2)
|
||||
goto failure;
|
||||
array = a2;
|
||||
}
|
||||
array[arrayidx].key = NULL;
|
||||
array[arrayidx].value = NULL;
|
||||
string = parse_dn_part (array+arrayidx, string);
|
||||
arrayidx++;
|
||||
if (!string)
|
||||
goto failure;
|
||||
while (*string == ' ')
|
||||
string++;
|
||||
if (*string && *string != ',' && *string != ';' && *string != '+')
|
||||
goto failure; /* invalid delimiter */
|
||||
if (*string)
|
||||
string++;
|
||||
}
|
||||
array[arrayidx].key = NULL;
|
||||
array[arrayidx].value = NULL;
|
||||
return array;
|
||||
|
||||
failure:
|
||||
for (i=0; i < arrayidx; i++)
|
||||
{
|
||||
xfree (array[i].key);
|
||||
xfree (array[i].value);
|
||||
}
|
||||
xfree (array);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
print_dn_part (FILE *fp, struct dn_array_s *dn, const char *key)
|
||||
{
|
||||
int any = 0;
|
||||
|
||||
for (; dn->key; dn++)
|
||||
{
|
||||
if (!strcmp (dn->key, key) && dn->value && *dn->value)
|
||||
{
|
||||
putc ('/', fp);
|
||||
if (any)
|
||||
fputs (" + ", fp);
|
||||
else
|
||||
fprintf (fp, "%s=", key);
|
||||
print_sanitized_utf8_string (fp, dn->value, '/');
|
||||
any = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print all parts of a DN in a "standard" sequence. We first print
|
||||
all the known parts, followed by the uncommon ones */
|
||||
static void
|
||||
print_dn_parts (FILE *fp, struct dn_array_s *dn)
|
||||
{
|
||||
const char *stdpart[] = {
|
||||
"CN", "OU", "O", "STREET", "L", "ST", "C", "EMail", NULL
|
||||
};
|
||||
int i;
|
||||
|
||||
for (i=0; stdpart[i]; i++)
|
||||
print_dn_part (fp, dn, stdpart[i]);
|
||||
|
||||
/* now print the rest without any specific ordering */
|
||||
for (; dn->key; dn++)
|
||||
{
|
||||
for (i=0; stdpart[i]; i++)
|
||||
{
|
||||
if (!strcmp (dn->key, stdpart[i]))
|
||||
break;
|
||||
}
|
||||
if (!stdpart[i])
|
||||
print_dn_part (fp, dn, dn->key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void
|
||||
gpgsm_print_name (FILE *fp, const char *name)
|
||||
{
|
||||
const unsigned char *s;
|
||||
int i;
|
||||
|
||||
s = name;
|
||||
if (!s)
|
||||
{
|
||||
fputs (_("[Error - No name]"), fp);
|
||||
}
|
||||
else if (*s == '<')
|
||||
{
|
||||
const unsigned char *s2 = strchr (s+1, '>');
|
||||
if (s2)
|
||||
print_sanitized_utf8_buffer (fp, s + 1, s2 - s - 1, 0);
|
||||
}
|
||||
else if (*s == '(')
|
||||
fputs (_("[Error - unknown encoding]"), fp);
|
||||
else if (!((*s >= '0' && *s < '9')
|
||||
|| (*s >= 'A' && *s <= 'Z')
|
||||
|| (*s >= 'a' && *s <= 'z')))
|
||||
fputs (_("[Error - invalid encoding]"), fp);
|
||||
else
|
||||
{
|
||||
struct dn_array_s *dn = parse_dn (s);
|
||||
if (!dn)
|
||||
fputs (_("[Error - invalid DN]"), fp);
|
||||
else
|
||||
{
|
||||
print_dn_parts (fp, dn);
|
||||
for (i=0; dn[i].key; i++)
|
||||
{
|
||||
xfree (dn[i].key);
|
||||
xfree (dn[i].value);
|
||||
}
|
||||
xfree (dn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
313
sm/certlist.c
313
sm/certlist.c
@ -1,313 +0,0 @@
|
||||
/* certlist.c - build list of certificates
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
/* Return 0 if the cert is usable for encryption. A MODE of 0 checks
|
||||
for signing a MODE of 1 checks for encryption, a MODE of 2 checks
|
||||
for verification and a MODE of 3 for decryption (just for
|
||||
debugging) */
|
||||
static int
|
||||
cert_usage_p (KsbaCert cert, int mode)
|
||||
{
|
||||
KsbaError err;
|
||||
unsigned int use;
|
||||
|
||||
err = ksba_cert_get_key_usage (cert, &use);
|
||||
if (err == KSBA_No_Data)
|
||||
{
|
||||
if (opt.verbose && mode < 2)
|
||||
log_info (mode?
|
||||
_("no key usage specified - accepted for encryption\n"):
|
||||
_("no key usage specified - accepted for signing\n"));
|
||||
return 0;
|
||||
}
|
||||
if (err)
|
||||
{
|
||||
log_error (_("error getting key usage information: %s\n"),
|
||||
ksba_strerror (err));
|
||||
return map_ksba_err (err);
|
||||
}
|
||||
|
||||
if (mode == 4)
|
||||
{
|
||||
if ((use & (KSBA_KEYUSAGE_KEY_CERT_SIGN)))
|
||||
return 0;
|
||||
log_info ( _("certificate should have not been used certification\n"));
|
||||
return GNUPG_Wrong_Key_Usage;
|
||||
}
|
||||
|
||||
if ((use & ((mode&1)?
|
||||
(KSBA_KEYUSAGE_KEY_ENCIPHERMENT|KSBA_KEYUSAGE_DATA_ENCIPHERMENT):
|
||||
(KSBA_KEYUSAGE_DIGITAL_SIGNATURE|KSBA_KEYUSAGE_NON_REPUDIATION)))
|
||||
)
|
||||
return 0;
|
||||
log_info (mode==3? _("certificate should have not been used for encryption\n"):
|
||||
mode==2? _("certificate should have not been used for signing\n"):
|
||||
mode==1? _("certificate is not usable for encryption\n"):
|
||||
_("certificate is not usable for signing\n"));
|
||||
return GNUPG_Wrong_Key_Usage;
|
||||
}
|
||||
|
||||
|
||||
/* Return 0 if the cert is usable for signing */
|
||||
int
|
||||
gpgsm_cert_use_sign_p (KsbaCert cert)
|
||||
{
|
||||
return cert_usage_p (cert, 0);
|
||||
}
|
||||
|
||||
|
||||
/* Return 0 if the cert is usable for encryption */
|
||||
int
|
||||
gpgsm_cert_use_encrypt_p (KsbaCert cert)
|
||||
{
|
||||
return cert_usage_p (cert, 1);
|
||||
}
|
||||
|
||||
int
|
||||
gpgsm_cert_use_verify_p (KsbaCert cert)
|
||||
{
|
||||
return cert_usage_p (cert, 2);
|
||||
}
|
||||
|
||||
int
|
||||
gpgsm_cert_use_decrypt_p (KsbaCert cert)
|
||||
{
|
||||
return cert_usage_p (cert, 3);
|
||||
}
|
||||
|
||||
int
|
||||
gpgsm_cert_use_cert_p (KsbaCert cert)
|
||||
{
|
||||
return cert_usage_p (cert, 4);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
same_subject_issuer (const char *subject, const char *issuer, KsbaCert cert)
|
||||
{
|
||||
char *subject2 = ksba_cert_get_subject (cert, 0);
|
||||
char *issuer2 = ksba_cert_get_subject (cert, 0);
|
||||
int tmp;
|
||||
|
||||
tmp = (subject && subject2
|
||||
&& !strcmp (subject, subject2)
|
||||
&& issuer && issuer2
|
||||
&& !strcmp (issuer, issuer2));
|
||||
xfree (subject2);
|
||||
xfree (issuer2);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Add a certificate to a list of certificate and make sure that it is
|
||||
a valid certificate. With SECRET set to true a secret key must be
|
||||
avaibale for the certificate. */
|
||||
int
|
||||
gpgsm_add_to_certlist (CTRL ctrl, const char *name, int secret,
|
||||
CERTLIST *listaddr)
|
||||
{
|
||||
int rc;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
KEYDB_HANDLE kh = NULL;
|
||||
KsbaCert cert = NULL;
|
||||
|
||||
rc = keydb_classify_name (name, &desc);
|
||||
if (!rc)
|
||||
{
|
||||
kh = keydb_new (0);
|
||||
if (!kh)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
int wrong_usage = 0;
|
||||
char *subject = NULL;
|
||||
char *issuer = NULL;
|
||||
|
||||
get_next:
|
||||
rc = keydb_search (kh, &desc, 1);
|
||||
if (!rc)
|
||||
rc = keydb_get_cert (kh, &cert);
|
||||
if (!rc)
|
||||
{
|
||||
rc = secret? gpgsm_cert_use_sign_p (cert)
|
||||
: gpgsm_cert_use_encrypt_p (cert);
|
||||
if (rc == GNUPG_Wrong_Key_Usage)
|
||||
{
|
||||
/* There might be another certificate with the
|
||||
correct usage, so we try again */
|
||||
if (!wrong_usage)
|
||||
{ /* save the first match */
|
||||
wrong_usage = rc;
|
||||
subject = ksba_cert_get_subject (cert, 0);
|
||||
issuer = ksba_cert_get_subject (cert, 0);
|
||||
ksba_cert_release (cert);
|
||||
cert = NULL;
|
||||
goto get_next;
|
||||
}
|
||||
else if (same_subject_issuer (subject, issuer, cert))
|
||||
{
|
||||
wrong_usage = rc;
|
||||
ksba_cert_release (cert);
|
||||
cert = NULL;
|
||||
goto get_next;
|
||||
}
|
||||
else
|
||||
wrong_usage = rc;
|
||||
|
||||
}
|
||||
}
|
||||
/* we want the error code from the first match in this case */
|
||||
if (rc && wrong_usage)
|
||||
rc = wrong_usage;
|
||||
|
||||
if (!rc)
|
||||
{
|
||||
next_ambigious:
|
||||
rc = keydb_search (kh, &desc, 1);
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
else if (!rc)
|
||||
{
|
||||
KsbaCert cert2 = NULL;
|
||||
|
||||
/* We have to ignore ambigious names as long as
|
||||
there only fault is a bad key usage */
|
||||
if (!keydb_get_cert (kh, &cert2))
|
||||
{
|
||||
int tmp = (same_subject_issuer (subject, issuer, cert2)
|
||||
&& ((secret? gpgsm_cert_use_sign_p (cert2):
|
||||
gpgsm_cert_use_encrypt_p (cert2))
|
||||
== GNUPG_Wrong_Key_Usage));
|
||||
ksba_cert_release (cert2);
|
||||
if (tmp)
|
||||
goto next_ambigious;
|
||||
}
|
||||
rc = GNUPG_Ambiguous_Name;
|
||||
}
|
||||
}
|
||||
xfree (subject);
|
||||
xfree (issuer);
|
||||
|
||||
if (!rc && secret)
|
||||
{
|
||||
char *p;
|
||||
|
||||
rc = GNUPG_No_Secret_Key;
|
||||
p = gpgsm_get_keygrip_hexstring (cert);
|
||||
if (p)
|
||||
{
|
||||
if (!gpgsm_agent_havekey (p))
|
||||
rc = 0;
|
||||
xfree (p);
|
||||
}
|
||||
}
|
||||
if (!rc)
|
||||
rc = gpgsm_validate_chain (ctrl, cert, NULL);
|
||||
if (!rc)
|
||||
{
|
||||
CERTLIST cl = xtrycalloc (1, sizeof *cl);
|
||||
if (!cl)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
cl->cert = cert; cert = NULL;
|
||||
cl->next = *listaddr;
|
||||
*listaddr = cl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keydb_release (kh);
|
||||
ksba_cert_release (cert);
|
||||
return rc == -1? GNUPG_No_Public_Key: rc;
|
||||
}
|
||||
|
||||
void
|
||||
gpgsm_release_certlist (CERTLIST list)
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
CERTLIST cl = list->next;
|
||||
ksba_cert_release (list->cert);
|
||||
xfree (list);
|
||||
list = cl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Like gpgsm_add_to_certlist, but look only for one certificate. No
|
||||
chain validation is done */
|
||||
int
|
||||
gpgsm_find_cert (const char *name, KsbaCert *r_cert)
|
||||
{
|
||||
int rc;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
KEYDB_HANDLE kh = NULL;
|
||||
|
||||
*r_cert = NULL;
|
||||
rc = keydb_classify_name (name, &desc);
|
||||
if (!rc)
|
||||
{
|
||||
kh = keydb_new (0);
|
||||
if (!kh)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
rc = keydb_search (kh, &desc, 1);
|
||||
if (!rc)
|
||||
rc = keydb_get_cert (kh, r_cert);
|
||||
if (!rc)
|
||||
{
|
||||
rc = keydb_search (kh, &desc, 1);
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
else
|
||||
{
|
||||
if (!rc)
|
||||
rc = GNUPG_Ambiguous_Name;
|
||||
ksba_cert_release (*r_cert);
|
||||
*r_cert = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keydb_release (kh);
|
||||
return rc == -1? GNUPG_No_Public_Key: rc;
|
||||
}
|
||||
|
699
sm/certreqgen.c
699
sm/certreqgen.c
@ -1,699 +0,0 @@
|
||||
/* certreqgen.c - Generate a key and a certification request
|
||||
* Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
* GnuPG is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* GnuPG is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
|
||||
*/
|
||||
|
||||
/*
|
||||
The format of the native parameter file is follows:
|
||||
o Text only, line length is limited to about 1000 chars.
|
||||
o You must use UTF-8 encoding to specify non-ascii characters.
|
||||
o Empty lines are ignored.
|
||||
o Leading and trailing spaces are ignored.
|
||||
o A hash sign as the first non white space character is a comment line.
|
||||
o Control statements are indicated by a leading percent sign, the
|
||||
arguments are separated by white space from the keyword.
|
||||
o Parameters are specified by a keyword, followed by a colon. Arguments
|
||||
are separated by white space.
|
||||
o The first parameter must be "Key-Type", control statements
|
||||
may be placed anywhere.
|
||||
o Key generation takes place when either the end of the parameter file
|
||||
is reached, the next "Key-Type" parameter is encountered or at the
|
||||
controlstatement "%commit"
|
||||
o Control statements:
|
||||
%echo <text>
|
||||
Print <text>.
|
||||
%dry-run
|
||||
Suppress actual key generation (useful for syntax checking).
|
||||
%commit
|
||||
Perform the key generation. Note that an implicit commit is done
|
||||
at the next "Key-Type" parameter.
|
||||
%certfile <filename>
|
||||
Do not write the certificate to the keyDB but to <filename>.
|
||||
This must be given before the first
|
||||
commit to take place, duplicate specification of the same filename
|
||||
is ignored, the last filename before a commit is used.
|
||||
The filename is used until a new filename is used (at commit points)
|
||||
and all keys are written to that file. If a new filename is given,
|
||||
this file is created (and overwrites an existing one).
|
||||
Both control statements must be given.
|
||||
o The order of the parameters does not matter except for "Key-Type"
|
||||
which must be the first parameter. The parameters are only for the
|
||||
generated keyblock and parameters from previous key generations are not
|
||||
used. Some syntactically checks may be performed.
|
||||
The currently defined parameters are:
|
||||
Key-Type: <algo>
|
||||
Starts a new parameter block by giving the type of the
|
||||
primary key. The algorithm must be capable of signing.
|
||||
This is a required parameter. For now the only supported
|
||||
algorithm is "rsa".
|
||||
Key-Length: <length-in-bits>
|
||||
Length of the key in bits. Default is 1024.
|
||||
Key-Usage: <usage-list>
|
||||
Space or comma delimited list of key usage, allowed values are
|
||||
"encrypt" and "sign". This is used to generate the KeyUsage extension.
|
||||
Please make sure that the algorithm is capable of this usage. Default
|
||||
is to allow encrypt and sign.
|
||||
Name-DN: subject name
|
||||
This is the DN name of the subject in rfc2253 format.
|
||||
Name-Email: <string>
|
||||
The ist the email address
|
||||
|
||||
Here is an example:
|
||||
$ cat >foo <<EOF
|
||||
%echo Generating a standard key
|
||||
Key-Type: RSA
|
||||
Key-Length: 1024
|
||||
Name-DN: CN=test cert 1,OU=Aegypten Project,O=g10 Code GmbH,L=Düsseldorf,C=DE
|
||||
Name-Email: joe@foo.bar
|
||||
# Do a commit here, so that we can later print "done" :-)
|
||||
%commit
|
||||
%echo done
|
||||
EOF
|
||||
*/
|
||||
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
enum para_name {
|
||||
pKEYTYPE,
|
||||
pKEYLENGTH,
|
||||
pKEYUSAGE,
|
||||
pNAMEDN,
|
||||
pNAMEEMAIL
|
||||
};
|
||||
|
||||
struct para_data_s {
|
||||
struct para_data_s *next;
|
||||
int lnr;
|
||||
enum para_name key;
|
||||
union {
|
||||
unsigned int usage;
|
||||
char value[1];
|
||||
} u;
|
||||
};
|
||||
|
||||
struct reqgen_ctrl_s {
|
||||
int lnr;
|
||||
int dryrun;
|
||||
KsbaWriter writer;
|
||||
};
|
||||
|
||||
|
||||
static int proc_parameters (struct para_data_s *para,
|
||||
struct reqgen_ctrl_s *outctrl);
|
||||
static int create_request (struct para_data_s *para,
|
||||
KsbaConstSexp public,
|
||||
struct reqgen_ctrl_s *outctrl);
|
||||
|
||||
|
||||
|
||||
static void
|
||||
release_parameter_list (struct para_data_s *r)
|
||||
{
|
||||
struct para_data_s *r2;
|
||||
|
||||
for (; r ; r = r2)
|
||||
{
|
||||
r2 = r->next;
|
||||
xfree(r);
|
||||
}
|
||||
}
|
||||
|
||||
static struct para_data_s *
|
||||
get_parameter (struct para_data_s *para, enum para_name key)
|
||||
{
|
||||
struct para_data_s *r;
|
||||
|
||||
for (r = para; r && r->key != key; r = r->next)
|
||||
;
|
||||
return r;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_parameter_value (struct para_data_s *para, enum para_name key)
|
||||
{
|
||||
struct para_data_s *r = get_parameter (para, key);
|
||||
return (r && *r->u.value)? r->u.value : NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
get_parameter_algo (struct para_data_s *para, enum para_name key)
|
||||
{
|
||||
struct para_data_s *r = get_parameter (para, key);
|
||||
if (!r)
|
||||
return -1;
|
||||
if (digitp (r->u.value))
|
||||
return atoi( r->u.value );
|
||||
return gcry_pk_map_name (r->u.value);
|
||||
}
|
||||
|
||||
/* parse the usage parameter. Returns 0 on success. Note that we
|
||||
only care about sign and encrypt and don't (yet) allow all the
|
||||
other X.509 usage to be specified; instead we will use a fixed
|
||||
mapping to the X.509 usage flags */
|
||||
static int
|
||||
parse_parameter_usage (struct para_data_s *para, enum para_name key)
|
||||
{
|
||||
struct para_data_s *r = get_parameter (para, key);
|
||||
char *p, *pn;
|
||||
unsigned int use;
|
||||
|
||||
if (!r)
|
||||
return 0; /* none (this is an optional parameter)*/
|
||||
|
||||
use = 0;
|
||||
pn = r->u.value;
|
||||
while ( (p = strsep (&pn, " \t,")) )
|
||||
{
|
||||
if (!*p)
|
||||
;
|
||||
else if ( !ascii_strcasecmp (p, "sign") )
|
||||
use |= GCRY_PK_USAGE_SIGN;
|
||||
else if ( !ascii_strcasecmp (p, "encrypt") )
|
||||
use |= GCRY_PK_USAGE_ENCR;
|
||||
else
|
||||
{
|
||||
log_error ("line %d: invalid usage list\n", r->lnr);
|
||||
return -1; /* error */
|
||||
}
|
||||
}
|
||||
r->u.usage = use;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static unsigned int
|
||||
get_parameter_uint (struct para_data_s *para, enum para_name key)
|
||||
{
|
||||
struct para_data_s *r = get_parameter (para, key);
|
||||
|
||||
if (!r)
|
||||
return 0;
|
||||
|
||||
return (unsigned int)strtoul (r->u.value, NULL, 10);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Read the certificate generation parameters from FP and generate
|
||||
(all) certificate requests. */
|
||||
static int
|
||||
read_parameters (FILE *fp, KsbaWriter writer)
|
||||
{
|
||||
static struct {
|
||||
const char *name;
|
||||
enum para_name key;
|
||||
} keywords[] = {
|
||||
{ "Key-Type", pKEYTYPE},
|
||||
{ "Key-Length", pKEYLENGTH },
|
||||
{ "Key-Usage", pKEYUSAGE },
|
||||
{ "Name-DN", pNAMEDN },
|
||||
{ "Name-Email", pNAMEEMAIL },
|
||||
{ NULL, 0 }
|
||||
};
|
||||
char line[1024], *p;
|
||||
const char *err = NULL;
|
||||
struct para_data_s *para, *r;
|
||||
int i, rc = 0, any = 0;
|
||||
struct reqgen_ctrl_s outctrl;
|
||||
|
||||
memset (&outctrl, 0, sizeof (outctrl));
|
||||
outctrl.writer = writer;
|
||||
|
||||
err = NULL;
|
||||
para = NULL;
|
||||
while (fgets (line, DIM(line)-1, fp) )
|
||||
{
|
||||
char *keyword, *value;
|
||||
|
||||
outctrl.lnr++;
|
||||
if (*line && line[strlen(line)-1] != '\n')
|
||||
{
|
||||
err = "line too long";
|
||||
break;
|
||||
}
|
||||
for (p=line; spacep (p); p++)
|
||||
;
|
||||
if (!*p || *p == '#')
|
||||
continue;
|
||||
|
||||
keyword = p;
|
||||
if (*keyword == '%')
|
||||
{
|
||||
for (; !spacep (p); p++)
|
||||
;
|
||||
if (*p)
|
||||
*p++ = 0;
|
||||
for (; spacep (p); p++)
|
||||
;
|
||||
value = p;
|
||||
trim_trailing_spaces (value);
|
||||
|
||||
if (!ascii_strcasecmp (keyword, "%echo"))
|
||||
log_info ("%s\n", value);
|
||||
else if (!ascii_strcasecmp (keyword, "%dry-run"))
|
||||
outctrl.dryrun = 1;
|
||||
else if (!ascii_strcasecmp( keyword, "%commit"))
|
||||
{
|
||||
rc = proc_parameters (para, &outctrl);
|
||||
if (rc)
|
||||
goto leave;
|
||||
any = 1;
|
||||
release_parameter_list (para);
|
||||
para = NULL;
|
||||
}
|
||||
else
|
||||
log_info ("skipping control `%s' (%s)\n", keyword, value);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!(p = strchr (p, ':')) || p == keyword)
|
||||
{
|
||||
err = "missing colon";
|
||||
break;
|
||||
}
|
||||
if (*p)
|
||||
*p++ = 0;
|
||||
for (; spacep (p); p++)
|
||||
;
|
||||
if (!*p)
|
||||
{
|
||||
err = "missing argument";
|
||||
break;
|
||||
}
|
||||
value = p;
|
||||
trim_trailing_spaces (value);
|
||||
|
||||
for (i=0; (keywords[i].name
|
||||
&& ascii_strcasecmp (keywords[i].name, keyword)); i++)
|
||||
;
|
||||
if (!keywords[i].name)
|
||||
{
|
||||
err = "unknown keyword";
|
||||
break;
|
||||
}
|
||||
if (keywords[i].key != pKEYTYPE && !para)
|
||||
{
|
||||
err = "parameter block does not start with \"Key-Type\"";
|
||||
break;
|
||||
}
|
||||
|
||||
if (keywords[i].key == pKEYTYPE && para)
|
||||
{
|
||||
rc = proc_parameters (para, &outctrl);
|
||||
if (rc)
|
||||
goto leave;
|
||||
any = 1;
|
||||
release_parameter_list (para);
|
||||
para = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (r = para; r && r->key != keywords[i].key; r = r->next)
|
||||
;
|
||||
if (r)
|
||||
{
|
||||
err = "duplicate keyword";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
r = xtrycalloc (1, sizeof *r + strlen( value ));
|
||||
if (!r)
|
||||
{
|
||||
err = "out of core";
|
||||
break;
|
||||
}
|
||||
r->lnr = outctrl.lnr;
|
||||
r->key = keywords[i].key;
|
||||
strcpy (r->u.value, value);
|
||||
r->next = para;
|
||||
para = r;
|
||||
}
|
||||
|
||||
if (err)
|
||||
{
|
||||
log_error ("line %d: %s\n", outctrl.lnr, err);
|
||||
rc = GNUPG_General_Error;
|
||||
}
|
||||
else if (ferror(fp))
|
||||
{
|
||||
log_error ("line %d: read error: %s\n", outctrl.lnr, strerror(errno) );
|
||||
rc = GNUPG_General_Error;
|
||||
}
|
||||
else if (para)
|
||||
{
|
||||
rc = proc_parameters (para, &outctrl);
|
||||
if (rc)
|
||||
goto leave;
|
||||
any = 1;
|
||||
}
|
||||
|
||||
if (!rc && !any)
|
||||
rc = GNUPG_No_Data;
|
||||
|
||||
leave:
|
||||
release_parameter_list (para);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* check whether there are invalid characters in the email address S */
|
||||
static int
|
||||
has_invalid_email_chars (const char *s)
|
||||
{
|
||||
int at_seen=0;
|
||||
static char valid_chars[] = "01234567890_-."
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
for (; *s; s++)
|
||||
{
|
||||
if (*s & 0x80)
|
||||
return 1;
|
||||
if (*s == '@')
|
||||
at_seen++;
|
||||
else if (!at_seen && !( !!strchr (valid_chars, *s) || *s == '+'))
|
||||
return 1;
|
||||
else if (at_seen && !strchr (valid_chars, *s))
|
||||
return 1;
|
||||
}
|
||||
return at_seen != 1;
|
||||
}
|
||||
|
||||
|
||||
/* Check that all required parameters are given and perform the action */
|
||||
static int
|
||||
proc_parameters (struct para_data_s *para, struct reqgen_ctrl_s *outctrl)
|
||||
{
|
||||
struct para_data_s *r;
|
||||
const char *s;
|
||||
int i;
|
||||
unsigned int nbits;
|
||||
char numbuf[20];
|
||||
unsigned char keyparms[100];
|
||||
int rc;
|
||||
KsbaSexp public;
|
||||
|
||||
/* check that we have all required parameters */
|
||||
assert (get_parameter (para, pKEYTYPE));
|
||||
|
||||
/* We can only use RSA for now. There is a with pkcs-10 on how to
|
||||
use ElGamal becuase it is expected that a PK algorithm can always
|
||||
be used for signing. */
|
||||
i = get_parameter_algo (para, pKEYTYPE);
|
||||
if (i < 1 || i != GCRY_PK_RSA )
|
||||
{
|
||||
r = get_parameter (para, pKEYTYPE);
|
||||
log_error ("line %d: invalid algorithm\n", r->lnr);
|
||||
return GNUPG_Invalid_Parameter;
|
||||
}
|
||||
|
||||
/* check the keylength */
|
||||
if (!get_parameter (para, pKEYLENGTH))
|
||||
nbits = 1024;
|
||||
else
|
||||
nbits = get_parameter_uint (para, pKEYLENGTH);
|
||||
if (nbits < 512 || nbits > 4096)
|
||||
{
|
||||
r = get_parameter (para, pKEYTYPE);
|
||||
log_error ("line %d: invalid key length %u (valid are 512 to 4096)\n",
|
||||
r->lnr, nbits);
|
||||
return GNUPG_Invalid_Parameter;
|
||||
}
|
||||
|
||||
/* check the usage */
|
||||
if (parse_parameter_usage (para, pKEYUSAGE))
|
||||
return GNUPG_Invalid_Parameter;
|
||||
|
||||
/* check that there is a subject name and that this DN fits our
|
||||
requirements */
|
||||
if (!(s=get_parameter_value (para, pNAMEDN)))
|
||||
{
|
||||
r = get_parameter (para, pKEYTYPE);
|
||||
log_error ("line %d: no subject name given\n", r->lnr);
|
||||
return GNUPG_Invalid_Parameter;
|
||||
}
|
||||
/* fixme check s */
|
||||
|
||||
/* check that the optional email address is okay */
|
||||
if ((s=get_parameter_value (para, pNAMEEMAIL)))
|
||||
{
|
||||
if (has_invalid_email_chars (s)
|
||||
|| *s == '@'
|
||||
|| s[strlen(s)-1] == '@'
|
||||
|| s[strlen(s)-1] == '.'
|
||||
|| strstr(s, ".."))
|
||||
{
|
||||
r = get_parameter (para, pKEYTYPE);
|
||||
log_error ("line %d: not a valid email address\n", r->lnr);
|
||||
return GNUPG_Invalid_Parameter;
|
||||
}
|
||||
}
|
||||
|
||||
sprintf (numbuf, "%u", nbits);
|
||||
snprintf (keyparms, DIM (keyparms)-1,
|
||||
"(6:genkey(3:rsa(5:nbits%d:%s)))", strlen (numbuf), numbuf);
|
||||
rc = gpgsm_agent_genkey (keyparms, &public);
|
||||
if (rc)
|
||||
{
|
||||
r = get_parameter (para, pKEYTYPE);
|
||||
log_error ("line %d: key generation failed: %s\n",
|
||||
r->lnr, gnupg_strerror (rc));
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = create_request (para, public, outctrl);
|
||||
xfree (public);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* Parameters are checked, the key pair has been created. Now
|
||||
generate the request and write it out */
|
||||
static int
|
||||
create_request (struct para_data_s *para, KsbaConstSexp public,
|
||||
struct reqgen_ctrl_s *outctrl)
|
||||
{
|
||||
KsbaCertreq cr;
|
||||
KsbaError err;
|
||||
GCRY_MD_HD md;
|
||||
KsbaStopReason stopreason;
|
||||
int rc = 0;
|
||||
const char *s;
|
||||
|
||||
cr = ksba_certreq_new ();
|
||||
if (!cr)
|
||||
return seterr (Out_Of_Core);
|
||||
|
||||
md = gcry_md_open (GCRY_MD_SHA1, 0);
|
||||
if (!md)
|
||||
{
|
||||
log_error ("md_open failed: %s\n", gcry_strerror (-1));
|
||||
rc = map_gcry_err (gcry_errno ());
|
||||
goto leave;
|
||||
}
|
||||
if (DBG_HASHING)
|
||||
gcry_md_start_debug (md, "cr.cri");
|
||||
|
||||
ksba_certreq_set_hash_function (cr, HASH_FNC, md);
|
||||
ksba_certreq_set_writer (cr, outctrl->writer);
|
||||
|
||||
err = ksba_certreq_add_subject (cr, get_parameter_value (para, pNAMEDN));
|
||||
if (err)
|
||||
{
|
||||
log_error ("error setting the subject's name: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
s = get_parameter_value (para, pNAMEEMAIL);
|
||||
if (s)
|
||||
{
|
||||
char *buf = xtrymalloc (strlen (s) + 3);
|
||||
|
||||
if (!buf)
|
||||
{
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
goto leave;
|
||||
}
|
||||
*buf = '<';
|
||||
strcpy (buf+1, s);
|
||||
strcat (buf+1, ">");
|
||||
err = ksba_certreq_add_subject (cr, buf);
|
||||
xfree (buf);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error setting the subject's alternate name: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
err = ksba_certreq_set_public_key (cr, public);
|
||||
if (err)
|
||||
{
|
||||
log_error ("error setting the public key: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
err = ksba_certreq_build (cr, &stopreason);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ksba_certreq_build failed: %s\n", ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
if (stopreason == KSBA_SR_NEED_SIG)
|
||||
{
|
||||
GCRY_SEXP s_pkey;
|
||||
size_t n;
|
||||
unsigned char grip[20], hexgrip[41];
|
||||
char *sigval;
|
||||
size_t siglen;
|
||||
|
||||
n = gcry_sexp_canon_len (public, 0, NULL, NULL);
|
||||
if (!n)
|
||||
{
|
||||
log_error ("libksba did not return a proper S-Exp\n");
|
||||
err = GNUPG_Bug;
|
||||
goto leave;
|
||||
}
|
||||
rc = gcry_sexp_sscan (&s_pkey, NULL, public, n);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
|
||||
rc = map_gcry_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
if ( !gcry_pk_get_keygrip (s_pkey, grip) )
|
||||
{
|
||||
rc = seterr (General_Error);
|
||||
log_error ("can't figure out the keygrip\n");
|
||||
gcry_sexp_release (s_pkey);
|
||||
goto leave;
|
||||
}
|
||||
gcry_sexp_release (s_pkey);
|
||||
for (n=0; n < 20; n++)
|
||||
sprintf (hexgrip+n*2, "%02X", grip[n]);
|
||||
|
||||
rc = gpgsm_agent_pksign (hexgrip,
|
||||
gcry_md_read(md, GCRY_MD_SHA1),
|
||||
gcry_md_get_algo_dlen (GCRY_MD_SHA1),
|
||||
GCRY_MD_SHA1,
|
||||
&sigval, &siglen);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("signing failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = ksba_certreq_set_sig_val (cr, sigval);
|
||||
xfree (sigval);
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to store the sig_val: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (stopreason != KSBA_SR_READY);
|
||||
|
||||
|
||||
leave:
|
||||
gcry_md_close (md);
|
||||
ksba_certreq_release (cr);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Create a new key by reading the parameters from in_fd. Multiple
|
||||
keys may be created */
|
||||
int
|
||||
gpgsm_genkey (CTRL ctrl, int in_fd, FILE *out_fp)
|
||||
{
|
||||
int rc;
|
||||
FILE *in_fp;
|
||||
Base64Context b64writer = NULL;
|
||||
KsbaWriter writer;
|
||||
|
||||
in_fp = fdopen (dup (in_fd), "rb");
|
||||
if (!in_fp)
|
||||
{
|
||||
log_error ("fdopen() failed: %s\n", strerror (errno));
|
||||
return seterr (IO_Error);
|
||||
}
|
||||
|
||||
ctrl->pem_name = "NEW CERTIFICATE REQUEST";
|
||||
rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't create writer: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = read_parameters (in_fp, writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("error creating certificate request: %s\n",
|
||||
gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = gpgsm_finish_writer (b64writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("write failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
gpgsm_status (ctrl, STATUS_KEY_CREATED, "P");
|
||||
log_info ("certificate request created\n");
|
||||
|
||||
leave:
|
||||
gpgsm_destroy_writer (b64writer);
|
||||
fclose (in_fp);
|
||||
return rc;
|
||||
}
|
||||
|
502
sm/decrypt.c
502
sm/decrypt.c
@ -1,502 +0,0 @@
|
||||
/* decrypt.c - Decrypt a message
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
struct decrypt_filter_parm_s {
|
||||
int algo;
|
||||
int mode;
|
||||
int blklen;
|
||||
GCRY_CIPHER_HD hd;
|
||||
char iv[16];
|
||||
size_t ivlen;
|
||||
int any_data; /* dod we push anything through the filter at all? */
|
||||
unsigned char lastblock[16]; /* to strip the padding we have to
|
||||
keep this one */
|
||||
char helpblock[16]; /* needed because there is no block buffering in
|
||||
libgcrypt (yet) */
|
||||
int helpblocklen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/* decrypt the session key and fill in the parm structure. The
|
||||
algo and the IV is expected to be already in PARM. */
|
||||
static int
|
||||
prepare_decryption (const char *hexkeygrip, KsbaConstSexp enc_val,
|
||||
struct decrypt_filter_parm_s *parm)
|
||||
{
|
||||
char *seskey = NULL;
|
||||
size_t n, seskeylen;
|
||||
int rc;
|
||||
|
||||
rc = gpgsm_agent_pkdecrypt (hexkeygrip, enc_val,
|
||||
&seskey, &seskeylen);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("error decrypting session key: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex ("pkcs1 encoded session key:", seskey, seskeylen);
|
||||
|
||||
n=0;
|
||||
if (seskeylen == 24)
|
||||
{
|
||||
/* Smells like a 3-des key. This might happen because a SC has
|
||||
already done the unpacking. fixme! */
|
||||
}
|
||||
else
|
||||
{
|
||||
if (n + 7 > seskeylen )
|
||||
{
|
||||
rc = seterr (Invalid_Session_Key);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* FIXME: Actually the leading zero is required but due to the way
|
||||
we encode the output in libgcrypt as an MPI we are not able to
|
||||
encode that leading zero. However, when using a Smartcard we are
|
||||
doing it the rightway and therefore we have to skip the zero. This
|
||||
should be fixed in gpg-agent of course. */
|
||||
if (!seskey[n])
|
||||
n++;
|
||||
|
||||
if (seskey[n] != 2 ) /* wrong block type version */
|
||||
{
|
||||
rc = seterr (Invalid_Session_Key);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
for (n++; n < seskeylen && seskey[n]; n++) /* skip the random bytes */
|
||||
;
|
||||
n++; /* and the zero byte */
|
||||
if (n >= seskeylen )
|
||||
{
|
||||
rc = seterr (Invalid_Session_Key);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
if (DBG_CRYPTO)
|
||||
log_printhex ("session key:", seskey+n, seskeylen-n);
|
||||
|
||||
parm->hd = gcry_cipher_open (parm->algo, parm->mode, 0);
|
||||
if (!parm->hd)
|
||||
{
|
||||
rc = gcry_errno ();
|
||||
log_error ("error creating decryptor: %s\n", gcry_strerror (rc));
|
||||
rc = map_gcry_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = gcry_cipher_setkey (parm->hd, seskey+n, seskeylen-n);
|
||||
if (rc == GCRYERR_WEAK_KEY)
|
||||
{
|
||||
log_info (_("WARNING: message was encrypted with "
|
||||
"a weak key in the symmetric cipher.\n"));
|
||||
rc = 0;
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
log_error("key setup failed: %s\n", gcry_strerror(rc) );
|
||||
rc = map_gcry_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
gcry_cipher_setiv (parm->hd, parm->iv, parm->ivlen);
|
||||
|
||||
leave:
|
||||
xfree (seskey);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/* This function is called by the KSBA writer just before the actual
|
||||
write is done. The function must take INLEN bytes from INBUF,
|
||||
decrypt it and store it inoutbuf which has a maximum size of
|
||||
maxoutlen. The valid bytes in outbuf should be return in outlen.
|
||||
Due to different buffer sizes or different length of input and
|
||||
output, it may happen that fewer bytes are process or fewer bytes
|
||||
are written. */
|
||||
static KsbaError
|
||||
decrypt_filter (void *arg,
|
||||
const void *inbuf, size_t inlen, size_t *inused,
|
||||
void *outbuf, size_t maxoutlen, size_t *outlen)
|
||||
{
|
||||
struct decrypt_filter_parm_s *parm = arg;
|
||||
int blklen = parm->blklen;
|
||||
size_t orig_inlen = inlen;
|
||||
|
||||
/* fixme: Should we issue an error when we have not seen one full block? */
|
||||
if (!inlen)
|
||||
return KSBA_Bug;
|
||||
|
||||
if (maxoutlen < 2*parm->blklen)
|
||||
return KSBA_Bug;
|
||||
/* make some space becuase we will later need an extra block at the end */
|
||||
maxoutlen -= blklen;
|
||||
|
||||
if (parm->helpblocklen)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i=parm->helpblocklen,j=0; i < blklen && j < inlen; i++, j++)
|
||||
parm->helpblock[i] = ((const char*)inbuf)[j];
|
||||
inlen -= j;
|
||||
if (blklen > maxoutlen)
|
||||
return KSBA_Bug;
|
||||
if (i < blklen)
|
||||
{
|
||||
parm->helpblocklen = i;
|
||||
*outlen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
parm->helpblocklen = 0;
|
||||
if (parm->any_data)
|
||||
{
|
||||
memcpy (outbuf, parm->lastblock, blklen);
|
||||
*outlen =blklen;
|
||||
}
|
||||
else
|
||||
*outlen = 0;
|
||||
gcry_cipher_decrypt (parm->hd, parm->lastblock, blklen,
|
||||
parm->helpblock, blklen);
|
||||
parm->any_data = 1;
|
||||
}
|
||||
*inused = orig_inlen - inlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (inlen > maxoutlen)
|
||||
inlen = maxoutlen;
|
||||
if (inlen % blklen)
|
||||
{ /* store the remainder away */
|
||||
parm->helpblocklen = inlen%blklen;
|
||||
inlen = inlen/blklen*blklen;
|
||||
memcpy (parm->helpblock, (const char*)inbuf+inlen, parm->helpblocklen);
|
||||
}
|
||||
|
||||
*inused = inlen + parm->helpblocklen;
|
||||
if (inlen)
|
||||
{
|
||||
assert (inlen >= blklen);
|
||||
if (parm->any_data)
|
||||
{
|
||||
gcry_cipher_decrypt (parm->hd, (char*)outbuf+blklen, inlen,
|
||||
inbuf, inlen);
|
||||
memcpy (outbuf, parm->lastblock, blklen);
|
||||
memcpy (parm->lastblock,(char*)outbuf+inlen, blklen);
|
||||
*outlen = inlen;
|
||||
}
|
||||
else
|
||||
{
|
||||
gcry_cipher_decrypt (parm->hd, outbuf, inlen, inbuf, inlen);
|
||||
memcpy (parm->lastblock, (char*)outbuf+inlen-blklen, blklen);
|
||||
*outlen = inlen - blklen;
|
||||
parm->any_data = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
*outlen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Perform a decrypt operation. */
|
||||
int
|
||||
gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp)
|
||||
{
|
||||
int rc;
|
||||
KsbaError err;
|
||||
Base64Context b64reader = NULL;
|
||||
Base64Context b64writer = NULL;
|
||||
KsbaReader reader;
|
||||
KsbaWriter writer;
|
||||
KsbaCMS cms = NULL;
|
||||
KsbaStopReason stopreason;
|
||||
KEYDB_HANDLE kh;
|
||||
int recp;
|
||||
FILE *in_fp = NULL;
|
||||
struct decrypt_filter_parm_s dfparm;
|
||||
|
||||
memset (&dfparm, 0, sizeof dfparm);
|
||||
|
||||
kh = keydb_new (0);
|
||||
if (!kh)
|
||||
{
|
||||
log_error (_("failed to allocated keyDB handle\n"));
|
||||
rc = GNUPG_General_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
in_fp = fdopen ( dup (in_fd), "rb");
|
||||
if (!in_fp)
|
||||
{
|
||||
log_error ("fdopen() failed: %s\n", strerror (errno));
|
||||
rc = seterr (IO_Error);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = gpgsm_create_reader (&b64reader, ctrl, in_fp, &reader);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't create reader: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't create writer: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
cms = ksba_cms_new ();
|
||||
if (!cms)
|
||||
{
|
||||
rc = seterr (Out_Of_Core);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = ksba_cms_set_reader_writer (cms, reader, writer);
|
||||
if (err)
|
||||
{
|
||||
log_debug ("ksba_cms_set_reader_writer failed: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* parser loop */
|
||||
do
|
||||
{
|
||||
err = ksba_cms_parse (cms, &stopreason);
|
||||
if (err)
|
||||
{
|
||||
log_debug ("ksba_cms_parse failed: %s\n", ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (stopreason == KSBA_SR_BEGIN_DATA
|
||||
|| stopreason == KSBA_SR_DETACHED_DATA)
|
||||
{
|
||||
int algo, mode;
|
||||
const char *algoid;
|
||||
int any_key = 0;
|
||||
|
||||
algoid = ksba_cms_get_content_oid (cms, 2/* encryption algo*/);
|
||||
algo = gcry_cipher_map_name (algoid);
|
||||
mode = gcry_cipher_mode_from_oid (algoid);
|
||||
if (!algo || !mode)
|
||||
{
|
||||
rc = GNUPG_Unsupported_Algorithm;
|
||||
log_error ("unsupported algorithm `%s'\n", algoid? algoid:"?");
|
||||
if (algoid && !strcmp (algoid, "1.2.840.113549.3.2"))
|
||||
log_info (_("(this is the RC2 algorithm)\n"));
|
||||
else if (!algoid)
|
||||
log_info (_("(this does not seem to be an encrypted"
|
||||
" message)\n"));
|
||||
gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.algorithm",
|
||||
gnupg_error_token (rc), algoid?algoid:"?", NULL);
|
||||
goto leave;
|
||||
}
|
||||
dfparm.algo = algo;
|
||||
dfparm.mode = mode;
|
||||
dfparm.blklen = gcry_cipher_get_algo_blklen (algo);
|
||||
if (dfparm.blklen > sizeof (dfparm.helpblock))
|
||||
return GNUPG_Bug;
|
||||
|
||||
rc = ksba_cms_get_content_enc_iv (cms,
|
||||
dfparm.iv,
|
||||
sizeof (dfparm.iv),
|
||||
&dfparm.ivlen);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("error getting IV: %s\n", ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
for (recp=0; !any_key; recp++)
|
||||
{
|
||||
char *issuer;
|
||||
KsbaSexp serial;
|
||||
KsbaSexp enc_val;
|
||||
char *hexkeygrip = NULL;
|
||||
|
||||
err = ksba_cms_get_issuer_serial (cms, recp, &issuer, &serial);
|
||||
if (err == -1 && recp)
|
||||
break; /* no more recipients */
|
||||
if (err)
|
||||
log_error ("recp %d - error getting info: %s\n",
|
||||
recp, ksba_strerror (err));
|
||||
else
|
||||
{
|
||||
KsbaCert cert = NULL;
|
||||
|
||||
log_debug ("recp %d - issuer: `%s'\n",
|
||||
recp, issuer? issuer:"[NONE]");
|
||||
log_debug ("recp %d - serial: ", recp);
|
||||
gpgsm_dump_serial (serial);
|
||||
log_printf ("\n");
|
||||
|
||||
keydb_search_reset (kh);
|
||||
rc = keydb_search_issuer_sn (kh, issuer, serial);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to find the certificate: %s\n",
|
||||
gnupg_strerror(rc));
|
||||
goto oops;
|
||||
}
|
||||
|
||||
rc = keydb_get_cert (kh, &cert);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to get cert: %s\n", gnupg_strerror (rc));
|
||||
goto oops;
|
||||
}
|
||||
/* Just in case there is a problem with the own
|
||||
certificate we print this message - should never
|
||||
happen of course */
|
||||
rc = gpgsm_cert_use_decrypt_p (cert);
|
||||
if (rc)
|
||||
{
|
||||
gpgsm_status2 (ctrl, STATUS_ERROR, "decrypt.keyusage",
|
||||
gnupg_error_token (rc), NULL);
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
hexkeygrip = gpgsm_get_keygrip_hexstring (cert);
|
||||
|
||||
oops:
|
||||
xfree (issuer);
|
||||
xfree (serial);
|
||||
ksba_cert_release (cert);
|
||||
}
|
||||
|
||||
if (!hexkeygrip)
|
||||
;
|
||||
else if (!(enc_val = ksba_cms_get_enc_val (cms, recp)))
|
||||
log_error ("recp %d - error getting encrypted session key\n",
|
||||
recp);
|
||||
else
|
||||
{
|
||||
rc = prepare_decryption (hexkeygrip, enc_val, &dfparm);
|
||||
xfree (enc_val);
|
||||
if (rc)
|
||||
{
|
||||
log_debug ("decrypting session key failed: %s\n",
|
||||
gnupg_strerror (rc));
|
||||
}
|
||||
else
|
||||
{ /* setup the bulk decrypter */
|
||||
any_key = 1;
|
||||
ksba_writer_set_filter (writer,
|
||||
decrypt_filter,
|
||||
&dfparm);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!any_key)
|
||||
{
|
||||
rc = GNUPG_No_Secret_Key;
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else if (stopreason == KSBA_SR_END_DATA)
|
||||
{
|
||||
ksba_writer_set_filter (writer, NULL, NULL);
|
||||
if (dfparm.any_data)
|
||||
{ /* write the last block with padding removed */
|
||||
int i, npadding = dfparm.lastblock[dfparm.blklen-1];
|
||||
if (!npadding || npadding > dfparm.blklen)
|
||||
{
|
||||
log_error ("invalid padding with value %d\n", npadding);
|
||||
rc = seterr (Invalid_Data);
|
||||
goto leave;
|
||||
}
|
||||
rc = ksba_writer_write (writer,
|
||||
dfparm.lastblock,
|
||||
dfparm.blklen - npadding);
|
||||
if (rc)
|
||||
{
|
||||
rc = map_ksba_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
for (i=dfparm.blklen - npadding; i < dfparm.blklen; i++)
|
||||
{
|
||||
if (dfparm.lastblock[i] != npadding)
|
||||
{
|
||||
log_error ("inconsistent padding\n");
|
||||
rc = seterr (Invalid_Data);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
while (stopreason != KSBA_SR_READY);
|
||||
|
||||
rc = gpgsm_finish_writer (b64writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("write failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
gpgsm_status (ctrl, STATUS_DECRYPTION_OKAY, NULL);
|
||||
|
||||
|
||||
leave:
|
||||
if (rc)
|
||||
gpgsm_status (ctrl, STATUS_DECRYPTION_FAILED, NULL);
|
||||
ksba_cms_release (cms);
|
||||
gpgsm_destroy_reader (b64reader);
|
||||
gpgsm_destroy_writer (b64writer);
|
||||
keydb_release (kh);
|
||||
if (in_fp)
|
||||
fclose (in_fp);
|
||||
if (dfparm.hd)
|
||||
gcry_cipher_close (dfparm.hd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
165
sm/delete.c
165
sm/delete.c
@ -1,165 +0,0 @@
|
||||
/* delete.c
|
||||
* 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
/* Delete a certificate or an secret key from a key database. */
|
||||
static int
|
||||
delete_one (CTRL ctrl, const char *username)
|
||||
{
|
||||
int rc = 0;
|
||||
KEYDB_SEARCH_DESC desc;
|
||||
KEYDB_HANDLE kh = NULL;
|
||||
KsbaCert cert = NULL;
|
||||
int duplicates = 0;
|
||||
|
||||
rc = keydb_classify_name (username, &desc);
|
||||
if (rc)
|
||||
{
|
||||
log_error (_("certificate `%s' not found: %s\n"),
|
||||
username, gnupg_strerror (rc));
|
||||
gpgsm_status2 (ctrl, STATUS_DELETE_PROBLEM, "1", NULL);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
kh = keydb_new (0);
|
||||
if (!kh)
|
||||
{
|
||||
log_error ("keydb_new failed\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
rc = keydb_search (kh, &desc, 1);
|
||||
if (!rc)
|
||||
rc = keydb_get_cert (kh, &cert);
|
||||
if (!rc)
|
||||
{
|
||||
char fpr[20];
|
||||
|
||||
gpgsm_get_fingerprint (cert, 0, fpr, NULL);
|
||||
|
||||
next_ambigious:
|
||||
rc = keydb_search (kh, &desc, 1);
|
||||
if (rc == -1)
|
||||
rc = 0;
|
||||
else if (!rc)
|
||||
{
|
||||
KsbaCert cert2 = NULL;
|
||||
char fpr2[20];
|
||||
|
||||
/* We ignore all duplicated certificates which might have
|
||||
been inserted due to program bugs. */
|
||||
if (!keydb_get_cert (kh, &cert2))
|
||||
{
|
||||
gpgsm_get_fingerprint (cert2, 0, fpr2, NULL);
|
||||
ksba_cert_release (cert2);
|
||||
if (!memcmp (fpr, fpr2, 20))
|
||||
{
|
||||
duplicates++;
|
||||
goto next_ambigious;
|
||||
}
|
||||
}
|
||||
rc = GNUPG_Ambiguous_Name;
|
||||
}
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
if (rc == -1)
|
||||
rc = GNUPG_No_Public_Key;
|
||||
log_error (_("certificate `%s' not found: %s\n"),
|
||||
username, gnupg_strerror (rc));
|
||||
gpgsm_status2 (ctrl, STATUS_DELETE_PROBLEM, "3", NULL);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* we need to search again to get back to the right position. */
|
||||
do
|
||||
{
|
||||
keydb_search_reset (kh);
|
||||
rc = keydb_search (kh, &desc, 1);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("problem re-searching certificate: %s\n",
|
||||
gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
rc = keydb_delete (kh);
|
||||
if (rc)
|
||||
goto leave;
|
||||
if (opt.verbose)
|
||||
{
|
||||
if (duplicates)
|
||||
log_info (_("duplicated certificate `%s' deleted\n"), username);
|
||||
else
|
||||
log_info (_("certificate `%s' deleted\n"), username);
|
||||
}
|
||||
}
|
||||
while (duplicates--);
|
||||
|
||||
leave:
|
||||
keydb_release (kh);
|
||||
ksba_cert_release (cert);
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Delete the certificates specified by NAMES. */
|
||||
int
|
||||
gpgsm_delete (CTRL ctrl, STRLIST names)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (!names)
|
||||
{
|
||||
log_error ("nothing to delete\n");
|
||||
return GNUPG_No_Data;
|
||||
}
|
||||
|
||||
for (; names; names=names->next )
|
||||
{
|
||||
rc = delete_one (ctrl, names->d);
|
||||
if (rc)
|
||||
{
|
||||
log_error (_("deleting certificate \"%s\" failed: %s\n"),
|
||||
names->d, gnupg_strerror (rc) );
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
549
sm/encrypt.c
549
sm/encrypt.c
@ -1,549 +0,0 @@
|
||||
/* encrypt.c - Encrypt a message
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
#include "i18n.h"
|
||||
|
||||
|
||||
struct dek_s {
|
||||
const char *algoid;
|
||||
int algo;
|
||||
GCRY_CIPHER_HD chd;
|
||||
char key[32];
|
||||
int keylen;
|
||||
char iv[32];
|
||||
int ivlen;
|
||||
};
|
||||
typedef struct dek_s *DEK;
|
||||
|
||||
struct encrypt_cb_parm_s {
|
||||
FILE *fp;
|
||||
DEK dek;
|
||||
int eof_seen;
|
||||
int ready;
|
||||
int readerror;
|
||||
int bufsize;
|
||||
unsigned char *buffer;
|
||||
int buflen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* initialize the data encryptionkey (session key) */
|
||||
static int
|
||||
init_dek (DEK dek)
|
||||
{
|
||||
int rc=0, mode, i;
|
||||
|
||||
dek->algo = gcry_cipher_map_name (dek->algoid);
|
||||
mode = gcry_cipher_mode_from_oid (dek->algoid);
|
||||
if (!dek->algo || !mode)
|
||||
{
|
||||
log_error ("unsupported algorithm `%s'\n", dek->algoid);
|
||||
return GNUPG_Unsupported_Algorithm;
|
||||
}
|
||||
|
||||
dek->keylen = gcry_cipher_get_algo_keylen (dek->algo);
|
||||
if (!dek->keylen || dek->keylen > sizeof (dek->key))
|
||||
return GNUPG_Bug;
|
||||
|
||||
dek->ivlen = gcry_cipher_get_algo_blklen (dek->algo);
|
||||
if (!dek->ivlen || dek->ivlen > sizeof (dek->iv))
|
||||
return GNUPG_Bug;
|
||||
|
||||
if (dek->keylen < 100/8)
|
||||
{ /* make sure we don't use weak keys */
|
||||
log_error ("key length of `%s' too small\n", dek->algoid);
|
||||
return GNUPG_Unsupported_Algorithm;
|
||||
}
|
||||
|
||||
dek->chd = gcry_cipher_open (dek->algo, mode, GCRY_CIPHER_SECURE);
|
||||
if (!dek->chd)
|
||||
{
|
||||
log_error ("failed to create cipher context: %s\n", gcry_strerror (-1));
|
||||
return GNUPG_General_Error;
|
||||
}
|
||||
|
||||
for (i=0; i < 8; i++)
|
||||
{
|
||||
gcry_randomize (dek->key, dek->keylen, GCRY_STRONG_RANDOM );
|
||||
rc = gcry_cipher_setkey (dek->chd, dek->key, dek->keylen);
|
||||
if (rc != GCRYERR_WEAK_KEY)
|
||||
break;
|
||||
log_info(_("weak key created - retrying\n") );
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to set the key: %s\n", gcry_strerror (rc));
|
||||
gcry_cipher_close (dek->chd);
|
||||
dek->chd = NULL;
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
gcry_randomize (dek->iv, dek->ivlen, GCRY_STRONG_RANDOM);
|
||||
rc = gcry_cipher_setiv (dek->chd, dek->iv, dek->ivlen);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to set the IV: %s\n", gcry_strerror (rc));
|
||||
gcry_cipher_close (dek->chd);
|
||||
dek->chd = NULL;
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Encode the session key. NBITS is the number of bits which should be
|
||||
used for packing the session key. returns: An mpi with the session
|
||||
key (caller must free) */
|
||||
static GCRY_MPI
|
||||
encode_session_key (DEK dek, unsigned int nbits)
|
||||
{
|
||||
int nframe = (nbits+7) / 8;
|
||||
byte *p;
|
||||
byte *frame;
|
||||
int i,n;
|
||||
MPI a;
|
||||
|
||||
if (dek->keylen + 7 > nframe || !nframe)
|
||||
log_bug ("can't encode a %d bit key in a %d bits frame\n",
|
||||
dek->keylen*8, nbits );
|
||||
|
||||
/* We encode the session key in this way:
|
||||
*
|
||||
* 0 2 RND(n bytes) 0 KEY(k bytes)
|
||||
*
|
||||
* (But how can we store the leading 0 - the external representaion
|
||||
* of MPIs doesn't allow leading zeroes =:-)
|
||||
*
|
||||
* RND are non-zero random bytes.
|
||||
* KEY is the encryption key (session key)
|
||||
*/
|
||||
|
||||
frame = gcry_xmalloc_secure (nframe);
|
||||
n = 0;
|
||||
frame[n++] = 0;
|
||||
frame[n++] = 2;
|
||||
i = nframe - 3 - dek->keylen;
|
||||
assert (i > 0);
|
||||
p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM);
|
||||
/* replace zero bytes by new values */
|
||||
for (;;)
|
||||
{
|
||||
int j, k;
|
||||
byte *pp;
|
||||
|
||||
/* count the zero bytes */
|
||||
for(j=k=0; j < i; j++ )
|
||||
{
|
||||
if( !p[j] )
|
||||
k++;
|
||||
}
|
||||
if( !k )
|
||||
break; /* okay: no zero bytes */
|
||||
|
||||
k += k/128; /* better get some more */
|
||||
pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM);
|
||||
for (j=0; j < i && k; j++)
|
||||
{
|
||||
if( !p[j] )
|
||||
p[j] = pp[--k];
|
||||
}
|
||||
xfree (pp);
|
||||
}
|
||||
memcpy (frame+n, p, i);
|
||||
xfree (p);
|
||||
|
||||
n += i;
|
||||
frame[n++] = 0;
|
||||
memcpy (frame+n, dek->key, dek->keylen);
|
||||
n += dek->keylen;
|
||||
assert (n == nframe);
|
||||
if (gcry_mpi_scan (&a, GCRYMPI_FMT_USG, frame, &nframe) )
|
||||
BUG ();
|
||||
gcry_free(frame);
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* encrypt the DEK under the key contained in CERT and return it as a
|
||||
canonical S-Exp in encval */
|
||||
static int
|
||||
encrypt_dek (const DEK dek, KsbaCert cert, char **encval)
|
||||
{
|
||||
GCRY_SEXP s_ciph, s_data, s_pkey;
|
||||
int rc;
|
||||
KsbaSexp buf;
|
||||
size_t len;
|
||||
|
||||
*encval = NULL;
|
||||
|
||||
/* get the key from the cert */
|
||||
buf = ksba_cert_get_public_key (cert);
|
||||
if (!buf)
|
||||
{
|
||||
log_error ("no public key for recipient\n");
|
||||
return GNUPG_No_Public_Key;
|
||||
}
|
||||
len = gcry_sexp_canon_len (buf, 0, NULL, NULL);
|
||||
if (!len)
|
||||
{
|
||||
log_error ("libksba did not return a proper S-Exp\n");
|
||||
return GNUPG_Bug;
|
||||
}
|
||||
rc = gcry_sexp_sscan (&s_pkey, NULL, buf, len);
|
||||
xfree (buf); buf = NULL;
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
|
||||
return map_gcry_err (rc);
|
||||
}
|
||||
|
||||
/* put the encoded cleartext into a simple list */
|
||||
{
|
||||
/* fixme: actually the pkcs-1 encoding should go into libgcrypt */
|
||||
GCRY_MPI data = encode_session_key (dek, gcry_pk_get_nbits (s_pkey));
|
||||
if (!data)
|
||||
{
|
||||
gcry_mpi_release (data);
|
||||
return GNUPG_General_Error;
|
||||
}
|
||||
if (gcry_sexp_build (&s_data, NULL, "%m", data))
|
||||
BUG ();
|
||||
gcry_mpi_release (data);
|
||||
}
|
||||
|
||||
/* pass it to libgcrypt */
|
||||
rc = gcry_pk_encrypt (&s_ciph, s_data, s_pkey);
|
||||
gcry_sexp_release (s_data);
|
||||
gcry_sexp_release (s_pkey);
|
||||
|
||||
/* reformat it */
|
||||
len = gcry_sexp_sprint (s_ciph, GCRYSEXP_FMT_CANON, NULL, 0);
|
||||
assert (len);
|
||||
buf = xtrymalloc (len);
|
||||
if (!buf)
|
||||
{
|
||||
gcry_sexp_release (s_ciph);
|
||||
return GNUPG_Out_Of_Core;
|
||||
}
|
||||
len = gcry_sexp_sprint (s_ciph, GCRYSEXP_FMT_CANON, buf, len);
|
||||
assert (len);
|
||||
|
||||
*encval = buf;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* do the actual encryption */
|
||||
static int
|
||||
encrypt_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
|
||||
{
|
||||
struct encrypt_cb_parm_s *parm = cb_value;
|
||||
int blklen = parm->dek->ivlen;
|
||||
unsigned char *p;
|
||||
size_t n;
|
||||
|
||||
*nread = 0;
|
||||
if (!buffer)
|
||||
return -1; /* not supported */
|
||||
|
||||
if (parm->ready)
|
||||
return -1;
|
||||
|
||||
if (count < blklen)
|
||||
BUG ();
|
||||
|
||||
if (!parm->eof_seen)
|
||||
{ /* fillup the buffer */
|
||||
p = parm->buffer;
|
||||
for (n=parm->buflen; n < parm->bufsize; n++)
|
||||
{
|
||||
int c = getc (parm->fp);
|
||||
if (c == EOF)
|
||||
{
|
||||
if (ferror (parm->fp))
|
||||
{
|
||||
parm->readerror = errno;
|
||||
return -1;
|
||||
}
|
||||
parm->eof_seen = 1;
|
||||
break;
|
||||
}
|
||||
p[n] = c;
|
||||
}
|
||||
parm->buflen = n;
|
||||
}
|
||||
|
||||
n = parm->buflen < count? parm->buflen : count;
|
||||
n = n/blklen * blklen;
|
||||
if (n)
|
||||
{ /* encrypt the stuff */
|
||||
gcry_cipher_encrypt (parm->dek->chd, buffer, n, parm->buffer, n);
|
||||
*nread = n;
|
||||
/* Who cares about cycles, take the easy way and shift the buffer */
|
||||
parm->buflen -= n;
|
||||
memmove (parm->buffer, parm->buffer+n, parm->buflen);
|
||||
}
|
||||
else if (parm->eof_seen)
|
||||
{ /* no complete block but eof: add padding */
|
||||
/* fixme: we should try to do this also in the above code path */
|
||||
int i, npad = blklen - (parm->buflen % blklen);
|
||||
p = parm->buffer;
|
||||
for (n=parm->buflen, i=0; n < parm->bufsize && i < npad; n++, i++)
|
||||
p[n] = npad;
|
||||
gcry_cipher_encrypt (parm->dek->chd, buffer, n, parm->buffer, n);
|
||||
*nread = n;
|
||||
parm->ready = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* Perform an encrypt operation.
|
||||
|
||||
Encrypt the data received on DATA-FD and write it to OUT_FP. The
|
||||
recipients are take from the certificate given in recplist; if this
|
||||
is NULL it will be encrypted for a default recipient */
|
||||
int
|
||||
gpgsm_encrypt (CTRL ctrl, CERTLIST recplist, int data_fd, FILE *out_fp)
|
||||
{
|
||||
int rc = 0;
|
||||
Base64Context b64writer = NULL;
|
||||
KsbaError err;
|
||||
KsbaWriter writer;
|
||||
KsbaReader reader = NULL;
|
||||
KsbaCMS cms = NULL;
|
||||
KsbaStopReason stopreason;
|
||||
KEYDB_HANDLE kh = NULL;
|
||||
struct encrypt_cb_parm_s encparm;
|
||||
DEK dek = NULL;
|
||||
int recpno;
|
||||
FILE *data_fp = NULL;
|
||||
CERTLIST cl;
|
||||
|
||||
memset (&encparm, 0, sizeof encparm);
|
||||
|
||||
if (!recplist)
|
||||
{
|
||||
log_error(_("no valid recipients given\n"));
|
||||
gpgsm_status (ctrl, STATUS_NO_RECP, "0");
|
||||
rc = GNUPG_No_Public_Key;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
kh = keydb_new (0);
|
||||
if (!kh)
|
||||
{
|
||||
log_error (_("failed to allocated keyDB handle\n"));
|
||||
rc = GNUPG_General_Error;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
data_fp = fdopen ( dup (data_fd), "rb");
|
||||
if (!data_fp)
|
||||
{
|
||||
log_error ("fdopen() failed: %s\n", strerror (errno));
|
||||
rc = seterr (IO_Error);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
reader = ksba_reader_new ();
|
||||
if (!reader)
|
||||
rc = KSBA_Out_Of_Core;
|
||||
if (!rc)
|
||||
rc = ksba_reader_set_cb (reader, encrypt_cb, &encparm);
|
||||
if (rc)
|
||||
{
|
||||
rc = map_ksba_err (rc);
|
||||
goto leave;
|
||||
}
|
||||
encparm.fp = data_fp;
|
||||
|
||||
ctrl->pem_name = "ENCRYPTED MESSAGE";
|
||||
rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, &writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't create writer: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
cms = ksba_cms_new ();
|
||||
if (!cms)
|
||||
{
|
||||
rc = seterr (Out_Of_Core);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = ksba_cms_set_reader_writer (cms, reader, writer);
|
||||
if (err)
|
||||
{
|
||||
log_debug ("ksba_cms_set_reader_writer failed: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* We are going to create enveloped data with uninterpreted data as
|
||||
inner content */
|
||||
err = ksba_cms_set_content_type (cms, 0, KSBA_CT_ENVELOPED_DATA);
|
||||
if (!err)
|
||||
err = ksba_cms_set_content_type (cms, 1, KSBA_CT_DATA);
|
||||
if (err)
|
||||
{
|
||||
log_debug ("ksba_cms_set_content_type failed: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* create a session key */
|
||||
dek = xtrycalloc (1, sizeof *dek); /* hmmm: should we put it into secmem?*/
|
||||
if (!dek)
|
||||
rc = GNUPG_Out_Of_Core;
|
||||
else
|
||||
{
|
||||
dek->algoid = opt.def_cipher_algoid;
|
||||
rc = init_dek (dek);
|
||||
}
|
||||
if (rc)
|
||||
{
|
||||
log_error ("failed to create the session key: %s\n",
|
||||
gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = ksba_cms_set_content_enc_algo (cms, dek->algoid, dek->iv, dek->ivlen);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ksba_cms_set_content_enc_algo failed: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
encparm.dek = dek;
|
||||
/* Use a ~8k (AES) or ~4k (3DES) buffer */
|
||||
encparm.bufsize = 500 * dek->ivlen;
|
||||
encparm.buffer = xtrymalloc (encparm.bufsize);
|
||||
if (!encparm.buffer)
|
||||
{
|
||||
rc = seterr (Out_Of_Core);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* gather certificates of recipients, encrypt the session key for
|
||||
each and store them in the CMS object */
|
||||
for (recpno = 0, cl = recplist; cl; recpno++, cl = cl->next)
|
||||
{
|
||||
char *encval;
|
||||
|
||||
rc = encrypt_dek (dek, cl->cert, &encval);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("encryption failed for recipient no. %d: %s\n",
|
||||
recpno, gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = ksba_cms_add_recipient (cms, cl->cert);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ksba_cms_add_recipient failed: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
xfree (encval);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
err = ksba_cms_set_enc_val (cms, recpno, encval);
|
||||
xfree (encval);
|
||||
if (err)
|
||||
{
|
||||
log_error ("ksba_cms_set_enc_val failed: %s\n",
|
||||
ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
/* main control loop for encryption */
|
||||
recpno = 0;
|
||||
do
|
||||
{
|
||||
err = ksba_cms_build (cms, &stopreason);
|
||||
if (err)
|
||||
{
|
||||
log_debug ("ksba_cms_build failed: %s\n", ksba_strerror (err));
|
||||
rc = map_ksba_err (err);
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
while (stopreason != KSBA_SR_READY);
|
||||
|
||||
if (encparm.readerror)
|
||||
{
|
||||
log_error ("error reading input: %s\n", strerror (encparm.readerror));
|
||||
rc = seterr (Read_Error);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
|
||||
rc = gpgsm_finish_writer (b64writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("write failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
log_info ("encrypted data created\n");
|
||||
|
||||
leave:
|
||||
ksba_cms_release (cms);
|
||||
gpgsm_destroy_writer (b64writer);
|
||||
ksba_reader_release (reader);
|
||||
keydb_release (kh);
|
||||
xfree (dek);
|
||||
if (data_fp)
|
||||
fclose (data_fp);
|
||||
xfree (encparm.buffer);
|
||||
return rc;
|
||||
}
|
248
sm/export.c
248
sm/export.c
@ -1,248 +0,0 @@
|
||||
/* export.c
|
||||
* 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 <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
#include "keydb.h"
|
||||
|
||||
static void print_short_info (KsbaCert cert, FILE *fp);
|
||||
|
||||
|
||||
|
||||
/* Export all certificates or just those given in NAMES. */
|
||||
void
|
||||
gpgsm_export (CTRL ctrl, STRLIST names, FILE *fp)
|
||||
{
|
||||
KEYDB_HANDLE hd;
|
||||
KEYDB_SEARCH_DESC *desc = NULL;
|
||||
int ndesc;
|
||||
Base64Context b64writer = NULL;
|
||||
KsbaWriter writer;
|
||||
STRLIST sl;
|
||||
KsbaCert cert = NULL;
|
||||
int rc=0;
|
||||
int count = 0;
|
||||
int i;
|
||||
|
||||
hd = keydb_new (0);
|
||||
if (!hd)
|
||||
{
|
||||
log_error ("keydb_new failed\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!names)
|
||||
ndesc = 1;
|
||||
else
|
||||
{
|
||||
for (sl=names, ndesc=0; sl; sl = sl->next, ndesc++)
|
||||
;
|
||||
}
|
||||
|
||||
desc = xtrycalloc (ndesc, sizeof *desc);
|
||||
if (!ndesc)
|
||||
{
|
||||
log_error ("%s\n", gnupg_strerror (GNUPG_Out_Of_Core));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (!names)
|
||||
desc[0].mode = KEYDB_SEARCH_MODE_FIRST;
|
||||
else
|
||||
{
|
||||
for (ndesc=0, sl=names; sl; sl = sl->next)
|
||||
{
|
||||
rc = keydb_classify_name (sl->d, desc+ndesc);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("key `%s' not found: %s\n",
|
||||
sl->d, gnupg_strerror (rc));
|
||||
rc = 0;
|
||||
}
|
||||
else
|
||||
ndesc++;
|
||||
}
|
||||
}
|
||||
|
||||
/* If all specifications are done by fingerprint, we switch to
|
||||
ephemeral mode so that _all_ currently available and matching
|
||||
certificates are exported.
|
||||
|
||||
fixme: we should in this case keep a list of certificates to
|
||||
avoid accidential export of duplicate certificates. */
|
||||
if (names && ndesc)
|
||||
{
|
||||
for (i=0; (i < ndesc
|
||||
&& (desc[i].mode == KEYDB_SEARCH_MODE_FPR
|
||||
|| desc[i].mode == KEYDB_SEARCH_MODE_FPR20
|
||||
|| desc[i].mode == KEYDB_SEARCH_MODE_FPR16)); i++)
|
||||
;
|
||||
if (i == ndesc)
|
||||
keydb_set_ephemeral (hd, 1);
|
||||
}
|
||||
|
||||
while (!(rc = keydb_search (hd, desc, ndesc)))
|
||||
{
|
||||
const unsigned char *image;
|
||||
size_t imagelen;
|
||||
|
||||
if (!names)
|
||||
desc[0].mode = KEYDB_SEARCH_MODE_NEXT;
|
||||
|
||||
rc = keydb_get_cert (hd, &cert);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("keydb_get_cert failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
image = ksba_cert_get_image (cert, &imagelen);
|
||||
if (!image)
|
||||
{
|
||||
log_error ("ksba_cert_get_image failed\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (ctrl->create_pem)
|
||||
{
|
||||
if (count)
|
||||
putc ('\n', fp);
|
||||
print_short_info (cert, fp);
|
||||
putc ('\n', fp);
|
||||
}
|
||||
count++;
|
||||
|
||||
if (!b64writer)
|
||||
{
|
||||
ctrl->pem_name = "CERTIFICATE";
|
||||
rc = gpgsm_create_writer (&b64writer, ctrl, fp, &writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("can't create writer: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
rc = ksba_writer_write (writer, image, imagelen);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("write error: %s\n", ksba_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (ctrl->create_pem)
|
||||
{
|
||||
/* We want one certificate per PEM block */
|
||||
rc = gpgsm_finish_writer (b64writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("write failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
gpgsm_destroy_writer (b64writer);
|
||||
b64writer = NULL;
|
||||
}
|
||||
|
||||
ksba_cert_release (cert);
|
||||
cert = NULL;
|
||||
}
|
||||
if (rc && rc != -1)
|
||||
log_error ("keydb_search failed: %s\n", gnupg_strerror (rc));
|
||||
else if (b64writer)
|
||||
{
|
||||
rc = gpgsm_finish_writer (b64writer);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("write failed: %s\n", gnupg_strerror (rc));
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
|
||||
leave:
|
||||
gpgsm_destroy_writer (b64writer);
|
||||
ksba_cert_release (cert);
|
||||
xfree (desc);
|
||||
keydb_release (hd);
|
||||
}
|
||||
|
||||
|
||||
/* Print some info about the certifciate CERT to FP */
|
||||
static void
|
||||
print_short_info (KsbaCert cert, FILE *fp)
|
||||
{
|
||||
char *p;
|
||||
KsbaSexp sexp;
|
||||
int idx;
|
||||
|
||||
for (idx=0; (p = ksba_cert_get_issuer (cert, idx)); idx++)
|
||||
{
|
||||
fputs (!idx? "Issuer ...: "
|
||||
: "\n aka ...: ", fp);
|
||||
gpgsm_print_name (fp, p);
|
||||
xfree (p);
|
||||
}
|
||||
putc ('\n', fp);
|
||||
|
||||
fputs ("Serial ...: ", fp);
|
||||
sexp = ksba_cert_get_serial (cert);
|
||||
if (sexp)
|
||||
{
|
||||
int len;
|
||||
const unsigned char *s = sexp;
|
||||
|
||||
if (*s == '(')
|
||||
{
|
||||
s++;
|
||||
for (len=0; *s && *s != ':' && digitp (s); s++)
|
||||
len = len*10 + atoi_1 (s);
|
||||
if (*s == ':')
|
||||
for (s++; len; len--, s++)
|
||||
fprintf (fp, "%02X", *s);
|
||||
}
|
||||
xfree (sexp);
|
||||
}
|
||||
putc ('\n', fp);
|
||||
|
||||
for (idx=0; (p = ksba_cert_get_subject (cert, idx)); idx++)
|
||||
{
|
||||
fputs (!idx? "Subject ..: "
|
||||
: "\n aka ..: ", fp);
|
||||
gpgsm_print_name (fp, p);
|
||||
xfree (p);
|
||||
}
|
||||
putc ('\n', fp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
271
sm/fingerprint.c
271
sm/fingerprint.c
@ -1,271 +0,0 @@
|
||||
/* fingerprint.c - Get the fingerprint
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include <gcrypt.h>
|
||||
#include <ksba.h>
|
||||
|
||||
#include "gpgsm.h"
|
||||
|
||||
/* Return the fingerprint of the certificate (we can't put this into
|
||||
libksba because we need libgcrypt support). The caller must
|
||||
provide an array of sufficient length or NULL so that the function
|
||||
allocates the array. If r_len is not NULL, the length of the
|
||||
digest is returned; well, this can also be done by using
|
||||
gcry_md_get_algo_dlen(). If algo is 0, a SHA-1 will be used.
|
||||
|
||||
If there is a problem , the function does never return NULL but a
|
||||
digest of all 0xff.
|
||||
*/
|
||||
char *
|
||||
gpgsm_get_fingerprint (KsbaCert cert, int algo, char *array, int *r_len)
|
||||
{
|
||||
GCRY_MD_HD md;
|
||||
int rc, len;
|
||||
|
||||
if (!algo)
|
||||
algo = GCRY_MD_SHA1;
|
||||
|
||||
len = gcry_md_get_algo_dlen (algo);
|
||||
assert (len);
|
||||
if (!array)
|
||||
array = xmalloc (len);
|
||||
|
||||
if (r_len)
|
||||
*r_len = len;
|
||||
|
||||
md = gcry_md_open (algo, 0);
|
||||
if (!md)
|
||||
{
|
||||
log_error ("md_open failed: %s\n", gcry_strerror (-1));
|
||||
memset (array, 0xff, len); /* better return an invalid fpr than NULL */
|
||||
return array;
|
||||
}
|
||||
|
||||
rc = ksba_cert_hash (cert, 0, HASH_FNC, md);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("ksba_cert_hash failed: %s\n", ksba_strerror (rc));
|
||||
gcry_md_close (md);
|
||||
memset (array, 0xff, len); /* better return an invalid fpr than NULL */
|
||||
return array;
|
||||
}
|
||||
gcry_md_final (md);
|
||||
memcpy (array, gcry_md_read(md, algo), len );
|
||||
return array;
|
||||
}
|
||||
|
||||
|
||||
/* Return an allocated buffer with the formatted fingerprint */
|
||||
char *
|
||||
gpgsm_get_fingerprint_string (KsbaCert cert, int algo)
|
||||
{
|
||||
unsigned char digest[MAX_DIGEST_LEN];
|
||||
char *buf;
|
||||
int len, i;
|
||||
|
||||
if (!algo)
|
||||
algo = GCRY_MD_SHA1;
|
||||
|
||||
len = gcry_md_get_algo_dlen (algo);
|
||||
assert (len <= MAX_DIGEST_LEN );
|
||||
gpgsm_get_fingerprint (cert, algo, digest, NULL);
|
||||
buf = xmalloc (len*3+1);
|
||||
*buf = 0;
|
||||
for (i=0; i < len; i++ )
|
||||
sprintf (buf+strlen(buf), i? ":%02X":"%02X", digest[i]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Return an allocated buffer with the formatted fingerprint as one
|
||||
large hexnumber */
|
||||
char *
|
||||
gpgsm_get_fingerprint_hexstring (KsbaCert cert, int algo)
|
||||
{
|
||||
unsigned char digest[MAX_DIGEST_LEN];
|
||||
char *buf;
|
||||
int len, i;
|
||||
|
||||
if (!algo)
|
||||
algo = GCRY_MD_SHA1;
|
||||
|
||||
len = gcry_md_get_algo_dlen (algo);
|
||||
assert (len <= MAX_DIGEST_LEN );
|
||||
gpgsm_get_fingerprint (cert, algo, digest, NULL);
|
||||
buf = xmalloc (len*3+1);
|
||||
*buf = 0;
|
||||
for (i=0; i < len; i++ )
|
||||
sprintf (buf+strlen(buf), "%02X", digest[i]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* Return a certificate ID. These are the last 4 bytes of the SHA-1
|
||||
fingerprint. */
|
||||
unsigned long
|
||||
gpgsm_get_short_fingerprint (KsbaCert cert)
|
||||
{
|
||||
unsigned char digest[20];
|
||||
|
||||
gpgsm_get_fingerprint (cert, GCRY_MD_SHA1, digest, NULL);
|
||||
return ((digest[16]<<24)|(digest[17]<<16)|(digest[18]<< 8)|digest[19]);
|
||||
}
|
||||
|
||||
|
||||
/* Return the so called KEYGRIP which is the SHA-1 hash of the public
|
||||
key parameters expressed as an canoncial encoded S-Exp. array must
|
||||
be 20 bytes long. returns the array or a newly allocated one if the
|
||||
passed one was NULL */
|
||||
char *
|
||||
gpgsm_get_keygrip (KsbaCert cert, char *array)
|
||||
{
|
||||
GCRY_SEXP s_pkey;
|
||||
int rc;
|
||||
KsbaSexp p;
|
||||
size_t n;
|
||||
|
||||
p = ksba_cert_get_public_key (cert);
|
||||
if (!p)
|
||||
return NULL; /* oops */
|
||||
|
||||
if (DBG_X509)
|
||||
log_debug ("get_keygrip for public key: %s\n", p);
|
||||
n = gcry_sexp_canon_len (p, 0, NULL, NULL);
|
||||
if (!n)
|
||||
{
|
||||
log_error ("libksba did not return a proper S-Exp\n");
|
||||
return NULL;
|
||||
}
|
||||
rc = gcry_sexp_sscan ( &s_pkey, NULL, p, n);
|
||||
xfree (p);
|
||||
if (rc)
|
||||
{
|
||||
log_error ("gcry_sexp_scan failed: %s\n", gcry_strerror (rc));
|
||||
return NULL;
|
||||
}
|
||||
array = gcry_pk_get_keygrip (s_pkey, array);
|
||||
gcry_sexp_release (s_pkey);
|
||||
if (!array)
|
||||
{
|
||||
rc = seterr (General_Error);
|
||||
log_error ("can't calculate keygrip\n");
|
||||
return NULL;
|
||||
}
|
||||
if (DBG_X509)
|
||||
log_printhex ("keygrip=", array, 20);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/* Return an allocated buffer with the keygrip of CERT in from of an
|
||||
hexstring. NULL is returned in case of error */
|
||||
char *
|
||||
gpgsm_get_keygrip_hexstring (KsbaCert cert)
|
||||
{
|
||||
unsigned char grip[20];
|
||||
char *buf, *p;
|
||||
int i;
|
||||
|
||||
gpgsm_get_keygrip (cert, grip);
|
||||
buf = p = xmalloc (20*2+1);
|
||||
for (i=0; i < 20; i++, p += 2 )
|
||||
sprintf (p, "%02X", grip[i]);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* For certain purposes we need a certificate id which has an upper
|
||||
limit of the size. We use the hash of the issuer name and the
|
||||
serial number for this. In most cases the serial number is not
|
||||
that large and the resulting string can be passed on an assuan
|
||||
command line. Everything is hexencoded with the serialnumber
|
||||
delimted from the has by a dot.
|
||||
|
||||
The caller must free the string.
|
||||
*/
|
||||
char *
|
||||
gpgsm_get_certid (KsbaCert cert)
|
||||
{
|
||||
KsbaSexp serial;
|
||||
unsigned char *p;
|
||||
char *endp;
|
||||
unsigned char hash[20];
|
||||
unsigned long n;
|
||||
char *certid;
|
||||
int i;
|
||||
|
||||
p = ksba_cert_get_issuer (cert, 0);
|
||||
if (!p)
|
||||
return NULL; /* Ooops: No issuer */
|
||||
gcry_md_hash_buffer (GCRY_MD_SHA1, hash, p, strlen (p));
|
||||
xfree (p);
|
||||
|
||||
serial = ksba_cert_get_serial (cert);
|
||||
if (!serial)
|
||||
return NULL; /* oops: no serial number */
|
||||
p = serial;
|
||||
if (*p != '(')
|
||||
{
|
||||
log_error ("Ooops: invalid serial number\n");
|
||||
xfree (serial);
|
||||
return NULL;
|
||||
}
|
||||
p++;
|
||||
n = strtoul (p, &endp, 10);
|
||||
p = endp;
|
||||
if (*p != ':')
|
||||
{
|
||||
log_error ("Ooops: invalid serial number (no colon)\n");
|
||||
xfree (serial);
|
||||
return NULL;
|
||||
}
|
||||
p++;
|
||||
|
||||
certid = xtrymalloc ( 40 + 1 + n*2 + 1);
|
||||
if (!certid)
|
||||
{
|
||||
xfree (serial);
|
||||
return NULL; /* out of core */
|
||||
}
|
||||
|
||||
for (i=0, endp = certid; i < 20; i++, endp += 2 )
|
||||
sprintf (endp, "%02X", hash[i]);
|
||||
*endp++ = '.';
|
||||
for (i=0; i < n; i++, endp += 2)
|
||||
sprintf (endp, "%02X", p[i]);
|
||||
*endp = 0;
|
||||
|
||||
xfree (serial);
|
||||
return certid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
1388
sm/gpgsm.c
1388
sm/gpgsm.c
File diff suppressed because it is too large
Load Diff
261
sm/gpgsm.h
261
sm/gpgsm.h
@ -1,261 +0,0 @@
|
||||
/* gpgsm.h - Global definitions for GpgSM
|
||||
* 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
|
||||
*/
|
||||
|
||||
#ifndef GPGSM_H
|
||||
#define GPGSM_H
|
||||
|
||||
#include <ksba.h>
|
||||
#include "../common/util.h"
|
||||
#include "../common/errors.h"
|
||||
|
||||
#define MAX_DIGEST_LEN 24
|
||||
|
||||
/* A large struct name "opt" to keep global flags */
|
||||
struct {
|
||||
unsigned int debug; /* debug flags (DBG_foo_VALUE) */
|
||||
int verbose; /* verbosity level */
|
||||
int quiet; /* be as quiet as possible */
|
||||
int batch; /* run in batch mode, i.e w/o any user interaction */
|
||||
int answer_yes; /* assume yes on most questions */
|
||||
int answer_no; /* assume no on most questions */
|
||||
int dry_run; /* don't change any persistent data */
|
||||
|
||||
const char *homedir; /* configuration directory name */
|
||||
const char *agent_program;
|
||||
char *display;
|
||||
char *ttyname;
|
||||
char *ttytype;
|
||||
char *lc_ctype;
|
||||
char *lc_messages;
|
||||
|
||||
const char *dirmngr_program;
|
||||
char *outfile; /* name of output file */
|
||||
|
||||
int with_key_data;/* include raw key in the column delimted output */
|
||||
|
||||
int fingerprint; /* list fingerprints in all key listings */
|
||||
|
||||
int armor; /* force base64 armoring (see also ctrl.with_base64) */
|
||||
int no_armor; /* don't try to figure out whether data is base64 armored*/
|
||||
|
||||
const char *def_cipher_algoid; /* cipher algorithm to use if
|
||||
nothing else is specified */
|
||||
|
||||
int def_digest_algo; /* Ditto for hash algorithm */
|
||||
int def_compress_algo; /* Ditto for compress algorithm */
|
||||
|
||||
char *def_recipient; /* userID of the default recipient */
|
||||
int def_recipient_self; /* The default recipient is the default key */
|
||||
|
||||
char *local_user; /* NULL or argument to -u */
|
||||
|
||||
int always_trust; /* Trust the given keys even if there is no
|
||||
valid certification chain */
|
||||
int skip_verify; /* do not check signatures on data */
|
||||
|
||||
int lock_once; /* Keep lock once they are set */
|
||||
|
||||
int ignore_time_conflict; /* Ignore certain time conflicts */
|
||||
|
||||
int no_crl_check; /* Don't do a CRL check */
|
||||
|
||||
char *policy_file; /* full pathname of policy file */
|
||||
int no_policy_check; /* ignore certificate policies */
|
||||
int no_chain_validation; /* Bypass all cert chain validity tests */
|
||||
|
||||
int auto_issuer_key_retrieve; /* try to retrieve a missing issuer key. */
|
||||
} opt;
|
||||
|
||||
|
||||
#define DBG_X509_VALUE 1 /* debug x.509 data reading/writing */
|
||||
#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 /* debug assuan communication */
|
||||
|
||||
#define DBG_X509 (opt.debug & DBG_X509_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;
|
||||
|
||||
/* Note that the default values for this are set by
|
||||
gpgsm_init_default_ctrl() */
|
||||
struct server_control_s {
|
||||
int no_server; /* we are not running under server control */
|
||||
int status_fd; /* only for non-server mode */
|
||||
struct server_local_s *server_local;
|
||||
int with_colons; /* use column delimited output format */
|
||||
int with_chain; /* include the certifying certs in a listing */
|
||||
|
||||
int autodetect_encoding; /* try to detect the input encoding */
|
||||
int is_pem; /* Is in PEM format */
|
||||
int is_base64; /* is in plain base-64 format */
|
||||
|
||||
int create_base64; /* Create base64 encoded output */
|
||||
int create_pem; /* create PEM output */
|
||||
const char *pem_name; /* PEM name to use */
|
||||
|
||||
int include_certs; /* -1 to send all certificates in the chain
|
||||
along with a signature or the number of
|
||||
certificates up the chain (0 = none, 1 = only
|
||||
signer) */
|
||||
};
|
||||
typedef struct server_control_s *CTRL;
|
||||
|
||||
/* data structure used in base64.c */
|
||||
typedef struct base64_context_s *Base64Context;
|
||||
|
||||
|
||||
struct certlist_s {
|
||||
struct certlist_s *next;
|
||||
KsbaCert cert;
|
||||
};
|
||||
typedef struct certlist_s *CERTLIST;
|
||||
|
||||
/*-- gpgsm.c --*/
|
||||
void gpgsm_exit (int rc);
|
||||
void gpgsm_init_default_ctrl (struct server_control_s *ctrl);
|
||||
|
||||
/*-- server.c --*/
|
||||
void gpgsm_server (void);
|
||||
void gpgsm_status (CTRL ctrl, int no, const char *text);
|
||||
void gpgsm_status2 (CTRL ctrl, int no, ...);
|
||||
|
||||
/*-- fingerprint --*/
|
||||
char *gpgsm_get_fingerprint (KsbaCert cert, int algo, char *array, int *r_len);
|
||||
char *gpgsm_get_fingerprint_string (KsbaCert cert, int algo);
|
||||
char *gpgsm_get_fingerprint_hexstring (KsbaCert cert, int algo);
|
||||
unsigned long gpgsm_get_short_fingerprint (KsbaCert cert);
|
||||
char *gpgsm_get_keygrip (KsbaCert cert, char *array);
|
||||
char *gpgsm_get_keygrip_hexstring (KsbaCert cert);
|
||||
char *gpgsm_get_certid (KsbaCert cert);
|
||||
|
||||
|
||||
/*-- base64.c --*/
|
||||
int gpgsm_create_reader (Base64Context *ctx,
|
||||
CTRL ctrl, FILE *fp, KsbaReader *r_reader);
|
||||
void gpgsm_destroy_reader (Base64Context ctx);
|
||||
int gpgsm_create_writer (Base64Context *ctx,
|
||||
CTRL ctrl, FILE *fp, KsbaWriter *r_writer);
|
||||
int gpgsm_finish_writer (Base64Context ctx);
|
||||
void gpgsm_destroy_writer (Base64Context ctx);
|
||||
|
||||
|
||||
/*-- certdump.c --*/
|
||||
void gpgsm_print_serial (FILE *fp, KsbaConstSexp p);
|
||||
void gpgsm_print_time (FILE *fp, time_t t);
|
||||
void gpgsm_print_name (FILE *fp, const char *string);
|
||||
|
||||
void gpgsm_dump_cert (const char *text, KsbaCert cert);
|
||||
void gpgsm_dump_serial (KsbaConstSexp p);
|
||||
void gpgsm_dump_time (time_t t);
|
||||
void gpgsm_dump_string (const char *string);
|
||||
|
||||
|
||||
|
||||
/*-- certcheck.c --*/
|
||||
int gpgsm_check_cert_sig (KsbaCert issuer_cert, KsbaCert cert);
|
||||
int gpgsm_check_cms_signature (KsbaCert cert, KsbaConstSexp sigval,
|
||||
GCRY_MD_HD md, int hash_algo);
|
||||
/* fixme: move create functions to another file */
|
||||
int gpgsm_create_cms_signature (KsbaCert cert, GCRY_MD_HD md, int mdalgo,
|
||||
char **r_sigval);
|
||||
|
||||
|
||||
/*-- certchain.c --*/
|
||||
int gpgsm_walk_cert_chain (KsbaCert start, KsbaCert *r_next);
|
||||
int gpgsm_is_root_cert (KsbaCert cert);
|
||||
int gpgsm_validate_chain (CTRL ctrl, KsbaCert cert, time_t *r_exptime);
|
||||
int gpgsm_basic_cert_check (KsbaCert cert);
|
||||
|
||||
/*-- certlist.c --*/
|
||||
int gpgsm_cert_use_sign_p (KsbaCert cert);
|
||||
int gpgsm_cert_use_encrypt_p (KsbaCert cert);
|
||||
int gpgsm_cert_use_verify_p (KsbaCert cert);
|
||||
int gpgsm_cert_use_decrypt_p (KsbaCert cert);
|
||||
int gpgsm_cert_use_cert_p (KsbaCert cert);
|
||||
int gpgsm_add_to_certlist (CTRL ctrl, const char *name, int secret,
|
||||
CERTLIST *listaddr);
|
||||
void gpgsm_release_certlist (CERTLIST list);
|
||||
int gpgsm_find_cert (const char *name, KsbaCert *r_cert);
|
||||
|
||||
/*-- keylist.c --*/
|
||||
void gpgsm_list_keys (CTRL ctrl, STRLIST names, FILE *fp, unsigned int mode);
|
||||
|
||||
/*-- import.c --*/
|
||||
int gpgsm_import (CTRL ctrl, int in_fd);
|
||||
int gpgsm_import_files (CTRL ctrl, int nfiles, char **files,
|
||||
int (*of)(const char *fname));
|
||||
|
||||
/*-- export.c --*/
|
||||
void gpgsm_export (CTRL ctrl, STRLIST names, FILE *fp);
|
||||
|
||||
/*-- delete.c --*/
|
||||
int gpgsm_delete (CTRL ctrl, STRLIST names);
|
||||
|
||||
/*-- verify.c --*/
|
||||
int gpgsm_verify (CTRL ctrl, int in_fd, int data_fd, FILE *out_fp);
|
||||
|
||||
/*-- sign.c --*/
|
||||
int gpgsm_get_default_cert (KsbaCert *r_cert);
|
||||
int gpgsm_sign (CTRL ctrl, CERTLIST signerlist,
|
||||
int data_fd, int detached, FILE *out_fp);
|
||||
|
||||
/*-- encrypt.c --*/
|
||||
int gpgsm_encrypt (CTRL ctrl, CERTLIST recplist, int in_fd, FILE *out_fp);
|
||||
|
||||
/*-- decrypt.c --*/
|
||||
int gpgsm_decrypt (CTRL ctrl, int in_fd, FILE *out_fp);
|
||||
|
||||
/*-- certreqgen.c --*/
|
||||
int gpgsm_genkey (CTRL ctrl, int in_fd, FILE *out_fp);
|
||||
|
||||
/*-- call-agent.c --*/
|
||||
int gpgsm_agent_pksign (const char *keygrip,
|
||||
unsigned char *digest,
|
||||
size_t digestlen,
|
||||
int digestalgo,
|
||||
char **r_buf, size_t *r_buflen);
|
||||
int gpgsm_agent_pkdecrypt (const char *keygrip,
|
||||
KsbaConstSexp ciphertext,
|
||||
char **r_buf, size_t *r_buflen);
|
||||
int gpgsm_agent_genkey (KsbaConstSexp keyparms, KsbaSexp *r_pubkey);
|
||||
int gpgsm_agent_istrusted (KsbaCert cert);
|
||||
int gpgsm_agent_havekey (const char *hexkeygrip);
|
||||
int gpgsm_agent_marktrusted (KsbaCert cert);
|
||||
int gpgsm_agent_learn (void);
|
||||
|
||||
/*-- call-dirmngr.c --*/
|
||||
int gpgsm_dirmngr_isvalid (KsbaCert cert);
|
||||
int gpgsm_dirmngr_lookup (CTRL ctrl, STRLIST names,
|
||||
void (*cb)(void*, KsbaCert), void *cb_value);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif /*GPGSM_H*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user