Merge branch 'master' into npth

Conflicts:
	ChangeLog-2011
	Makefile.am
	agent/ChangeLog-2011
	agent/gpg-agent.c
	dirmngr/ChangeLog-2011
	dirmngr/dirmngr.c
	doc/HACKING
	g13/g13.c
	po/de.po
	scd/ChangeLog-2011
	scd/apdu.c
	scd/command.c
	scd/scdaemon.c
	scripts/gitlog-to-changelog
	tools/ChangeLog-2011
This commit is contained in:
Marcus Brinkmann 2012-01-03 18:13:19 +01:00
commit 0868997e18
55 changed files with 1541 additions and 705 deletions

View File

@ -14,21 +14,6 @@
accept --with-libgpg-error-prefix as well as --with-gpg-error-prefix
* m4/gpg-error.m4: Update from git master.
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
* configure.ac: Fix npth version check.
* m4/npth.m4: Fix version check.
2011-09-26 Marcus Brinkmann <marcus@g10code.com>
* configure.ac: Don't check for PTH but for NPTH.
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
(have_pth): Rename to ...
(have_npth): ... this.
(USE_GNU_NPTH): Rename to ...
(USE_GNU_PTH): ... this.
* m4/gnupg-npth.m4: New file.
2011-09-23 Werner Koch <wk@g10code.com>
* configure.ac: Remove check for gcry_kdf_derive.

View File

@ -116,6 +116,7 @@ gen-ChangeLog:
if test -d $(top_srcdir)/.git; then \
(cd $(top_srcdir) && \
./scripts/gitlog-to-changelog \
--append-dot --tear-off \
--amend=scripts/git-log-fix \
--since=$(gen_start_date) ) > $(distdir)/cl-t; \
cat $(top_srcdir)/scripts/git-log-footer >> $(distdir)/cl-t; \

19
NEWS
View File

@ -1,4 +1,8 @@
Noteworthy changes in version 2.1.0beta3
Noteworthy changes in version 2.1.0beta4 (unreleased)
-----------------------------------------------------
Noteworthy changes in version 2.1.0beta3 (2011-12-20)
-----------------------------------------------------
* Fixed regression in GPG's secret key export function.
@ -9,6 +13,19 @@ Noteworthy changes in version 2.1.0beta3
* The Assuan commands KILLAGENT and KILLSCD are working again.
* SCdaemon does not anymore block after changing a card (regression
fix).
* gpg-connect-agent does now proberly display the help output for
"SCD HELP" commands.
* Preliminary support for the GPGSM validation model "steed".
* Improved certificate creation in GPGSM.
* New option for GPG_AGENT to select a passphrase mode. The loopback
mode may be used to bypass Pinentry.
Noteworthy changes in version 2.1.0beta2 (2011-03-08)
-----------------------------------------------------

View File

@ -27,8 +27,8 @@ Release process:
* Run "make -C po update-po".
* Write NEWS entries and set the release date in NEWS.
* In configure.ac set "my_issvn" to "no".
* Put a "Release <version>" line into the top level ChangeLog.
* Commit all changes to GIT and push them.
* Do a commit with a "Release <version>" line.
* Run "./autogen.sh --force"
(--force is required for the svn magic in configure.ac and a good
idea in any case)

View File

@ -12,17 +12,6 @@
(ssh_handler_request_identities): Do not call card_key_available
if the scdaemon is disabled.
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
* gpg-agent.c (start_connection_thread)
(start_connection_thread_ssh): Cast npth_self result to unsigned
long for safety.
* cache.c (new_data): Fix error check.
* cache.c, call-pinentry.c, call-scd.c, findkey.c, gpg-agent.c,
trustlist.c: Port to NPth.
2011-09-12 Ben Kibbey <bjk@luxsci.net>
* genkey.c (agent_ask_new_passphrase): Allow for an empty passphrase

View File

@ -73,17 +73,20 @@ struct
/* True if we handle sigusr2. */
int sigusr2_enabled;
/* Environment setting gathered at program start or changed using the
/* Environment settings gathered at program start or changed using the
Assuan command UPDATESTARTUPTTY. */
session_env_t startup_env;
char *startup_lc_ctype;
char *startup_lc_messages;
const char *pinentry_program; /* Filename of the program to start as
pinentry. */
const char *scdaemon_program; /* Filename of the program to handle
smartcard tasks. */
/* Filename of the program to start as pinentry. */
const char *pinentry_program;
/* Filename of the program to handle smartcard tasks. */
const char *scdaemon_program;
int disable_scdaemon; /* Never use the SCdaemon. */
int no_grab; /* Don't let the pinentry grab the keyboard */
/* The name of the file pinentry shall tocuh before exiting. If
@ -98,31 +101,51 @@ struct
/* Flag disallowing bypassing of the warning. */
int enforce_passphrase_constraints;
/* The require minmum length of a passphrase. */
unsigned int min_passphrase_len;
/* The minimum number of non-alpha characters in a passphrase. */
unsigned int min_passphrase_nonalpha;
/* File name with a patternfile or NULL if not enabled. */
const char *check_passphrase_pattern;
/* If not 0 the user is asked to change his passphrase after these
number of days. */
unsigned int max_passphrase_days;
/* If set, a passphrase history will be written and checked at each
passphrase change. */
int enable_passhrase_history;
int running_detached; /* We are running detached from the tty. */
/* If this global option is true, the passphrase cache is ignored
for signing operations. */
int ignore_cache_for_signing;
/* If this global option is true, the user is allowed to
interactively mark certificate in trustlist.txt as trusted. */
int allow_mark_trusted;
/* If this global option is true, the Assuan command
PRESET_PASSPHRASE is allowed. */
int allow_preset_passphrase;
/* If this global option is true, the Assuan option
pinentry-mode=loopback is allowed. */
int allow_loopback_pinentry;
int keep_tty; /* Don't switch the TTY (for pinentry) on request */
int keep_display; /* Don't switch the DISPLAY (for pinentry) on request */
int ssh_support; /* Enable ssh-agent emulation. */
/* This global option enables the ssh-agent subsystem. */
int ssh_support;
} opt;
/* Bit values for the --debug option. */
#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 */
@ -130,8 +153,9 @@ struct
#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_ASSUAN_VALUE 1024 /* Enable Assuan debugging. */
/* Test macros for the debug option. */
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
@ -139,14 +163,18 @@ struct
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
/* Forward reference for local definitions in command.c. */
struct server_local_s;
/* Forward reference for local definitions in call-scd.c. */
struct scd_local_s;
/* Collection of data per session (aka connection). */
struct server_control_s
{
/* Private data used to fire up the connection thread. We use this
structure do avoid an extra allocation for just a few bytes. */
structure do avoid an extra allocation for only a few bytes while
spawning a new connection thread. */
struct {
gnupg_fd_t fd;
} thread_startup;
@ -157,6 +185,7 @@ struct server_control_s
/* Private data of the SCdaemon (call-scd.c). */
struct scd_local_s *scd_local;
/* Environment settings for the connection. */
session_env_t session_env;
char *lc_ctype;
char *lc_messages;
@ -177,37 +206,47 @@ struct server_control_s
unsigned char keygrip[20];
int have_keygrip;
int use_auth_call; /* Hack to send the PKAUTH command instead of the
PKSIGN command to the scdaemon. */
int in_passwd; /* Hack to inhibit enforced passphrase change
during an explicit passwd command. */
/* A flag to enable a hack to send the PKAUTH command instead of the
PKSIGN command to the scdaemon. */
int use_auth_call;
unsigned long s2k_count; /* Other than the calibrated count. */
/* A flag to inhibit enforced passphrase change during an explicit
passwd command. */
int in_passwd;
/* The current S2K which might be different from the calibrated
count. */
unsigned long s2k_count;
};
/* Information pertaining to pinentry requests. */
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 max_tries; /* max. number of allowed tries. */
int failed_tries; /* Number of tries so far failed. */
int with_qualitybar; /* Set if the quality bar should be displayed. */
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 display a specific error */
size_t max_length; /* allocated length of the buffer */
char pin[1];
size_t max_length; /* Allocated length of the buffer PIN. */
char pin[1]; /* The buffer to hold the PIN or passphrase.
It's actual allocated length is given by
MAX_LENGTH (above). */
};
/* Types of the private keys. */
enum
{
PRIVATE_KEY_UNKNOWN = 0,
PRIVATE_KEY_CLEAR = 1,
PRIVATE_KEY_PROTECTED = 2,
PRIVATE_KEY_SHADOWED = 3,
PROTECTED_SHARED_SECRET = 4
PRIVATE_KEY_UNKNOWN = 0, /* Type of key is not known. */
PRIVATE_KEY_CLEAR = 1, /* The key is not protected. */
PRIVATE_KEY_PROTECTED = 2, /* The key is protected. */
PRIVATE_KEY_SHADOWED = 3, /* The key is a stub for a smartcard
based key. */
PROTECTED_SHARED_SECRET = 4 /* RFU. */
};

View File

@ -1261,8 +1261,7 @@ agent_popup_message_stop (ctrl_t ctrl)
assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
}
else if (pid > 0)
kill (pid, SIGKILL); /* Need to use SIGKILL due to bad
interaction of SIGINT with Pth. */
kill (pid, SIGINT);
#endif
/* Now wait for the thread to terminate. */

View File

@ -1,5 +1,6 @@
/* call-scd.c - fork of the scdaemon to do SC operations
* Copyright (C) 2001, 2002, 2005, 2007, 2010 Free Software Foundation, Inc.
* Copyright (C) 2001, 2002, 2005, 2007, 2010,
* 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -44,15 +45,6 @@
#define MAX_OPEN_FDS 20
#endif
/* This Assuan flag is only available since libassuan 2.0.2. Because
comments lines are comments anyway we can use a replacement which
might not do anything. assuan_{g,s}et_flag don't return an error
thus there won't be any ABI problem. */
#ifndef ASSUAN_CONVEY_COMMENTS
#define ASSUAN_CONVEY_COMMENTS 4
#endif
/* Definition of module local data of the CTRL structure. */
struct scd_local_s
{
@ -1115,16 +1107,28 @@ pass_status_thru (void *opaque, const char *line)
char keyword[200];
int i;
for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
keyword[i] = *line;
keyword[i] = 0;
/* truncate any remaining keyword stuff. */
for (; *line && !spacep (line); line++)
;
while (spacep (line))
line++;
if (line[0] == '#' && (!line[1] || spacep (line+1)))
{
/* We are called in convey comments mode. Now, if we see a
comment marker as keyword we forward the line verbatim to the
the caller. This way the comment lines from scdaemon won't
appear as status lines with keyword '#'. */
assuan_write_line (ctx, line);
}
else
{
for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
keyword[i] = *line;
keyword[i] = 0;
assuan_write_status (ctx, keyword, line);
/* Truncate any remaining keyword stuff. */
for (; *line && !spacep (line); line++)
;
while (spacep (line))
line++;
assuan_write_status (ctx, keyword, line);
}
return 0;
}

View File

@ -50,31 +50,57 @@
/* The size of the import/export KEK key (in bytes). */
#define KEYWRAP_KEYSIZE (128/8)
/* A shortcut to call assuan_set_error using an gpg_err_code_t and a
text string. */
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
/* Check that the maximum digest length we support has at least the
length of the keygrip. */
#if MAX_DIGEST_LEN < 20
#error MAX_DIGEST_LEN shorter than keygrip
#endif
/* Data used to associate an Assuan context with local server data */
/* Data used to associate an Assuan context with local server data.
This is this modules local part of the server_control_s struct. */
struct server_local_s
{
/* Our Assuan context. */
assuan_context_t assuan_ctx;
int message_fd;
/* If this flag is true, the passphrase cache is used for signing
operations. It defaults to true but may be set on a per
connection base. The global option opt.ignore_cache_for_signing
takes precedence over this flag. */
int use_cache_for_signing;
char *keydesc; /* Allocated description for the next key
operation. */
int pause_io_logging; /* Used to suppress I/O logging during a command */
int stopme; /* If set to true the agent will be terminated after
the end of this session. */
int allow_pinentry_notify; /* Set if pinentry notifications should
be done. */
void *import_key; /* Malloced KEK for the import_key command. */
void *export_key; /* Malloced KEK for the export_key command. */
int allow_fully_canceled; /* Client is aware of GPG_ERR_FULLY_CANCELED. */
char *last_cache_nonce; /* Last CACHE_NOCNE sent as status (malloced). */
char *last_passwd_nonce; /* Last PASSWD_NOCNE sent as status (malloced). */
/* An allocated description for the next key operation. This is
used if a pinnetry needs to be popped up. */
char *keydesc;
/* Flags to suppress I/O logging during a command. */
int pause_io_logging;
/* If this flags is set to true the agent will be terminated after
the end of the current session. */
int stopme;
/* Flag indicating whether pinentry notifications shall be done. */
int allow_pinentry_notify;
/* Malloced KEK (Key-Encryption-Key) for the import_key command. */
void *import_key;
/* Malloced KEK for the export_key command. */
void *export_key;
/* Client is aware of the error code GPG_ERR_FULLY_CANCELED. */
int allow_fully_canceled;
/* Last CACHE_NONCE sent as status (malloced). */
char *last_cache_nonce;
/* Last PASSWD_NONCE sent as status (malloced). */
char *last_passwd_nonce;
};
@ -156,6 +182,8 @@ write_and_clear_outbuf (assuan_context_t ctx, membuf_t *mb)
}
/* Clear the nonces used to enable the passphrase cache for certain
multi-command command sequences. */
static void
clear_nonce_cache (ctrl_t ctrl)
{
@ -176,6 +204,9 @@ clear_nonce_cache (ctrl_t ctrl)
}
/* This function is called by Libassuan whenever thee client sends a
reset. It has been registered similar to the other Assuan
commands. */
static gpg_error_t
reset_notify (assuan_context_t ctx, char *line)
{
@ -196,8 +227,13 @@ reset_notify (assuan_context_t ctx, char *line)
}
/* Skip over options.
Blanks after the options are also removed. */
/* Skip over options in LINE.
Blanks after the options are also removed. Options are indicated
by two leading dashes followed by a string consisting of non-space
characters. The special option "--" indicates an explicit end of
options; all what follows will not be considered an option. The
first no-option string also indicates the end of option parsing. */
static char *
skip_options (const char *line)
{
@ -213,7 +249,11 @@ skip_options (const char *line)
return (char*)line;
}
/* Check whether the option NAME appears in LINE */
/* Check whether the option NAME appears in LINE. An example for a
line with options is:
--algo=42 --data foo bar
This function would then only return true if NAME is "data". */
static int
has_option (const char *line, const char *name)
{
@ -226,6 +266,7 @@ has_option (const char *line, const char *name)
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
}
/* Same as has_option but does only test for the name of the option
and ignores an argument, i.e. with NAME being "--hash" it would
return true for "--hash" as well as for "--hash=foo". */
@ -242,8 +283,9 @@ has_option_name (const char *line, const char *name)
&& (!s[n] || spacep (s+n) || s[n] == '='));
}
/* Return a pointer to the argument of the option with NAME. If such
an option is not given, it returns NULL. */
an option is not given, NULL is retruned. */
static char *
option_value (const char *line, const char *name)
{
@ -265,7 +307,7 @@ option_value (const char *line, const char *name)
}
/* Replace all '+' by a blank. */
/* Replace all '+' by a blank in the string S. */
static void
plus_to_blank (char *s)
{
@ -296,8 +338,9 @@ parse_hexstring (assuan_context_t ctx, const char *string, size_t *len)
return 0;
}
/* Parse the keygrip in STRING into the provided buffer BUF. BUF must
provide space for 20 bytes. BUF is not changed if the function
provide space for 20 bytes. BUF is not changed if the function
returns an error. */
static int
parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
@ -319,7 +362,11 @@ parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
}
/* Write an assuan status line. */
/* Write an Assuan status line. KEYWORD is the first item on the
status line. The following arguments are all separated by a space
in the output. The last argument must be a NULL. Linefeeds and
carriage returns characters (which are not allowed in an Assuan
status line) are silently quoted in C-style. */
gpg_error_t
agent_write_status (ctrl_t ctrl, const char *keyword, ...)
{
@ -463,6 +510,7 @@ bump_key_eventcounter (void)
eventcounter.any++;
}
/* This function should be called for all card reader status
changes. This function is assured not to do any context
switches. */
@ -1069,6 +1117,8 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
}
/* Entry int for the command KEYINFO. This function handles the
command option processing. For details see hlp_keyinfo above. */
static gpg_error_t
cmd_keyinfo (assuan_context_t ctx, char *line)
{
@ -1140,6 +1190,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
/* Helper for cmd_get_passphrase. */
static int
send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
{
@ -2259,12 +2310,8 @@ cmd_killagent (assuan_context_t ctx, char *line)
return set_error (GPG_ERR_NOT_SUPPORTED, "no --use-standard-socket");
ctrl->server_local->stopme = 1;
#ifdef ASSUAN_FORCE_CLOSE
assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
return 0;
#else
return gpg_error (GPG_ERR_EOF);
#endif
}
@ -2415,6 +2462,8 @@ cmd_getinfo (assuan_context_t ctx, char *line)
/* This function is called by Libassuan to parse the OPTION command.
It has been registered similar to the other Assuan commands. */
static gpg_error_t
option_handler (assuan_context_t ctx, const char *key, const char *value)
{
@ -2574,7 +2623,8 @@ command_has_option (const char *cmd, const char *cmdopt)
}
/* Tell the assuan library about our commands */
/* Tell Libassuan about our commands. Also register the other Assuan
handlers. */
static int
register_commands (assuan_context_t ctx)
{
@ -2685,7 +2735,6 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
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;
ctrl->digest.raw_value = 0;
@ -2733,6 +2782,8 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
}
/* Helper for the pinentry loopback mode. It merely passes the
parameters on to the client. */
gpg_error_t
pinentry_loopback(ctrl_t ctrl, const char *keyword,
unsigned char **buffer, size_t *size,

View File

@ -299,6 +299,9 @@ ASSUAN_SYSTEM_NPTH_IMPL;
Functions.
*/
/* Allocate a string describing a library version by calling a GETFNC.
This function is expected to be called only once. GETFNC is
expected to have a semantic like gcry_check_version (). */
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
{
@ -316,7 +319,9 @@ make_libversion (const char *libname, const char *(*getfnc)(const char*))
return result;
}
/* Return strings describing this program. The case values are
described in common/argparse.c:strusage. The values here override
the default values given by strusage. */
static const char *
my_strusage (int level)
{
@ -438,6 +443,9 @@ remove_socket (char *name)
}
}
/* Cleanup code for this program. This is either called has an atexit
handler or directly. */
static void
cleanup (void)
{
@ -1150,11 +1158,11 @@ main (int argc, char **argv )
if (csh_style)
{
*strchr (infostr, '=') = ' ';
es_printf ("setenv %s\n", infostr);
es_printf ("setenv %s;\n", infostr);
if (opt.ssh_support)
{
*strchr (infostr_ssh_sock, '=') = ' ';
es_printf ("setenv %s\n", infostr_ssh_sock);
es_printf ("setenv %s;\n", infostr_ssh_sock);
}
}
else
@ -1238,6 +1246,8 @@ main (int argc, char **argv )
}
/* Exit entry point. This function should be called instead of a
plain exit. */
void
agent_exit (int rc)
{
@ -1264,6 +1274,11 @@ agent_exit (int rc)
}
/* Each thread has its own local variables conveyed by a control
structure usually identified by an argument named CTRL. This
function is called immediately after allocating the control
structure. Its purpose is to setup the default values for that
structure. */
static void
agent_init_default_ctrl (ctrl_t ctrl)
{
@ -1289,6 +1304,8 @@ agent_init_default_ctrl (ctrl_t ctrl)
}
/* Release all resources allocated by default in the control
structure. This is the counterpart to agent_init_default_ctrl. */
static void
agent_deinit_default_ctrl (ctrl_t ctrl)
{
@ -1690,6 +1707,7 @@ agent_sighup_action (void)
}
/* A helper function to handle SIGUSR2. */
static void
agent_sigusr2_action (void)
{
@ -1700,6 +1718,8 @@ agent_sigusr2_action (void)
}
/* The signal handler for this program. It is expected to be run in
its own trhead and not in the context of a signal handler. */
static void
handle_signal (int signo)
{

View File

@ -97,6 +97,19 @@ setup_libassuan_logging (unsigned int *debug_var_address)
assuan_set_log_cb (my_libassuan_log_handler, debug_var_address);
}
/* Change the Libassuan log categories to those given by NEWCATS.
NEWCATS is 0 the default category of ASSUAN_LOG_CONTROL is
selected. Note, that setup_libassuan_logging overrides the values
given here. */
void
set_libassuan_log_cats (unsigned int newcats)
{
if (newcats)
log_cats = newcats;
else /* Default to log the control channel. */
log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
}
static gpg_error_t

View File

@ -26,6 +26,7 @@
#include "session-env.h"
void setup_libassuan_logging (unsigned int *debug_var_address);
void set_libassuan_log_cats (unsigned int newcats);
gpg_error_t

View File

@ -583,7 +583,8 @@ use_hardlinks_p (const char *tname)
strcpy (lname, tname);
strcat (lname, "x");
link (tname, lname);
/* We ignore the return value of link() because it is unreliable. */
(void) link (tname, lname);
if (stat (tname, &sb))
res = -1; /* Ooops. */
@ -1004,7 +1005,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
{
struct stat sb;
link (h->tname, h->lockname);
/* We ignore the return value of link() because it is unreliable. */
(void) link (h->tname, h->lockname);
if (stat (h->tname, &sb))
{

View File

@ -217,6 +217,17 @@ struct notify_list_s
};
typedef struct notify_list_s *notify_list_t;
/* A private cookie function to implement an internal IOCTL
service. */
typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd,
void *ptr, size_t *len);
/* IOCTL commands for the private cookie function. */
#define COOKIE_IOCTL_SNATCH_BUFFER 1
/* An internal stream object. */
struct estream_internal
{
@ -231,6 +242,7 @@ struct estream_internal
es_cookie_read_function_t func_read;
es_cookie_write_function_t func_write;
es_cookie_seek_function_t func_seek;
cookie_ioctl_function_t func_ioctl;
es_cookie_close_function_t func_close;
int strategy;
es_syshd_t syshd; /* A copy of the sytem handle. */
@ -771,6 +783,33 @@ es_func_mem_seek (void *cookie, off_t *offset, int whence)
return 0;
}
/* An IOCTL function for memory objects. */
static int
es_func_mem_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
{
estream_cookie_mem_t mem_cookie = cookie;
int ret;
if (cmd == COOKIE_IOCTL_SNATCH_BUFFER)
{
/* Return the internal buffer of the stream to the caller and
invalidate it for the stream. */
*(void**)ptr = mem_cookie->memory;
*len = mem_cookie->offset;
mem_cookie->memory = NULL;
mem_cookie->memory_size = 0;
mem_cookie->offset = 0;
ret = 0;
}
else
{
_set_errno (EINVAL);
ret = -1;
}
return ret;
}
/* Destroy function for memory objects. */
static int
@ -1608,6 +1647,7 @@ es_initialize (estream_t stream,
stream->intern->func_read = functions.func_read;
stream->intern->func_write = functions.func_write;
stream->intern->func_seek = functions.func_seek;
stream->intern->func_ioctl = NULL;
stream->intern->func_close = functions.func_close;
stream->intern->strategy = _IOFBF;
stream->intern->syshd = *syshd;
@ -2667,6 +2707,47 @@ es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags, 0))
(*estream_functions_mem.func_close) (cookie);
if (stream)
stream->intern->func_ioctl = es_func_mem_ioctl;
return stream;
}
/* This is the same as es_fopenmem but intializes the memory with a
copy of (DATA,DATALEN). The stream is initally set to the
beginning. If MEMLIMIT is not 0 but shorter than DATALEN it
DATALEN will be used as the value for MEMLIMIT. */
estream_t
es_fopenmem_init (size_t memlimit, const char *ES__RESTRICT mode,
const void *data, size_t datalen)
{
estream_t stream;
if (memlimit && memlimit < datalen)
memlimit = datalen;
stream = es_fopenmem (memlimit, mode);
if (stream && data && datalen)
{
if (es_writen (stream, data, datalen, NULL))
{
int saveerrno = errno;
es_fclose (stream);
stream = NULL;
_set_errno (saveerrno);
}
else
{
es_seek (stream, 0L, SEEK_SET, NULL);
es_set_indicators (stream, 0, 0);
}
}
if (stream)
stream->intern->func_ioctl = es_func_mem_ioctl;
return stream;
}
@ -3082,6 +3163,65 @@ es_fclose (estream_t stream)
}
/* This is a special version of es_fclose which can be used with
es_fopenmem to return the memory buffer. This is feature is useful
to write to a memory buffer using estream. Note that the function
does not close the stream if the stream does not support snatching
the buffer. On error NULL is stored at R_BUFFER. Note that if no
write operation has happened, NULL may also be stored at BUFFER on
success. The caller needs to release the returned memory using
es_free. */
int
es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen)
{
int err;
/* Note: There is no need to lock the stream in a close call. The
object will be destroyed after the close and thus any other
contender for the lock would work on a closed stream. */
if (r_buffer)
{
cookie_ioctl_function_t func_ioctl = stream->intern->func_ioctl;
size_t buflen;
*r_buffer = NULL;
if (!func_ioctl)
{
_set_errno (EOPNOTSUPP);
err = -1;
goto leave;
}
if (stream->flags.writing)
{
err = es_flush (stream);
if (err)
goto leave;
stream->flags.writing = 0;
}
err = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_SNATCH_BUFFER,
r_buffer, &buflen);
if (err)
goto leave;
if (r_buflen)
*r_buflen = buflen;
}
err = do_close (stream, 0);
leave:
if (err && r_buffer)
{
mem_free (*r_buffer);
*r_buffer = NULL;
}
return err;
}
/* Register or unregister a close notification function for STREAM.
FNC is the function to call and FNC_VALUE the value passed as
second argument. To register the notification the value for MODE

View File

@ -1,5 +1,5 @@
/* estream.h - Extended stream I/O Library
* Copyright (C) 2004, 2005, 2006, 2007, 2010 g10 Code GmbH
* Copyright (C) 2004, 2005, 2006, 2007, 2010, 2011 g10 Code GmbH
*
* This file is part of Libestream.
*
@ -88,6 +88,7 @@
#define es_freopen _ESTREAM_PREFIX(es_freopen)
#define es_fopencookie _ESTREAM_PREFIX(es_fopencookie)
#define es_fclose _ESTREAM_PREFIX(es_fclose)
#define es_fclose_snatch _ESTREAM_PREFIX(es_fclose_snatch)
#define es_onclose _ESTREAM_PREFIX(es_onclose)
#define es_fileno _ESTREAM_PREFIX(es_fileno)
#define es_fileno_unlocked _ESTREAM_PREFIX(es_fileno_unlocked)
@ -285,6 +286,7 @@ estream_t es_fopencookie (void *ES__RESTRICT cookie,
const char *ES__RESTRICT mode,
es_cookie_io_functions_t functions);
int es_fclose (estream_t stream);
int es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen);
int es_onclose (estream_t stream, int mode,
void (*fnc) (estream_t, void*), void *fnc_value);
int es_fileno (estream_t stream);

View File

@ -46,7 +46,7 @@ NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.5.0
NEED_LIBASSUAN_API=2
NEED_LIBASSUAN_VERSION=2.0.0
NEED_LIBASSUAN_VERSION=2.0.3
NEED_KSBA_API=1
NEED_KSBA_VERSION=1.2.0

View File

@ -15,21 +15,6 @@
* certcache.c (classify_pattern): Remove unused variable and make
explicit substring search work.
2011-11-24 Werner Koch <wk@g10code.com>
* ks-engine-http.c (ks_http_help): Do not print help for hkp.
* ks-engine-hkp.c (ks_hkp_help): Print help only for hkp.
(send_request): Remove test code.
(map_host): Use xtrymalloc.
* certcache.c (classify_pattern): Remove unused variable and make
explicit substring search work.
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
* Makefile.am, certcache.c, crlfetch.c, dirmngr.c, ldap-wrapper.c:
Port to NPth.
2011-06-01 Marcus Brinkmann <mb@g10code.com>
* Makefile.am (dirmngr_ldap_CFLAGS): Add $(LIBGCRYPT_CFLAGS),

View File

@ -1038,7 +1038,7 @@ main (int argc, char **argv)
if (csh_style)
{
*strchr (infostr, '=') = ' ';
es_printf ( "setenv %s\n", infostr);
es_printf ( "setenv %s;\n", infostr);
}
else
{

View File

@ -58,6 +58,10 @@ record; gpg2 does this by default and the option is a dummy.
u = The key is ultimately valid. This often means
that the secret key is available, but any key may
be marked as ultimately valid.
w = The key has a well known private part.
s = The key has special validity. This means that it
might be self-signed and expected to be used in
the STEED sytem.
If the validity information is given for a UID or UAT
record, it describes the validity calculated based on this
@ -347,6 +351,7 @@ more arguments in future versions.
"pgp" for the standard PGP WoT.
"shell" for the standard X.509 model.
"chain" for the chain model.
"steed" for the STEED model.
Note that we use the term "TRUST_" in the status names for
historic reasons; we now speak of validity.
@ -1036,6 +1041,7 @@ OIDs below the GnuPG arc:
1.3.6.1.4.1.11591.2.1.1 pkaAddress
1.3.6.1.4.1.11591.2.2 X.509 extensions
1.3.6.1.4.1.11591.2.2.1 standaloneCertificate
1.3.6.1.4.1.11591.2.2.2 wellKnownPrivateKey
1.3.6.1.4.1.11591.2.12242973 invalid encoded OID

View File

@ -23,7 +23,8 @@ and ChangeLog entries don't give enough of the big picture. Omit the
leading TABs that you're used to seeing in a "real" ChangeLog file, but
keep the maximum line length at 72 or smaller, so that the generated
ChangeLog lines, each with its leading TAB, will not exceed 80 columns.
If you want to add text which shall not be copied to the ChangeLog,
separate it by a line consisting of two dashes at the begin of a line.
===> What follows is probably out of date <===
@ -39,15 +40,17 @@ RFCs
1750 Randomness Recommendations for Security.
1991 PGP Message Exchange Formats.
2015 MIME Security with Pretty Good Privacy (PGP).
1991 PGP Message Exchange Formats (obsolete)
2144 The CAST-128 Encryption Algorithm.
2279 UTF-8, a transformation format of ISO 10646.
2440 OpenPGP.
2440 OpenPGP (obsolete).
3156 MIME Security with Pretty Good Privacy (PGP).
4880 Current OpenPGP specification.

View File

@ -482,3 +482,21 @@ G1RRiCiWgYaEtSIDAP0V9ehpcghfJLlmMBnxSf4n7OZvkd1whvme2rXaQxnZi2qV
d2qclY03eJ7zx6Zpq8VFuVvOxvmFZ4mMe706runhCq+rHc5x6x0/oIMhDrk=
-----END CERTIFICATE-----
Issuer ...: /CN=The STEED Self-Signing Nonthority
Serial ...: 01
Subject ..: /CN=The STEED Self-Signing Nonthority
-----BEGIN CERTIFICATE-----
MIICKDCCAZGgAwIBAgIBATANBgkqhkiG9w0BAQUFADAsMSowKAYDVQQDEyFUaGUg
U1RFRUQgU2VsZi1TaWduaW5nIE5vbnRob3JpdHkwIBcNMTExMTExMDAwMDAwWhgP
MjEwNjAyMDYwMDAwMDBaMCwxKjAoBgNVBAMTIVRoZSBTVEVFRCBTZWxmLVNpZ25p
bmcgTm9udGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAk2h9kqe8
0eb8ESY7UGV6j6S5zuP5DiM4TWJ3jKG2y+D2CyA1Sl90iZ6zyN3zCB0yR1xxhpuw
xdrwBRovRFludAbx3MeynYhzXkk0Hwn038q1oIt2YUw3Igz34s24o455ZE86JQ/6
5dC7ppF8Z1I9KBL96NO+qZR/alVAKxYAwS8CAwEAAaNYMFYwEgYDVR0TAQH/BAgw
BgEB/wIBATARBgorBgEEAdpHAgICBAMBAf8wHQYDVR0OBBYEFGimOJmN+rrFEOpk
XONPloay7ffqMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQB3JwUn
AbOdGv5ErojNSSP+yGZIy5av4wnkzK840Uj3jY6A5cuHroZGOD60hqLV2Hy0npox
zte4phWEKWmZiXd8SCmd3MFNgZSieiixye0qxSmuqYft2j6NhEXD5xc/iTTjFT42
SjGPLKAICuMBuGPnoozOEVlgqwaDqKOUph5sqw==
-----END CERTIFICATE-----

View File

@ -1167,13 +1167,8 @@ update this FAQ in the next month. See the section "Changes" for recent updates
:CUSTOM_ID: i-get-sed-errors-when-running-configure-on-mac-os-x
:END:
This will be fixed after GnuPG has been upgraded to autoconf-2.50.
Until then, find the line setting CDPATH in the configure script
and place an:
: unset CDPATH
statement below it.
This problem has been fixed for all modern GnuPG versions.
(By using an autoconf 2.50 generated configure script).
** Why does GnuPG 1.0.6 bail out on keyrings used with 1.0.7?
:PROPERTIES:
@ -1470,6 +1465,41 @@ update this FAQ in the next month. See the section "Changes" for recent updates
of the listing before before starting the import.
* Bug reporting and hacking
:PROPERTIES:
:CUSTOM_ID: bugreports-et-al
:END:
** Copyright asssignments
:PROPERTIES:
:CUSTOM_ID: copyright-assigments
:END:
** U.S. export restrictions
:PROPERTIES:
:CUSTOM_ID: us-export-restrictions
:END:
GnuPG has originally been developed in Germany because we have been
able to do that without being affected by the US export restrictions.
We had to reject any contributions from US citizens or from people
living the the US. That changed by end of 2000 when the export
restrictions were basically dropped for all kind of freely available
software. However there are still some requirements in the US.
Quoting David Shaw: mail
#+begin_quote
For each release of GPG that I contributed to, I sent an email
containing a pointer to the new source code to the Commerce
Department. The rules changed slightly in 2004, so that you could
send a single email and then be done until the information in that
email changed, so I just sent "www.gnupg.org" and haven't bothered
with the email since.
#+end_quote
The rules: http://www.bis.doc.gov/encryption/pubavailencsourcecodenofify.html
The 2004 rule change: http://edocket.access.gpo.gov/2004/04-26992.htm
* Acknowledgements
:PROPERTIES:
:CUSTOM_ID: acknowledgements

View File

@ -451,10 +451,11 @@ address and the time when you verified the signature.
@item --validation-model @var{name}
@opindex validation-model
This option changes the default validation model. The only possible
values are "shell" (which is the default) and "chain" which forces the
use of the chain model. The chain model is also used if an option in
the @file{trustlist.txt} or an attribute of the certificate requests it.
However the standard model (shell) is in that case always tried first.
values are "shell" (which is the default), "chain" which forces the
use of the chain model and "steed" for a new simplified model. The
chain model is also used if an option in the @file{trustlist.txt} or
an attribute of the certificate requests it. However the standard
model (shell) is in that case always tried first.
@item --ignore-cert-extension @var{oid}
@opindex ignore-cert-extension
@ -1042,9 +1043,9 @@ already existing key. Key-Length will be ignored when given.
@item Key-Usage: @var{usage-list}
Space or comma delimited list of key usage, allowed values are
@samp{encrypt} and @samp{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.
@samp{encrypt}, @samp{sign} and @samp{cert}. 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.
@item Name-DN: @var{subject-name}
This is the Distinguished Name (DN) of the subject in RFC-2253 format.

View File

@ -21,16 +21,16 @@
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.B \-\-server
.RI [ options ]
.B \-\-server
.br
.B scdaemon
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
.RI [ options ]
.B \-\-daemon
.RI [ options ]
.B \-\-daemon
.RI [ command_line ]
@end ifset
@ -130,7 +130,7 @@ a numeric value or a keyword:
@item none
No debugging at all. A value of less than 1 may be used instead of
the keyword.
@item basic
@item basic
Some basic debug messages. A value between 1 and 2 may be used
instead of the keyword.
@item advanced
@ -165,8 +165,8 @@ usual C-Syntax. The currently defined bits are:
@table @code
@item 0 (1)
command I/O
@item 1 (2)
values of big number integers
@item 1 (2)
values of big number integers
@item 2 (4)
low level crypto operations
@item 5 (32)
@ -178,9 +178,11 @@ show memory statistics.
@item 9 (512)
write hashed data to files named @code{dbgmd-000*}
@item 10 (1024)
trace Assuan protocol
trace Assuan protocol. See also option @option{--debug-assuan-log-cats}.
@item 11 (2048)
trace APDU I/O to the card. This may reveal sensitive data.
@item 12 (4096)
trace some card reader related function calls.
@end table
@item --debug-all
@ -215,6 +217,15 @@ dump. This options enables it and also changes the working directory to
@opindex debug-log-tid
This option appends a thread ID to the PID in the log output.
@item --debug-assuan-log-cats @var{cats}
@opindex debug-assuan-log-cats
Changes the active Libassuan logging categories to @var{cats}. The
value for @var{cats} is an unsigned integer given in usual C-Syntax.
A value of of 0 switches to a default category. If this option is not
used the categories are taken from the environment variable
@samp{ASSUAN_DEBUG}. Note that this option has only an effect if the
Assuan debug flag has also been with the option @option{--debug}. For
a list of categories see the Libassuan manual.
@item --no-detach
@opindex no-detach
@ -240,7 +251,7 @@ Use @var{library} to access the smartcard reader. The current default
is @file{libtowitoko.so}. Note that the use of this interface is
deprecated; it may be removed in future releases.
@item --disable-ccid
@item --disable-ccid
@opindex disable-ccid
Disable the integrated support for CCID compliant readers. This
allows to fall back to one of the other drivers even if the internal
@ -318,6 +329,7 @@ stripping off the two leading dashes.
* DINSIG Card:: The DINSIG card application
* PKCS#15 Card:: The PKCS#15 card application
* Geldkarte Card:: The Geldkarte application
* Undefined Card:: The Undefined stub application
@end menu
@node OpenPGP Card
@ -325,7 +337,7 @@ stripping off the two leading dashes.
This application is currently only used by @command{gpg} but may in
future also be useful with @command{gpgsm}. Version 1 and version 2 of
the card is supported.
the card is supported.
The specifications for these cards are available at
@uref{http://g10code.com/docs/openpgp-card-1.0.pdf} and
@ -358,6 +370,14 @@ This is a simple application to display information of a German
Geldkarte. The Geldkarte is a small amount debit card application which
comes with almost all German banking cards.
@node Undefined Card
@subsection The Undefined card application ``undefined''
This is a stub application to allow the use of the APDU command even
if no supported application is found on the card. This application is
not used automatically but must be explicitly requested using the
SERIALNO command.
@c *******************************************
@c *************** ****************
@ -395,7 +415,7 @@ about reader status changes. Its use is now deprecated in favor of
@end table
@c
@c
@c Examples
@c
@mansect examples
@ -410,7 +430,7 @@ $ scdaemon --server -v
@c man end
@c
@c
@c Assuan Protocol
@c
@manpause
@ -447,7 +467,7 @@ synchronizing access to a token between sessions.
* Scdaemon APDU:: Send a verbatim APDU to the card
@end menu
@node Scdaemon SERIALNO
@node Scdaemon SERIALNO
@subsection Return the serial number
This command should be used to check for the presence of a card. It is
@ -470,7 +490,7 @@ Return the serial number of the card using a status response like:
@end example
The trailing 0 should be ignored for now, it is reserved for a future
extension. The serial number is the hex encoded value identified by
extension. The serial number is the hex encoded value identified by
the @code{0x5A} tag in the GDO file (FIX=0x2F02).
@ -522,7 +542,7 @@ READKEY @var{hexified_certid}
@end example
Return the public key for the given cert or key ID as an standard
S-Expression.
S-Expression.
@ -619,7 +639,7 @@ TO BE WRITTEN.
@example
PASSWD [--reset] [--nullpin] @var{chvno}
@end example
Change the PIN or reset the retry counter of the card holder
verification vector number @var{chvno}. The option @option{--nullpin}
is used to initialize the PIN of TCOS cards (6 byte NullPIN only).
@ -663,11 +683,11 @@ and only if the retry counter is still at 3.
Restart the current connection; this is a kind of warm reset. It
deletes the context used by this connection but does not actually
reset the card.
reset the card.
This is used by gpg-agent to reuse a primary pipe connection and
may be used by clients to backup from a conflict in the serial
command; i.e. to select another application.
command; i.e. to select another application.
@ -704,7 +724,7 @@ length up to N bytes. If N is not given a default value is used
@mansect see also
@ifset isman
@command{gpg-agent}(1),
@command{gpgsm}(1),
@command{gpgsm}(1),
@command{gpg2}(1)
@end ifset
@include see-also-note.texi

View File

@ -1,5 +1,5 @@
/* photoid.c - photo ID handling code
* Copyright (C) 2001, 2002, 2005, 2006, 2008 Free Software Foundation, Inc.
* Copyright (C) 2001, 2002, 2005, 2006, 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -141,8 +141,7 @@ generate_photo_id(PKT_public_key *pk,const char *photo_name)
iobuf_close(file);
/* Is it a JPEG? */
if(photo[0]!=0xFF || photo[1]!=0xD8 ||
photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F')
if(photo[0]!=0xFF || photo[1]!=0xD8)
{
log_error(_("`%s' is not a JPEG file\n"),filename);
xfree(photo);

View File

@ -353,6 +353,8 @@ main ( int argc, char **argv)
i18n_init ();
init_common_subsystems (&argc, &argv);
npth_init ();
/* Check that the Libgcrypt is suitable. */
if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
@ -658,6 +660,7 @@ main ( int argc, char **argv)
#endif /*0*/
/* Dispatch command. */
err = 0;
switch (cmd)
{
case aGPGConfList:

View File

@ -241,9 +241,10 @@ static int
get_key(char *getkey)
{
CURLcode res;
char request[MAX_URL+60];
char request[MAX_URL+92];
char *offset;
struct curl_writer_ctx ctx;
size_t keylen;
memset(&ctx,0,sizeof(ctx));
@ -269,14 +270,19 @@ get_key(char *getkey)
strcat(request,port);
strcat(request,opt->path);
/* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
including any supplied path. The 60 overcovers this /pks/... etc
string plus the 8 bytes of key id */
including any supplied path. The 92 overcovers this /pks/... etc
string plus the 8, 16, or 40 bytes of key id/fingerprint */
append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
/* fingerprint or long key id. Take the last 8 characters and treat
it like a short key id */
if(strlen(getkey)>8)
offset=&getkey[strlen(getkey)-8];
/* send only fingerprint, long key id, or short keyid. see:
https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-3.1.1.1 */
keylen = strlen(getkey);
if(keylen >= 40)
offset=&getkey[keylen-40];
else if(keylen >= 16)
offset=&getkey[keylen-16];
else if(keylen >= 8)
offset=&getkey[keylen-8];
else
offset=getkey;

View File

@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: gnupg-2.1.0\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2011-11-24 14:15+0100\n"
"PO-Revision-Date: 2011-12-20 15:52+0100\n"
"Last-Translator: Werner Koch <wk@gnupg.org>\n"
"Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\n"
@ -111,9 +111,9 @@ msgstr "Fehler beim Holen der Karten-Seriennummer: %s\n"
msgid "detected card with S/N: %s\n"
msgstr "Erkannte Karte hat die Seriennummer: %s\n"
#, fuzzy, c-format
#, c-format
msgid "no authentication key for ssh on card: %s\n"
msgstr "Fehler beim Holen der Authentisierungsschlüssel-ID der Karte: %s\n"
msgstr "Auf der Karte ist kein Authentisierungsschlüssel für SSH: %s\n"
#, c-format
msgid "no suitable card key found: %s\n"
@ -5434,17 +5434,11 @@ msgstr "|AN|Neue Admin-PIN"
msgid "|N|New PIN"
msgstr "|N|Neue PIN"
#, fuzzy
msgid "||Please enter the Reset Code for the card and New PIN"
msgstr "Bitte geben Sie den Rückstellcode für diese Karte ein"
#, fuzzy
msgid "||Please enter the Admin PIN and New Admin PIN"
msgstr "|A|Bitte die Admin-PIN eingeben."
msgstr "|A|Bitte die Admin-PIN sowie die neue Admin-PIN eingeben."
#, fuzzy
msgid "||Please enter the PIN and New PIN"
msgstr "||Bitte die PIN eingeben"
msgstr "||Bitte die PIN sowie die neue PIN eingeben"
msgid "error reading application data\n"
msgstr "Fehler beim Lesen der Anwendungsdaten\n"
@ -5880,6 +5874,18 @@ msgstr ""
msgid "line %d: invalid hash algorithm given\n"
msgstr "Zeile %d: Ungültiges Hashverfahren\n"
#, c-format
msgid "line %d: invalid authority-key-id\n"
msgstr "Zeile %d: Ungültige Authentisierungsschlüssel-ID\n"
#, c-format
msgid "line %d: invalid subject-key-id\n"
msgstr "Zeile %d: ungültige \"Subject-Key-Id\"\n"
#, c-format
msgid "line %d: invalid extension syntax\n"
msgstr "Zeile %d: Ungültiger Syntax der Extension\n"
#, c-format
msgid "line %d: error reading key `%s' from card: %s\n"
msgstr "Zeile %d: Fehler beim Lesen des Schlüssels `%s' von der Karte: %s\n"
@ -7925,6 +7931,10 @@ msgstr ""
"Syntax: gpg-check-pattern [optionen] Musterdatei\n"
"Die von stdin gelesene Passphrase gegen die Musterdatei prüfen\n"
#, fuzzy
#~ msgid "||Please enter the Reset Code for the card and New PIN"
#~ msgstr "Bitte geben Sie den Rückstellcode für diese Karte ein"
#~ msgid " - probably dead - removing lock"
#~ msgstr " - existiert wahrscheinlich nicht mehr - entferne Sperre"

View File

@ -87,10 +87,6 @@
(handle_control): New.
(main): Handle the case 6 of handle_control.
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
* Makefile.am, apdu.c, app.c, command.c, scdaemon.c: Port to Npth.
2011-08-10 Werner Koch <wk@g10code.com>
* command.c (cmd_killscd): Use the new assuan force close flag

View File

@ -37,6 +37,7 @@ card_apps = app-openpgp.c app-nks.c app-dinsig.c app-p15.c app-geldkarte.c
scdaemon_SOURCES = \
scdaemon.c scdaemon.h \
command.c \
atr.c atr.h \
apdu.c apdu.h \
ccid-driver.c ccid-driver.h \
iso7816.c iso7816.h \

View File

@ -465,8 +465,11 @@ apdu_strerror (int rc)
case SW_FILE_NOT_FOUND : return "file not found";
case SW_RECORD_NOT_FOUND:return "record not found";
case SW_REF_NOT_FOUND : return "reference not found";
case SW_BAD_LC : return "bad Lc";
case SW_BAD_P0_P1 : return "bad P0 or P1";
case SW_NOT_ENOUGH_MEMORY: return "not enough memory space in the file";
case SW_INCONSISTENT_LC: return "Lc inconsistent with TLV structure.";
case SW_INCORRECT_P0_P1: return "incorrect parameters P0,P1";
case SW_BAD_LC : return "Lc inconsistent with P0,P1";
case SW_BAD_P0_P1 : return "bad P0,P1";
case SW_INS_NOT_SUP : return "instruction not supported";
case SW_CLA_NOT_SUP : return "class not supported";
case SW_SUCCESS : return "success";
@ -2052,7 +2055,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
{
int sw;
unsigned char *pin_verify;
unsigned long len = PIN_VERIFY_STRUCTURE_SIZE;
int len = PIN_VERIFY_STRUCTURE_SIZE;
unsigned char result[2];
size_t resultlen = 2;
@ -2108,12 +2111,23 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
pin_verify[22] = p1; /* abData[3] */
pin_verify[23] = 0x00; /* abData[4] */
if (DBG_CARD_IO)
log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
class, ins, p0, p1, len, pininfo->maxlen);
sw = control_pcsc (slot, reader_table[slot].pcsc.verify_ioctl,
pin_verify, len, result, &resultlen);
xfree (pin_verify);
if (sw || resultlen < 2)
return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
sw = (result[resultlen-2] << 8) | result[resultlen-1];
{
log_error ("control_pcsc failed: %d\n", sw);
return sw? sw: SW_HOST_INCOMPLETE_CARD_RESPONSE;
}
sw = (result[resultlen-2] << 8) | result[resultlen-1];
if (DBG_CARD_IO)
log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen);
return sw;
}
@ -2125,7 +2139,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
{
int sw;
unsigned char *pin_modify;
unsigned long len = PIN_MODIFY_STRUCTURE_SIZE;
int len = PIN_MODIFY_STRUCTURE_SIZE;
unsigned char result[2];
size_t resultlen = 2;
@ -2192,12 +2206,21 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
pin_modify[27] = p1; /* abData[3] */
pin_modify[28] = 0x00; /* abData[4] */
if (DBG_CARD_IO)
log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
class, ins, p0, p1, len, (int)pininfo->maxlen);
sw = control_pcsc (slot, reader_table[slot].pcsc.modify_ioctl,
pin_modify, len, result, &resultlen);
xfree (pin_modify);
if (sw || resultlen < 2)
return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
{
log_error ("control_pcsc failed: %d\n", sw);
return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
}
sw = (result[resultlen-2] << 8) | result[resultlen-1];
if (DBG_CARD_IO)
log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen);
return sw;
}
@ -2783,6 +2806,9 @@ apdu_open_reader (const char *portstr, int *r_no_service)
static int pcsc_api_loaded, ct_api_loaded;
int slot;
if (DBG_READER)
log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
if (r_no_service)
*r_no_service = 0;
@ -2797,6 +2823,8 @@ apdu_open_reader (const char *portstr, int *r_no_service)
if (slot != -1)
{
once_available = 1;
if (DBG_READER)
log_debug ("leave: apdu_open_reader => slot=%d [ccid]\n", slot);
return slot; /* got one */
}
@ -2807,14 +2835,22 @@ apdu_open_reader (const char *portstr, int *r_no_service)
and over again. To reset this flag "gpgconf --kill scdaemon"
can be used. */
if (once_available)
return -1;
{
if (DBG_READER)
log_debug ("leave: apdu_open_reader => slot=-1 (once_avail)\n");
return -1;
}
/* If a CCID reader specification has been given, the user does
not want a fallback to other drivers. */
if (portstr)
for (s=portstr, i=0; *s; s++)
if (*s == ':' && (++i == 3))
return -1;
{
if (DBG_READER)
log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
return -1;
}
}
#endif /* HAVE_LIBUSB */
@ -2939,6 +2975,8 @@ apdu_open_reader (const char *portstr, int *r_no_service)
if (slot == -1 && r_no_service && pcsc_no_service)
*r_no_service = 1;
if (DBG_READER)
log_debug ("leave: apdu_open_reader => slot=%d [pc/sc]\n", slot);
return slot;
}
@ -2993,13 +3031,31 @@ apdu_close_reader (int slot)
{
int sw;
if (DBG_READER)
log_debug ("enter: apdu_close_reader: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
{
if (DBG_READER)
log_debug ("leave: apdu_close_reader => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER;
}
sw = apdu_disconnect (slot);
if (sw)
return sw;
{
if (DBG_READER)
log_debug ("leave: apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
return sw;
}
if (reader_table[slot].close_reader)
return reader_table[slot].close_reader (slot);
{
sw = reader_table[slot].close_reader (slot);
if (DBG_READER)
log_debug ("leave: apdu_close_reader => 0x%x (close_reader)\n", sw);
return sw;
}
if (DBG_READER)
log_debug ("leave: apdu_close_reader => SW_HOST_NOT_SUPPORTED\n");
return SW_HOST_NOT_SUPPORTED;
}
@ -3038,13 +3094,32 @@ apdu_shutdown_reader (int slot)
{
int sw;
if (DBG_READER)
log_debug ("enter: apdu_shutdown_reader: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
{
if (DBG_READER)
log_debug ("leave: apdu_shutdown_reader => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER;
}
sw = apdu_disconnect (slot);
if (sw)
return sw;
{
if (DBG_READER)
log_debug ("leave: apdu_shutdown_reader => 0x%x (apdu_disconnect)\n",
sw);
return sw;
}
if (reader_table[slot].shutdown_reader)
return reader_table[slot].shutdown_reader (slot);
{
sw = reader_table[slot].shutdown_reader (slot);
if (DBG_READER)
log_debug ("leave: apdu_shutdown_reader => 0x%x (close_reader)\n", sw);
return sw;
}
if (DBG_READER)
log_debug ("leave: apdu_shutdown_reader => SW_HOST_NOT_SUPPORTED\n");
return SW_HOST_NOT_SUPPORTED;
}
@ -3062,14 +3137,24 @@ apdu_enum_reader (int slot, int *used)
/* Connect a card. This is used to power up the card and make sure
that an ATR is available. */
that an ATR is available. Depending on the reader backend it may
return an error for an inactive card or if no card is
available. */
int
apdu_connect (int slot)
{
int sw;
unsigned int status;
if (DBG_READER)
log_debug ("enter: apdu_connect: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
{
if (DBG_READER)
log_debug ("leave: apdu_connect => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER;
}
/* Only if the access method provides a connect function we use it.
If not, we expect that the card has been implicitly connected by
@ -3091,7 +3176,16 @@ apdu_connect (int slot)
scdaemon is fired up and apdu_get_status has not yet been called.
Without that we would force a reset of the card with the next
call to apdu_get_status. */
apdu_get_status_internal (slot, 1, 1, NULL, NULL);
apdu_get_status_internal (slot, 1, 1, &status, NULL);
if (sw)
;
else if (!(status & APDU_CARD_PRESENT))
sw = SW_HOST_NO_CARD;
else if ((status & APDU_CARD_PRESENT) && !(status & APDU_CARD_ACTIVE))
sw = SW_HOST_CARD_INACTIVE;
if (DBG_READER)
log_debug ("leave: apdu_connect => sw=0x%x\n", sw);
return sw;
}
@ -3102,8 +3196,15 @@ apdu_disconnect (int slot)
{
int sw;
if (DBG_READER)
log_debug ("enter: apdu_disconnect: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
{
if (DBG_READER)
log_debug ("leave: apdu_disconnect => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER;
}
if (reader_table[slot].disconnect_card)
{
@ -3116,6 +3217,9 @@ apdu_disconnect (int slot)
}
else
sw = 0;
if (DBG_READER)
log_debug ("leave: apdu_disconnect => sw=0x%x\n", sw);
return sw;
}
@ -3151,11 +3255,22 @@ apdu_reset (int slot)
{
int sw;
if (DBG_READER)
log_debug ("enter: apdu_reset: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
{
if (DBG_READER)
log_debug ("leave: apdu_reset => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER;
}
if ((sw = lock_slot (slot)))
return sw;
{
if (DBG_READER)
log_debug ("leave: apdu_reset => sw=0x%x (lock_slot)\n", sw);
return sw;
}
reader_table[slot].last_status = 0;
if (reader_table[slot].reset_reader)
@ -3171,73 +3286,47 @@ apdu_reset (int slot)
}
unlock_slot (slot);
if (DBG_READER)
log_debug ("leave: apdu_reset => sw=0x%x\n", sw);
return sw;
}
/* Activate a card if it has not yet been done. This is a kind of
reset-if-required. It is useful to test for presence of a card
before issuing a bunch of apdu commands. It does not wait on a
locked card. */
int
apdu_activate (int slot)
{
int sw;
unsigned int s;
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
if ((sw = trylock_slot (slot)))
return sw;
if (reader_table[slot].get_status_reader)
sw = reader_table[slot].get_status_reader (slot, &s);
if (!sw)
{
if (!(s & 2)) /* Card not present. */
sw = SW_HOST_NO_CARD;
else if ( ((s & 2) && !(s & 4))
|| !reader_table[slot].atrlen )
{
/* We don't have an ATR or a card is present though inactive:
do a reset now. */
if (reader_table[slot].reset_reader)
{
reader_table[slot].last_status = 0;
sw = reader_table[slot].reset_reader (slot);
if (!sw)
{
/* If we got to here we know that a card is present
and usable. Thus remember this. */
reader_table[slot].last_status = (APDU_CARD_USABLE
| APDU_CARD_PRESENT
| APDU_CARD_ACTIVE);
}
}
}
}
unlock_slot (slot);
return sw;
}
/* Return the ATR or NULL if none is available. On success the length
of the ATR is stored at ATRLEN. The caller must free the returned
value. */
unsigned char *
apdu_get_atr (int slot, size_t *atrlen)
{
unsigned char *buf;
if (DBG_READER)
log_debug ("enter: apdu_get_atr: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return NULL;
{
if (DBG_READER)
log_debug ("leave: apdu_get_atr => NULL (bad slot)\n");
return NULL;
}
if (!reader_table[slot].atrlen)
return NULL;
{
if (DBG_READER)
log_debug ("leave: apdu_get_atr => NULL (no ATR)\n");
return NULL;
}
buf = xtrymalloc (reader_table[slot].atrlen);
if (!buf)
return NULL;
{
if (DBG_READER)
log_debug ("leave: apdu_get_atr => NULL (out of core)\n");
return NULL;
}
memcpy (buf, reader_table[slot].atr, reader_table[slot].atrlen);
*atrlen = reader_table[slot].atrlen;
if (DBG_READER)
log_debug ("leave: apdu_get_atr => atrlen=%zu\n", *atrlen);
return buf;
}
@ -3308,7 +3397,26 @@ int
apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed)
{
return apdu_get_status_internal (slot, hang, 0, status, changed);
int sw;
if (DBG_READER)
log_debug ("enter: apdu_get_status: slot=%d hang=%d\n", slot, hang);
sw = apdu_get_status_internal (slot, hang, 0, status, changed);
if (DBG_READER)
{
if (status && changed)
log_debug ("leave: apdu_get_status => sw=0x%x status=%u changecnt=%u\n",
sw, *status, *changed);
else if (status)
log_debug ("leave: apdu_get_status => sw=0x%x status=%u\n",
sw, *status);
else if (changed)
log_debug ("leave: apdu_get_status => sw=0x%x changed=%u\n",
sw, *changed);
else
log_debug ("leave: apdu_get_status => sw=0x%x\n", sw);
}
return sw;
}

View File

@ -41,6 +41,9 @@ enum {
SW_NOT_SUPPORTED = 0x6a81,
SW_FILE_NOT_FOUND = 0x6a82,
SW_RECORD_NOT_FOUND = 0x6a83,
SW_NOT_ENOUGH_MEMORY= 0x6a84, /* Not enough memory space in the file. */
SW_INCONSISTENT_LC = 0x6a85, /* Lc inconsistent with TLV structure. */
SW_INCORRECT_P0_P1 = 0x6a86,
SW_BAD_LC = 0x6a87, /* Lc does not match command or p1/p2. */
SW_REF_NOT_FOUND = 0x6a88,
SW_BAD_P0_P1 = 0x6b00,
@ -108,7 +111,6 @@ int apdu_disconnect (int slot);
int apdu_set_progress_cb (int slot, gcry_handler_progress_t cb, void *cb_arg);
int apdu_activate (int slot);
int apdu_reset (int slot);
int apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed);

View File

@ -143,7 +143,8 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
/*-- app.c --*/
void app_dump_state (void);
void application_notify_card_reset (int slot);
gpg_error_t check_application_conflict (ctrl_t ctrl, const char *name);
gpg_error_t check_application_conflict (ctrl_t ctrl, int slot,
const char *name);
gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name,
app_t *r_app);
char *get_supported_applications (void);

102
scd/app.c
View File

@ -198,18 +198,19 @@ application_notify_card_reset (int slot)
used to request a specific application and the connection has
already done a select_application. */
gpg_error_t
check_application_conflict (ctrl_t ctrl, const char *name)
check_application_conflict (ctrl_t ctrl, int slot, const char *name)
{
int slot = ctrl->reader_slot;
app_t app;
(void)ctrl;
if (slot < 0 || slot >= DIM (lock_table))
return gpg_error (GPG_ERR_INV_VALUE);
app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
if (app && app->apptype && name)
if ( ascii_strcasecmp (app->apptype, name))
return gpg_error (GPG_ERR_CONFLICT);
return gpg_error (GPG_ERR_CONFLICT);
return 0;
}
@ -226,11 +227,14 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
app_t app = NULL;
unsigned char *result = NULL;
size_t resultlen;
int want_undefined;
(void)ctrl;
*r_app = NULL;
want_undefined = (name && !strcmp (name, "undefined"));
err = lock_reader (slot, ctrl);
if (err)
return err;
@ -310,45 +314,49 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
/* Fixme: We should now first check whether a card is at all
present. */
/* Try to read the GDO file first to get a default serial number. */
err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
if (!err)
err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
if (!err)
err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
if (!err)
/* Try to read the GDO file first to get a default serial number.
We skip this if the undefined application has been requested. */
if (!want_undefined)
{
size_t n;
const unsigned char *p;
p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
if (p)
resultlen -= (p-result);
if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
if (!err)
err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
if (!err)
err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
if (!err)
{
/* The object 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. */
log_info ("enabling BMI testcard workaround\n");
n--;
}
size_t n;
const unsigned char *p;
if (p && n <= resultlen)
{
/* The GDO file is pretty short, thus we simply reuse it for
storing the serial number. */
memmove (result, p, n);
app->serialno = result;
app->serialnolen = n;
err = app_munge_serialno (app);
if (err)
goto leave;
p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
if (p)
resultlen -= (p-result);
if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
{
/* The object 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. */
log_info ("enabling BMI testcard workaround\n");
n--;
}
if (p && n <= resultlen)
{
/* The GDO file is pretty short, thus we simply reuse it for
storing the serial number. */
memmove (result, p, n);
app->serialno = result;
app->serialnolen = n;
err = app_munge_serialno (app);
if (err)
goto leave;
}
else
xfree (result);
result = NULL;
}
else
xfree (result);
result = NULL;
}
/* For certain error codes, there is no need to try more. */
@ -357,7 +365,15 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
goto leave;
/* Figure out the application to use. */
err = gpg_error (GPG_ERR_NOT_FOUND);
if (want_undefined)
{
/* We switch to the "undefined" application only if explicitly
requested. */
app->apptype = "UNDEFINED";
err = 0;
}
else
err = gpg_error (GPG_ERR_NOT_FOUND);
if (err && is_app_allowed ("openpgp")
&& (!name || !strcmp (name, "openpgp")))
@ -366,11 +382,11 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
err = app_select_nks (app);
if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
err = app_select_p15 (app);
if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
err = app_select_dinsig (app);
if (err && is_app_allowed ("geldkarte")
&& (!name || !strcmp (name, "geldkarte")))
err = app_select_geldkarte (app);
if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
err = app_select_dinsig (app);
if (err && name)
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
@ -404,8 +420,10 @@ get_supported_applications (void)
"openpgp",
"nks",
"p15",
"dinsig",
"geldkarte",
"dinsig",
/* Note: "undefined" is not listed here because it needs special
treatment by the client. */
NULL
};
int idx;

252
scd/atr.c
View File

@ -1,5 +1,5 @@
/* atr.c - ISO 7816 ATR fucntions
* Copyright (C) 2003 Free Software Foundation, Inc.
* Copyright (C) 2003, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -24,10 +24,9 @@
#include <string.h>
#include <assert.h>
#include "scdaemon.h"
#include "apdu.h"
#include "../common/estream.h"
#include "../common/logging.h"
#include "atr.h"
#include "dynload.h"
static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
-1, 512, 768, 1024, 1536, 2048, -1, -1 };
@ -35,37 +34,42 @@ static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
0, -1, -2, -4, -8, -16, -32, -64};
/* Dump the ATR of the card at SLOT in a human readable format to
stream FP. */
int
atr_dump (int slot, FILE *fp)
/* Dump the ATR in (BUFFER,BUFLEN) to a human readable format and
return that as a malloced buffer. The caller must release this
buffer using es_free! On error this function returns NULL and sets
ERRNO. */
char *
atr_dump (const void *buffer, size_t buflen)
{
unsigned char *atrbuffer, *atr;
size_t atrlen;
const unsigned char *atr = buffer;
size_t atrlen = buflen;
estream_t fp;
int have_ta, have_tb, have_tc, have_td;
int n_historical;
int idx, val;
unsigned char chksum;
char *result;
atr = atrbuffer = apdu_get_atr (slot, &atrlen);
if (!atr)
return gpg_error (GPG_ERR_GENERAL);
fp = es_fopenmem (0, "rwb");
if (!fp)
return NULL;
fprintf (fp, "Info on ATR of length %u at slot %d\n",
(unsigned int)atrlen, slot);
if (!atrlen)
{
fprintf (fp, "error: empty ATR\n");
es_fprintf (fp, "error: empty ATR\n");
goto bailout;
}
for (idx=0; idx < atrlen ; idx++)
es_fprintf (fp, "%s%02X", idx?" ":"", atr[idx]);
es_putc ('\n', fp);
if (*atr == 0x3b)
fputs ("direct convention\n", fp);
es_fputs ("Direct convention\n", fp);
else if (*atr == 0x3f)
fputs ("inverse convention\n", fp);
es_fputs ("Inverse convention\n", fp);
else
fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
es_fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
if (!--atrlen)
goto bailout;
atr++;
@ -79,34 +83,34 @@ atr_dump (int slot, FILE *fp)
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
n_historical = (*atr & 0x0f);
fprintf (fp, "%d historical characters indicated\n", n_historical);
es_fprintf (fp, "%d historical characters indicated\n", n_historical);
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
fputs ("error: ATR shorter than indicated by format character\n", fp);
es_fputs ("error: ATR shorter than indicated by format character\n", fp);
if (!--atrlen)
goto bailout;
atr++;
if (have_ta)
{
fputs ("TA1: F=", fp);
es_fputs ("TA1: F=", fp);
val = fi_table[(*atr >> 4) & 0x0f];
if (!val)
fputs ("internal clock", fp);
es_fputs ("internal clock", fp);
else if (val == -1)
fputs ("RFU", fp);
es_fputs ("RFU", fp);
else
fprintf (fp, "%d", val);
fputs (" D=", fp);
es_fprintf (fp, "%d", val);
es_fputs (" D=", fp);
val = di_table[*atr & 0x0f];
if (!val)
fputs ("[impossible value]\n", fp);
es_fputs ("[impossible value]\n", fp);
else if (val == -1)
fputs ("RFU\n", fp);
es_fputs ("RFU\n", fp);
else if (val < 0 )
fprintf (fp, "1/%d\n", val);
es_fprintf (fp, "1/%d\n", val);
else
fprintf (fp, "%d\n", val);
es_fprintf (fp, "%d\n", val);
if (!--atrlen)
goto bailout;
@ -115,8 +119,9 @@ atr_dump (int slot, FILE *fp)
if (have_tb)
{
fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
(*atr & 0x80)? " [high bit not cleared]":"");
es_fprintf (fp, "TB1: II=%d PI1=%d%s\n",
((*atr >> 5) & 3), (*atr & 0x1f),
(*atr & 0x80)? " [high bit not cleared]":"");
if (!--atrlen)
goto bailout;
atr++;
@ -125,9 +130,9 @@ atr_dump (int slot, FILE *fp)
if (have_tc)
{
if (*atr == 255)
fputs ("TC1: guard time shortened to 1 etu\n", fp);
es_fputs ("TC1: guard time shortened to 1 etu\n", fp);
else
fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
es_fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
if (!--atrlen)
goto bailout;
@ -140,10 +145,11 @@ atr_dump (int slot, FILE *fp)
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
fprintf (fp, "TD1: protocol T%d supported\n", *atr & 0x0f);
es_fprintf (fp, "TD1: protocol T%d supported\n", (*atr & 0x0f));
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
fputs ("error: ATR shorter than indicated by format character\n", fp);
es_fputs ("error: ATR shorter than indicated by format character\n",
fp);
if (!--atrlen)
goto bailout;
@ -154,12 +160,12 @@ atr_dump (int slot, FILE *fp)
if (have_ta)
{
fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
(*atr & 0x80)? "no-":"",
(*atr & 0x10)? "im": "ex",
(*atr & 0x0f));
es_fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
(*atr & 0x80)? "no-":"",
(*atr & 0x10)? "im": "ex",
(*atr & 0x0f));
if ((*atr & 0x60))
fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
es_fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
if (!--atrlen)
goto bailout;
atr++;
@ -167,7 +173,7 @@ atr_dump (int slot, FILE *fp)
if (have_tb)
{
fprintf (fp, "TB2: PI2=%d\n", *atr);
es_fprintf (fp, "TB2: PI2=%d\n", *atr);
if (!--atrlen)
goto bailout;
atr++;
@ -175,7 +181,7 @@ atr_dump (int slot, FILE *fp)
if (have_tc)
{
fprintf (fp, "TC2: PWI=%d\n", *atr);
es_fprintf (fp, "TC2: PWI=%d\n", *atr);
if (!--atrlen)
goto bailout;
atr++;
@ -187,10 +193,11 @@ atr_dump (int slot, FILE *fp)
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
es_fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
fputs ("error: ATR shorter than indicated by format character\n", fp);
es_fputs ("error: ATR shorter than indicated by format character\n",
fp);
if (!--atrlen)
goto bailout;
@ -203,7 +210,7 @@ atr_dump (int slot, FILE *fp)
{
if (have_ta)
{
fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
es_fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
if (!--atrlen)
goto bailout;
atr++;
@ -211,7 +218,7 @@ atr_dump (int slot, FILE *fp)
if (have_tb)
{
fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
es_fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
if (!--atrlen)
goto bailout;
@ -220,7 +227,7 @@ atr_dump (int slot, FILE *fp)
if (have_tc)
{
fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
es_fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
if (!--atrlen)
goto bailout;
atr++;
@ -232,11 +239,12 @@ atr_dump (int slot, FILE *fp)
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
es_fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
fputs ("error: ATR shorter than indicated by format character\n",
fp);
es_fputs ("error: "
"ATR shorter than indicated by format character\n",
fp);
if (!--atrlen)
goto bailout;
@ -247,150 +255,36 @@ atr_dump (int slot, FILE *fp)
}
if (n_historical + 1 > atrlen)
fputs ("error: ATR shorter than required for historical bytes "
"and checksum\n", fp);
es_fputs ("error: ATR shorter than required for historical bytes "
"and checksum\n", fp);
if (n_historical)
{
fputs ("Historical:", fp);
es_fputs ("HCH:", fp);
for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
fprintf (fp, " %02X", *atr);
putchar ('\n');
es_fprintf (fp, " %02X", *atr);
es_putc ('\n', fp);
}
if (!atrlen)
fputs ("error: checksum missing\n", fp);
es_fputs ("error: checksum missing\n", fp);
else if (*atr == chksum)
fprintf (fp, "TCK: %02X (good)\n", *atr);
es_fprintf (fp, "TCK: %02X (good)\n", *atr);
else
fprintf (fp, "TCK: %02X (bad; calculated %02X)\n", *atr, chksum);
es_fprintf (fp, "TCK: %02X (bad; computed %02X)\n", *atr, chksum);
atrlen--;
if (atrlen)
fprintf (fp, "error: %u bytes garbage at end of ATR\n",
(unsigned int)atrlen );
es_fprintf (fp, "error: %u bytes garbage at end of ATR\n",
(unsigned int)atrlen );
bailout:
xfree (atrbuffer);
return 0;
}
/* Note: This code has not yet been tested! It shall return -1 on
error or the number of historical bytes and store them at
HISTORICAL. */
int
atr_get_historical (int slot, unsigned char historical[])
{
int result = -1;
unsigned char *atrbuffer = NULL;
unsigned char *atr;
size_t atrlen;
int have_ta, have_tb, have_tc, have_td;
int n_historical;
int idx;
unsigned char chksum;
atr = atrbuffer = apdu_get_atr (slot, &atrlen);
if (!atr || atrlen < 2)
goto leave;
atrlen--;
atr++;
chksum = *atr;
for (idx=1; idx < atrlen-1; idx++)
chksum ^= atr[idx];
have_ta = !!(*atr & 0x10);
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
n_historical = (*atr & 0x0f);
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
goto leave; /* ATR shorter than indicated by format character. */
atrlen--;
atr++;
if (have_ta + have_tb + have_tc >= atrlen)
goto leave;
atrlen -= have_ta + have_tb + have_tc;
atr += have_ta + have_tb + have_tc;
if (have_td)
es_putc ('\0', fp); /* We want a string. */
if (es_fclose_snatch (fp, (void**)&result, NULL))
{
have_ta = !!(*atr & 0x10);
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
goto leave; /* ATR shorter than indicated by format character. */
atrlen--;
atr++;
log_error ("oops: es_fclose_snatch failed: %s\n", strerror (errno));
return NULL;
}
else
have_ta = have_tb = have_tc = have_td = 0;
if (have_ta + have_tb + have_tc >= atrlen)
goto leave;
atrlen -= have_ta + have_tb + have_tc;
atr += have_ta + have_tb + have_tc;
if (have_td)
{
have_ta = !!(*atr & 0x10);
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
goto leave; /* ATR shorter than indicated by format character. */
atrlen--;
atr++;
}
else
have_ta = have_tb = have_tc = have_td = 0;
for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
{
if (have_ta + have_tb + have_tc >= atrlen)
goto leave;
atrlen -= have_ta + have_tb + have_tc;
atr += have_ta + have_tb + have_tc;
if (have_td)
{
have_ta = !!(*atr & 0x10);
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
goto leave; /* ATR shorter than indicated by format character. */
atrlen--;
atr++;
}
else
have_ta = have_tb = have_tc = have_td = 0;
}
if (n_historical >= atrlen)
goto leave; /* ATR shorter than required for historical bytes. */
if (n_historical)
{
for (idx=0; n_historical && atrlen; n_historical--, atrlen--, atr++)
historical[idx] = *atr;
}
if (!atrlen || *atr != chksum)
goto leave;
/* Don't care about garbage at the end of the ATR. */
result = n_historical;
leave:
xfree (atrbuffer);
return result;
}

View File

@ -20,7 +20,7 @@
#ifndef ATR_H
#define ATR_H
int atr_dump (int slot, FILE *fp);
char *atr_dump (const void *buffer, size_t buflen);

View File

@ -1,6 +1,6 @@
/* command.c - SCdaemon command handler
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
* 2007, 2008, 2009 Free Software Foundation, Inc.
* 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -35,11 +35,13 @@
#include <ksba.h>
#include "app-common.h"
#include "apdu.h" /* Required for apdu_*_reader (). */
#include "atr.h"
#include "exechelp.h"
#ifdef HAVE_LIBUSB
#include "ccid-driver.h"
#endif
/* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
#define MAXLEN_PIN 100
@ -60,33 +62,39 @@
int _r = (r); \
if (gpg_err_code (_r) == GPG_ERR_CARD_NOT_PRESENT \
|| gpg_err_code (_r) == GPG_ERR_CARD_REMOVED \
|| gpg_err_code (_r) == GPG_ERR_CARD_RESET \
|| gpg_err_code (_r) == GPG_ERR_ENODEV ) \
update_card_removed ((c)->reader_slot, 1); \
update_card_removed ((c)->server_local->vreader_idx, 1); \
} while (0)
#define IS_LOCKED(c) \
(locked_session && locked_session != (c)->server_local \
&& (c)->reader_slot != -1 && locked_session->ctrl_backlink \
&& (c)->reader_slot == locked_session->ctrl_backlink->reader_slot)
#define IS_LOCKED(c) \
(locked_session \
&& locked_session != (c)->server_local \
&& (c)->server_local->vreader_idx != -1 \
&& locked_session->ctrl_backlink \
&& ((c)->server_local->vreader_idx \
== locked_session->ctrl_backlink->server_local->vreader_idx))
/* Flag indicating that the reader has been disabled. */
static int reader_disabled;
/* This structure is used to keep track of open readers (slots). */
struct slot_status_s
/* This structure is used to keep track of user readers. To
eventually accommodate this structure for RFID cards, where more
than one card is used per reader, we name it virtual reader. */
struct vreader_s
{
int valid; /* True if the other objects are valid. */
int slot; /* Slot number of the reader or -1 if not open. */
int slot; /* APDU slot number of the reader or -1 if not open. */
int reset_failed; /* A reset failed. */
int any; /* Flag indicating whether any status check has been
done. This is set once to indicate that the status
tracking for the slot has been initialized. */
unsigned int status; /* Last status of the slot. */
unsigned int changed; /* Last change counter of the slot. */
unsigned int status; /* Last status of the reader. */
unsigned int changed; /* Last change counter of the reader. */
};
@ -113,6 +121,9 @@ struct server_local_s
int event_signal; /* Or 0 if not used. */
#endif
/* Index into the vreader table (command.c) or -1 if not open. */
int vreader_idx;
/* True if the card has been removed and a reset is required to
continue operation. */
int card_removed;
@ -131,10 +142,8 @@ struct server_local_s
};
/* The table with information on all used slots. FIXME: This is a
different slot number than the one used by the APDU layer, and
should be renamed. */
static struct slot_status_s slot_table[10];
/* The table with information on all used virtual readers. */
static struct vreader_s vreader_table[10];
/* To keep track of all running sessions, we link all active server
@ -175,26 +184,41 @@ initialize_module_command (void)
}
/* Update the CARD_REMOVED element of all sessions using the reader
given by SLOT to VALUE. */
/* Helper to return the slot number for a given virtual reader index
VRDR. In case on an error -1 is returned. */
static int
vreader_slot (int vrdr)
{
if (vrdr == -1 || !(vrdr >= 0 && vrdr < DIM(vreader_table)))
return -1;
if (!vreader_table [vrdr].valid)
return -1;
return vreader_table[vrdr].slot;
}
/* Update the CARD_REMOVED element of all sessions using the virtual
reader given by VRDR to VALUE. */
static void
update_card_removed (int slot, int value)
update_card_removed (int vrdr, int value)
{
struct server_local_s *sl;
if (vrdr == -1)
return;
for (sl=session_list; sl; sl = sl->next_session)
if (sl->ctrl_backlink
&& sl->ctrl_backlink->reader_slot == slot)
&& sl->ctrl_backlink->server_local->vreader_idx == vrdr)
{
sl->card_removed = value;
}
/* Let the card application layer know about the removal. */
if (value)
application_notify_card_reset (slot);
application_notify_card_reset (vreader_slot (vrdr));
}
/* Check whether the option NAME appears in LINE. Returns 1 or 0. */
static int
has_option (const char *line, const char *name)
@ -280,10 +304,10 @@ hex_to_buffer (const char *string, size_t *r_length)
static void
do_reset (ctrl_t ctrl, int send_reset)
{
int slot = ctrl->reader_slot;
int err;
int vrdr = ctrl->server_local->vreader_idx;
int slot;
if (!(slot == -1 || (slot >= 0 && slot < DIM(slot_table))))
if (!(vrdr == -1 || (vrdr >= 0 && vrdr < DIM(vreader_table))))
BUG ();
/* If there is an active application, release it. Tell all other
@ -299,7 +323,7 @@ do_reset (ctrl_t ctrl, int send_reset)
for (sl=session_list; sl; sl = sl->next_session)
if (sl->ctrl_backlink
&& sl->ctrl_backlink->reader_slot == slot)
&& sl->ctrl_backlink->server_local->vreader_idx == vrdr)
{
sl->app_ctx_marked_for_release = 1;
}
@ -308,13 +332,22 @@ do_reset (ctrl_t ctrl, int send_reset)
/* If we want a real reset for the card, send the reset APDU and
tell the application layer about it. */
slot = vreader_slot (vrdr);
if (slot != -1 && send_reset && !IS_LOCKED (ctrl) )
{
if (apdu_reset (slot))
{
slot_table[slot].valid = 0;
}
application_notify_card_reset (slot);
switch (apdu_reset (slot))
{
case 0:
break;
case SW_HOST_NO_CARD:
case SW_HOST_CARD_INACTIVE:
break;
default:
apdu_close_reader (slot);
vreader_table[vrdr].slot = slot = -1;
break;
}
}
/* If we hold a lock, unlock now. */
@ -327,25 +360,24 @@ do_reset (ctrl_t ctrl, int send_reset)
/* Reset the card removed flag for the current reader. We need to
take the lock here so that the ticker thread won't concurrently
try to update the file. Calling update_reader_status_file is
required to get hold of the new status of the card in the slot
required to get hold of the new status of the card in the vreader
table. */
err = npth_mutex_lock (&status_file_update_lock);
if (err)
{
log_error ("failed to acquire status_fle_update lock: %s\n",
strerror (err));
ctrl->reader_slot = -1;
log_error ("failed to acquire status_file_update lock\n");
ctrl->server_local->vreader_idx = -1;
return;
}
update_reader_status_file (0); /* Update slot status table. */
update_card_removed (slot, 0); /* Clear card_removed flag. */
update_card_removed (vrdr, 0); /* Clear card_removed flag. */
err = npth_mutex_unlock (&status_file_update_lock);
if (err)
log_error ("failed to release status_file_update lock: %s\n",
strerror (err));
/* Do this last, so that the update_card_removed above does its job. */
ctrl->reader_slot = -1;
ctrl->server_local->vreader_idx = -1;
}
@ -385,35 +417,38 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
}
/* Return the slot of the current reader or open the reader if no
other sessions are using a reader. Note, that we currently support
/* Return the index of the current reader or open the reader if no
other sessions are using that reader. If it is not possible to
open the reader -1 is returned. Note, that we currently support
only one reader but most of the code (except for this function)
should be able to cope with several readers. */
static int
get_reader_slot (void)
get_current_reader (void)
{
struct slot_status_s *ss;
struct vreader_s *vr;
ss = &slot_table[0]; /* One reader for now. */
/* We only support one reader for now. */
vr = &vreader_table[0];
/* Initialize the item if needed. */
if (!ss->valid)
/* Initialize the vreader item if not yet done. */
if (!vr->valid)
{
ss->slot = -1;
ss->valid = 1;
vr->slot = -1;
vr->valid = 1;
}
/* Try to open the reader. */
if (ss->slot == -1)
if (vr->slot == -1)
{
int no_service_flag;
ss->slot = apdu_open_reader (opt.reader_port, &no_service_flag);
vr->slot = apdu_open_reader (opt.reader_port, &no_service_flag);
/* If we still don't have a slot, we have no readers.
Invalidate for now until a reader is attached. */
if(ss->slot == -1)
if (vr->slot == -1)
{
ss->valid = 0;
vr->valid = 0;
}
if (no_service_flag)
@ -423,18 +458,17 @@ get_reader_slot (void)
}
}
/* Return the slot_table index. */
return 0;
/* Return the vreader index or -1. */
return vr->valid ? 0 : -1;
}
/* 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. */
/* If the card has not yet been opened, do it. */
static gpg_error_t
open_card (ctrl_t ctrl, const char *apptype)
{
gpg_error_t err;
int slot;
int vrdr;
if (reader_disabled)
return gpg_error (GPG_ERR_NOT_OPERATIONAL);
@ -462,21 +496,25 @@ open_card (ctrl_t ctrl, const char *apptype)
need to check that the client didn't requested a specific
application different from the one in use before we continue. */
if (ctrl->app_ctx)
return check_application_conflict (ctrl, apptype);
{
return check_application_conflict
(ctrl, vreader_slot (ctrl->server_local->vreader_idx), apptype);
}
/* Setup the slot and select the application. */
if (ctrl->reader_slot != -1)
slot = ctrl->reader_slot;
/* Setup the vreader and select the application. */
if (ctrl->server_local->vreader_idx != -1)
vrdr = ctrl->server_local->vreader_idx;
else
slot = get_reader_slot ();
ctrl->reader_slot = slot;
if (slot == -1)
vrdr = get_current_reader ();
ctrl->server_local->vreader_idx = vrdr;
if (vrdr == -1)
err = gpg_error (reader_disabled? GPG_ERR_NOT_OPERATIONAL: GPG_ERR_CARD);
else
{
/* Fixme: We should move the apdu_connect call to
select_application. */
int sw;
int slot = vreader_slot (vrdr);
ctrl->server_local->disconnect_allowed = 0;
sw = apdu_connect (slot);
@ -484,6 +522,8 @@ open_card (ctrl_t ctrl, const char *apptype)
{
if (sw == SW_HOST_NO_CARD)
err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
else if (sw == SW_HOST_CARD_INACTIVE)
err = gpg_error (GPG_ERR_CARD_RESET);
else
err = gpg_error (GPG_ERR_CARD);
}
@ -523,8 +563,10 @@ cmd_serialno (assuan_context_t ctx, char *line)
char *serial_and_stamp;
char *serial;
time_t stamp;
int retries = 0;
/* Clear the remove flag so that the open_card is able to reread it. */
retry:
if (!reader_disabled && ctrl->server_local->card_removed)
{
if ( IS_LOCKED (ctrl) )
@ -533,7 +575,12 @@ cmd_serialno (assuan_context_t ctx, char *line)
}
if ((rc = open_card (ctrl, *line? line:NULL)))
return rc;
{
/* In case of an inactive card, retry once. */
if (gpg_err_code (rc) == GPG_ERR_CARD_RESET && retries++ < 1)
goto retry;
return rc;
}
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
if (rc)
@ -1613,8 +1660,8 @@ static const char hlp_getinfo[] =
"\n"
"socket_name - Return the name of the socket.\n"
"\n"
"status - Return the status of the current slot (in the future, may\n"
"also return the status of all slots). The status is a list of\n"
"status - Return the status of the current reader (in the future, may\n"
"also return the status of all readers). The status is a list of\n"
"one-character flags. The following flags are currently defined:\n"
" 'u' Usable card present. This is the normal state during operation.\n"
" 'r' Card removed. A reset is necessary.\n"
@ -1658,22 +1705,18 @@ cmd_getinfo (assuan_context_t ctx, char *line)
else if (!strcmp (line, "status"))
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int slot = ctrl->reader_slot;
int vrdr = ctrl->server_local->vreader_idx;
char flag = 'r';
if (!ctrl->server_local->card_removed && slot != -1)
if (!ctrl->server_local->card_removed && vrdr != -1)
{
struct slot_status_s *ss;
struct vreader_s *vr;
if (!(slot >= 0 && slot < DIM(slot_table)))
if (!(vrdr >= 0 && vrdr < DIM(vreader_table)))
BUG ();
ss = &slot_table[slot];
if (!ss->valid)
BUG ();
if (ss->any && (ss->status & 1))
vr = &vreader_table[vrdr];
if (vr->valid && vr->any && (vr->status & 1))
flag = 'u';
}
rc = assuan_send_data (ctx, &flag, 1);
@ -1759,7 +1802,7 @@ cmd_disconnect (assuan_context_t ctx, char *line)
static const char hlp_apdu[] =
"APDU [--atr] [--more] [--exlen[=N]] [hexstring]\n"
"APDU [--[dump-]atr] [--more] [--exlen[=N]] [hexstring]\n"
"\n"
"Send an APDU to the current reader. This command bypasses the high\n"
"level functions and sends the data directly to the card. HEXSTRING\n"
@ -1788,8 +1831,12 @@ cmd_apdu (assuan_context_t ctx, char *line)
int handle_more;
const char *s;
size_t exlen;
int slot;
with_atr = has_option (line, "--atr");
if (has_option (line, "--dump-atr"))
with_atr = 2;
else
with_atr = has_option (line, "--atr");
handle_more = has_option (line, "--more");
if ((s=has_option_name (line, "--exlen")))
@ -1810,21 +1857,46 @@ cmd_apdu (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl, NULL)))
return rc;
slot = vreader_slot (ctrl->server_local->vreader_idx);
if (with_atr)
{
unsigned char *atr;
size_t atrlen;
char hexbuf[400];
atr = apdu_get_atr (ctrl->reader_slot, &atrlen);
atr = apdu_get_atr (slot, &atrlen);
if (!atr || atrlen > sizeof hexbuf - 2 )
{
rc = gpg_error (GPG_ERR_INV_CARD);
goto leave;
}
bin2hex (atr, atrlen, hexbuf);
if (with_atr == 2)
{
char *string, *p, *pend;
string = atr_dump (atr, atrlen);
if (string)
{
for (rc=0, p=string; !rc && (pend = strchr (p, '\n')); p = pend+1)
{
rc = assuan_send_data (ctx, p, pend - p + 1);
if (!rc)
rc = assuan_send_data (ctx, NULL, 0);
}
if (!rc && *p)
rc = assuan_send_data (ctx, p, strlen (p));
es_free (string);
if (rc)
goto leave;
}
}
else
{
bin2hex (atr, atrlen, hexbuf);
send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
}
xfree (atr);
send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
}
apdu = hex_to_buffer (line, &apdulen);
@ -1838,7 +1910,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
unsigned char *result = NULL;
size_t resultlen;
rc = apdu_send_direct (ctrl->reader_slot, exlen,
rc = apdu_send_direct (slot, exlen,
apdu, apdulen, handle_more,
&result, &resultlen);
if (rc)
@ -1869,15 +1941,8 @@ cmd_killscd (assuan_context_t ctx, char *line)
(void)line;
ctrl->server_local->stopme = 1;
#ifdef ASSUAN_FORCE_CLOSE
assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
return 0;
#else
/* Actually returning an EOF does not anymore work with modern
Libassuan versions. However we keep that non working code until
we make a Libassuan with the force close flag a requirement. */
return gpg_error (GPG_ERR_EOF);
#endif
}
@ -1988,12 +2053,13 @@ scd_command_handler (ctrl_t ctrl, int fd)
session_list = ctrl->server_local;
ctrl->server_local->ctrl_backlink = ctrl;
ctrl->server_local->assuan_ctx = ctx;
ctrl->server_local->vreader_idx = -1;
/* We open the reader right at startup so that the ticker is able to
update the status file. */
if (ctrl->reader_slot == -1)
if (ctrl->server_local->vreader_idx == -1)
{
ctrl->reader_slot = get_reader_slot ();
ctrl->server_local->vreader_idx = get_current_reader ();
}
/* Command processing loop. */
@ -2195,32 +2261,33 @@ update_reader_status_file (int set_card_removed_flag)
int idx;
unsigned int status, changed;
/* Make sure that the reader has been opened. Like get_reader_slot,
/* Make sure that a reader has been opened. Like get_current_reader,
this part of the code assumes that there is only one reader. */
if (!slot_table[0].valid)
(void)get_reader_slot ();
if (!vreader_table[0].valid)
(void)get_current_reader ();
/* Note, that we only try to get the status, because it does not
make sense to wait here for a operation to complete. If we are
busy working with a card, delays in the status file update should
be acceptable. */
for (idx=0; idx < DIM(slot_table); idx++)
for (idx=0; idx < DIM(vreader_table); idx++)
{
struct slot_status_s *ss = slot_table + idx;
struct vreader_s *vr = vreader_table + idx;
struct server_local_s *sl;
int sw_apdu;
if (!ss->valid || ss->slot == -1)
if (!vr->valid || vr->slot == -1)
continue; /* Not valid or reader not yet open. */
sw_apdu = apdu_get_status (ss->slot, 0, &status, &changed);
sw_apdu = apdu_get_status (vr->slot, 0, &status, &changed);
if (sw_apdu == SW_HOST_NO_READER)
{
/* Most likely the _reader_ has been unplugged. */
apdu_close_reader(ss->slot);
ss->valid = 0;
application_notify_card_reset (vr->slot);
apdu_close_reader (vr->slot);
vr->slot = -1;
status = 0;
changed = ss->changed;
changed = vr->changed;
}
else if (sw_apdu)
{
@ -2228,21 +2295,21 @@ update_reader_status_file (int set_card_removed_flag)
continue;
}
if (!ss->any || ss->status != status || ss->changed != changed )
if (!vr->any || vr->status != status || vr->changed != changed )
{
char *fname;
char templ[50];
FILE *fp;
log_info ("updating slot %d status: 0x%04X->0x%04X (%u->%u)\n",
ss->slot, ss->status, status, ss->changed, changed);
ss->status = status;
ss->changed = changed;
log_info ("updating reader %d (%d) status: 0x%04X->0x%04X (%u->%u)\n",
idx, vr->slot, vr->status, status, vr->changed, changed);
vr->status = status;
vr->changed = changed;
/* FIXME: Should this be IDX instead of ss->slot? This
/* FIXME: Should this be IDX instead of vr->slot? This
depends on how client sessions will associate the reader
status with their session. */
snprintf (templ, sizeof templ, "reader_%d.status", ss->slot);
snprintf (templ, sizeof templ, "reader_%d.status", vr->slot);
fname = make_filename (opt.homedir, templ, NULL );
fp = fopen (fname, "w");
if (fp)
@ -2270,8 +2337,8 @@ update_reader_status_file (int set_card_removed_flag)
envs[0] = envstr;
envs[1] = NULL;
sprintf (numbuf1, "%d", ss->slot);
sprintf (numbuf2, "0x%04X", ss->status);
sprintf (numbuf1, "%d", vr->slot);
sprintf (numbuf2, "0x%04X", vr->status);
sprintf (numbuf3, "0x%04X", status);
args[0] = "--reader-port";
args[1] = numbuf1;
@ -2299,10 +2366,10 @@ update_reader_status_file (int set_card_removed_flag)
/* Set the card removed flag for all current sessions. We
will set this on any card change because a reset or
SERIALNO request must be done in any case. */
if (ss->any && set_card_removed_flag)
if (vr->any && set_card_removed_flag)
update_card_removed (idx, 1);
ss->any = 1;
vr->any = 1;
/* Send a signal to all clients who applied for it. */
send_client_notifications ();
@ -2318,8 +2385,9 @@ update_reader_status_file (int set_card_removed_flag)
{
/* FIXME: Use a real timeout. */
/* At least one connection and all allow a disconnect. */
log_info ("disconnecting card in slot %d\n", ss->slot);
apdu_disconnect (ss->slot);
log_info ("disconnecting card in reader %d (%d)\n",
idx, vr->slot);
apdu_disconnect (vr->slot);
}
}

View File

@ -74,6 +74,7 @@ enum cmd_and_opt_values
oDebugAllowCoreDump,
oDebugCCIDDriver,
oDebugLogTid,
oDebugAssuanLogCats,
oNoGreeting,
oNoOptions,
oHomedir,
@ -123,6 +124,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oDebugCCIDDriver, "debug-ccid-driver", "@"),
ARGPARSE_s_n (oDebugDisableTicker, "debug-disable-ticker", "@"),
ARGPARSE_s_n (oDebugLogTid, "debug-log-tid", "@"),
ARGPARSE_p_u (oDebugAssuanLogCats, "debug-assuan-log-cats", "@"),
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write a log to FILE")),
ARGPARSE_s_s (oReaderPort, "reader-port",
@ -542,6 +544,9 @@ main (int argc, char **argv )
case oDebugLogTid:
log_set_pid_suffix_cb (tid_log_callback);
break;
case oDebugAssuanLogCats:
set_libassuan_log_cats (pargs.r.ret_ulong);
break;
case oOptions:
/* config files may not be nested (silently ignore them) */
@ -826,7 +831,7 @@ main (int argc, char **argv )
if (csh_style)
{
*strchr (infostr, '=') = ' ';
es_printf ( "setenv %s\n", infostr);
es_printf ( "setenv %s;\n", infostr);
}
else
{
@ -909,7 +914,7 @@ scd_exit (int rc)
static void
scd_init_default_ctrl (ctrl_t ctrl)
{
ctrl->reader_slot = -1;
(void)ctrl;
}
static void

View File

@ -72,8 +72,9 @@ struct
#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_ASSUAN_VALUE 1024
#define DBG_CARD_IO_VALUE 2048
#define DBG_READER_VALUE 4096 /* Trace reader related functions. */
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
@ -82,6 +83,7 @@ struct
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
#define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE)
#define DBG_READER (opt.debug & DBG_READER_VALUE)
struct server_local_s;
struct app_ctx_s;
@ -97,9 +99,6 @@ struct server_control_s
/* Local data of the server; used only in command.c. */
struct server_local_s *server_local;
/* Slot of the open reader or -1 if not open. */
int reader_slot;
/* The application context used with this connection or NULL if none
associated. Note that this is shared with the other connections:
All connections accessing the same reader are using the same

View File

@ -64,6 +64,7 @@ OPTIONS:
makes a change to SHA1's commit log text or metadata.
--append-dot append a dot to the first line of each commit message if
there is no other punctuation or blank at the end.
--tear-off tear off all commit log lines after a '--' line.
--since=DATE convert only the logs since DATE;
the default is to convert all log entries.
--format=FMT set format string for commit subject and body;
@ -175,6 +176,7 @@ sub parse_amend_file($)
my $format_string = '%s%n%b%n';
my $amend_file;
my $append_dot = 0;
my $tear_off = 0;
GetOptions
(
help => sub { usage 0 },
@ -183,6 +185,7 @@ sub parse_amend_file($)
'format=s' => \$format_string,
'amend=s' => \$amend_file,
'append-dot' => \$append_dot,
'tear-off' => \$tear_off,
) or usage 1;
@ -281,6 +284,18 @@ sub parse_amend_file($)
@line = grep !/^Signed-off-by: .*>$/, @line;
@line = grep !/^Co-authored-by: /, @line;
# Remove everything after a line with 2 dashes at the beginning.
if ($tear_off)
{
my @tmpline;
foreach (@line)
{
last if /^--\s*$/;
push @tmpline,$_;
}
@line = @tmpline;
}
# Remove leading and trailing blank lines.
if (@line)
{

View File

@ -816,7 +816,7 @@ get_cached_cert (assuan_context_t ctx,
char hexfpr[2*20+1];
struct membuf mb;
char *buf;
size_t buflen;
size_t buflen = 0;
ksba_cert_t cert;
*r_cert = NULL;

View File

@ -1,6 +1,6 @@
/* certchain.c - certificate chain validation
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
* 2006, 2007, 2008 Free Software Foundation, Inc.
* 2006, 2007, 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -1193,6 +1193,7 @@ ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode)
VALIDATE_FLAG_NO_DIRMNGR - Do not do any dirmngr isvalid checks.
VALIDATE_FLAG_CHAIN_MODEL - Check according to chain model.
VALIDATE_FLAG_STEED - Check according to the STEED model.
*/
static int
do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
@ -1305,13 +1306,21 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
We used to do this only later but changed it to call the
check right here so that we can access special flags
associated with that specific root certificate. */
istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, NULL,
rootca_flags);
if (gpgsm_cert_has_well_known_private_key (subject_cert))
{
memset (rootca_flags, 0, sizeof *rootca_flags);
istrusted_rc = ((flags & VALIDATE_FLAG_STEED)
? 0 : gpg_error (GPG_ERR_NOT_TRUSTED));
}
else
istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, NULL,
rootca_flags);
audit_log_cert (ctrl->audit, AUDIT_ROOT_TRUSTED,
subject_cert, istrusted_rc);
/* If the chain model extended attribute is used, make sure
that our chain model flag is set. */
if (has_validation_model_chain (subject_cert, listmode, listfp))
if (!(flags & VALIDATE_FLAG_STEED)
&& has_validation_model_chain (subject_cert, listmode, listfp))
rootca_flags->chain_model = 1;
}
@ -1383,7 +1392,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
/* Set the flag for qualified signatures. This flag is
deduced from a list of root certificates allowed for
qualified signatures. */
if (is_qualified == -1)
if (is_qualified == -1 && !(flags & VALIDATE_FLAG_STEED))
{
gpg_error_t err;
size_t buflen;
@ -1437,8 +1446,11 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
expired it does not make much sense to ask the user
whether we wants to trust the root certificate. We
should do this only if the certificate under question
will then be usable. */
will then be usable. If the certificate has a well
known private key asking the user does not make any
sense. */
if ( !any_expired
&& !gpgsm_cert_has_well_known_private_key (subject_cert)
&& (!listmode || !already_asked_marktrusted (subject_cert))
&& ask_marktrusted (ctrl, subject_cert, listmode) )
rc = 0;
@ -1455,6 +1467,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
/* Check for revocations etc. */
if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
;
else if ((flags & VALIDATE_FLAG_STEED))
; /* Fixme: check revocations via DNS. */
else if (opt.no_trusted_cert_crl_check || rootca_flags->relax)
;
else
@ -1586,8 +1600,16 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
performance reasons. */
if (is_root)
{
istrusted_rc = gpgsm_agent_istrusted (ctrl, issuer_cert, NULL,
rootca_flags);
if (gpgsm_cert_has_well_known_private_key (issuer_cert))
{
memset (rootca_flags, 0, sizeof *rootca_flags);
istrusted_rc = ((flags & VALIDATE_FLAG_STEED)
? 0 : gpg_error (GPG_ERR_NOT_TRUSTED));
}
else
istrusted_rc = gpgsm_agent_istrusted
(ctrl, issuer_cert, NULL, rootca_flags);
if (!istrusted_rc && rootca_flags->relax)
{
/* Ignore the error due to the relax flag. */
@ -1627,6 +1649,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
be fixed. */
if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
rc = 0;
else if ((flags & VALIDATE_FLAG_STEED))
rc = 0; /* Fixme: XXX */
else if (is_root && (opt.no_trusted_cert_crl_check
|| (!istrusted_rc && rootca_flags->relax)))
rc = 0;
@ -1722,7 +1746,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
capability of the certificate under question, store the result as
user data in all certificates of the chain. We do this even if the
validation itself failed. */
if (is_qualified != -1)
if (is_qualified != -1 && !(flags & VALIDATE_FLAG_STEED))
{
gpg_error_t err;
chain_item_t ci;
@ -1780,8 +1804,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
do_validate_chain. This function is a wrapper to handle a root
certificate with the chain_model flag set. If RETFLAGS is not
NULL, flags indicating now the verification was done are stored
there. The only defined flag for RETFLAGS is
VALIDATE_FLAG_CHAIN_MODEL.
there. The only defined vits for RETFLAGS are
VALIDATE_FLAG_CHAIN_MODEL and VALIDATE_FLAG_STEED.
If you are verifying a signature you should set CHECKTIME to the
creation time of the signature. If your are verifying a
@ -1801,16 +1825,27 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
if (!retflags)
retflags = &dummy_retflags;
/* If the session requested a certain validation mode make sure the
corresponding flags are set. */
if (ctrl->validation_model == 1)
flags |= VALIDATE_FLAG_CHAIN_MODEL;
else if (ctrl->validation_model == 2)
flags |= VALIDATE_FLAG_STEED;
/* If the chain model was forced, set this immediately into
RETFLAGS. */
*retflags = (flags & VALIDATE_FLAG_CHAIN_MODEL);
memset (&rootca_flags, 0, sizeof rootca_flags);
rc = do_validate_chain (ctrl, cert, checktime,
r_exptime, listmode, listfp, flags,
&rootca_flags);
if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED
if (!rc && (flags & VALIDATE_FLAG_STEED))
{
*retflags |= VALIDATE_FLAG_STEED;
}
else if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED
&& !(flags & VALIDATE_FLAG_CHAIN_MODEL)
&& (rootca_flags.valid && rootca_flags.chain_model))
{
@ -1824,6 +1859,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
if (opt.verbose)
do_list (0, listmode, listfp, _("validation model used: %s"),
(*retflags & VALIDATE_FLAG_STEED)?
"steed" :
(*retflags & VALIDATE_FLAG_CHAIN_MODEL)?
_("chain"):_("shell"));

View File

@ -1,6 +1,6 @@
/* certlist.c - build list of certificates
* Copyright (C) 2001, 2003, 2004, 2005, 2007,
* 2008 Free Software Foundation, Inc.
* 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -210,6 +210,21 @@ gpgsm_cert_use_ocsp_p (ksba_cert_t cert)
}
/* Return true if CERT has the well known private key extension. */
int
gpgsm_cert_has_well_known_private_key (ksba_cert_t cert)
{
int idx;
const char *oid;
for (idx=0; !ksba_cert_get_extension (cert, idx,
&oid, NULL, NULL, NULL);idx++)
if (!strcmp (oid, "1.3.6.1.4.1.11591.2.2.2") )
return 1; /* Yes. */
return 0; /* No. */
}
static int
same_subject_issuer (const char *subject, const char *issuer, ksba_cert_t cert)
{

View File

@ -33,6 +33,22 @@
%commit
%echo done
EOF
This parameter file was used to create the STEED CA:
Key-Type: RSA
Key-Length: 1024
Key-Grip: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
Key-Usage: cert
Serial: 1
Name-DN: CN=The STEED Self-Signing Nonthority
Not-Before: 2011-11-11
Not-After: 2106-02-06
Subject-Key-Id: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
Extension: 2.5.29.19 c 30060101ff020101
Extension: 1.3.6.1.4.1.11591.2.2.2 n 0101ff
Signing-Key: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
%commit
*/
@ -68,7 +84,10 @@ enum para_name
pNOTBEFORE,
pNOTAFTER,
pSIGNINGKEY,
pHASHALGO
pHASHALGO,
pAUTHKEYID,
pSUBJKEYID,
pEXTENSION
};
struct para_data_s
@ -89,6 +108,8 @@ struct reqgen_ctrl_s
};
static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35";
static const char oidstr_subjectKeyIdentifier[] = "2.5.29.14";
static const char oidstr_keyUsage[] = "2.5.29.15";
static const char oidstr_basicConstraints[] = "2.5.29.19";
static const char oidstr_standaloneCertificate[] = "1.3.6.1.4.1.11591.2.2.1";
@ -170,8 +191,11 @@ parse_parameter_usage (struct para_data_s *para, enum para_name key)
;
else if ( !ascii_strcasecmp (p, "sign") )
use |= GCRY_PK_USAGE_SIGN;
else if ( !ascii_strcasecmp (p, "encrypt") )
else if ( !ascii_strcasecmp (p, "encrypt")
|| !ascii_strcasecmp (p, "encr") )
use |= GCRY_PK_USAGE_ENCR;
else if ( !ascii_strcasecmp (p, "cert") )
use |= GCRY_PK_USAGE_CERT;
else
{
log_error ("line %d: invalid usage list\n", r->lnr);
@ -225,6 +249,9 @@ read_parameters (ctrl_t ctrl, estream_t fp, estream_t out_fp)
{ "Not-After", pNOTAFTER },
{ "Signing-Key", pSIGNINGKEY },
{ "Hash-Algo", pHASHALGO },
{ "Authority-Key-Id", pAUTHKEYID },
{ "Subject-Key-Id", pSUBJKEYID },
{ "Extension", pEXTENSION, 1 },
{ NULL, 0 }
};
char line[1024], *p;
@ -594,6 +621,74 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
}
}
/* Check the optional AuthorityKeyId. */
string = get_parameter_value (para, pAUTHKEYID, 0);
if (string)
{
for (s=string, i=0; hexdigitp (s); s++, i++)
;
if (*s || (i&1))
{
r = get_parameter (para, pAUTHKEYID, 0);
log_error (_("line %d: invalid authority-key-id\n"), r->lnr);
xfree (cardkeyid);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
}
/* Check the optional SubjectKeyId. */
string = get_parameter_value (para, pSUBJKEYID, 0);
if (string)
{
for (s=string, i=0; hexdigitp (s); s++, i++)
;
if (*s || (i&1))
{
r = get_parameter (para, pSUBJKEYID, 0);
log_error (_("line %d: invalid subject-key-id\n"), r->lnr);
xfree (cardkeyid);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
}
/* Check the optional extensions. */
for (seq=0; (string=get_parameter_value (para, pEXTENSION, seq)); seq++)
{
int okay = 0;
s = strpbrk (string, " \t:");
if (s)
{
s++;
while (spacep (s))
s++;
if (*s && strchr ("nNcC", *s))
{
s++;
while (spacep (s))
s++;
if (*s == ':')
s++;
if (*s)
{
while (spacep (s))
s++;
for (i=0; hexdigitp (s); s++, i++)
;
if (!((*s && *s != ':') || !i || (i&1)))
okay = 1;
}
}
}
if (!okay)
{
r = get_parameter (para, pEXTENSION, seq);
log_error (_("line %d: invalid extension syntax\n"), r->lnr);
xfree (cardkeyid);
return gpg_error (GPG_ERR_INV_PARAMETER);
}
}
/* Create or retrieve the public key. */
if (cardkeyid) /* Take the key from the current smart card. */
{
@ -838,6 +933,14 @@ create_request (ctrl_t ctrl,
err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
"\x03\x02\x04\x30", 4);
}
else if (use == GCRY_PK_USAGE_CERT)
{
/* For certify only we encode the bits:
KSBA_KEYUSAGE_KEY_CERT_SIGN
KSBA_KEYUSAGE_CRL_SIGN */
err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
"\x03\x02\x01\x06", 4);
}
else
err = 0; /* Both or none given: don't request one. */
if (err)
@ -889,7 +992,7 @@ create_request (ctrl_t ctrl,
*p++ = '0';
strcpy (p, string);
for (p=hexbuf, len=0; p[0] && p[1]; p += 2)
((unsigned char*)hexbuf)[len++] = xtoi_2 (s);
((unsigned char*)hexbuf)[len++] = xtoi_2 (p);
/* Now build the S-expression. */
snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
buf = p = xtrymalloc (1 + strlen (numbuf) + len + 1 + 1);
@ -1009,6 +1112,139 @@ create_request (ctrl_t ctrl,
goto leave;
}
}
/* Insert the AuthorityKeyId. */
string = get_parameter_value (para, pAUTHKEYID, 0);
if (string)
{
char *hexbuf;
/* Allocate a buffer for in-place conversion. We also add 4
extra bytes space for the tags and lengths fields. */
hexbuf = xtrymalloc (4 + strlen (string) + 1);
if (!hexbuf)
{
err = gpg_error_from_syserror ();
goto leave;
}
strcpy (hexbuf+4, string);
for (p=hexbuf+4, len=0; p[0] && p[1]; p += 2)
((unsigned char*)hexbuf)[4+len++] = xtoi_2 (p);
if (len > 125)
{
err = gpg_error (GPG_ERR_TOO_LARGE);
xfree (hexbuf);
goto leave;
}
hexbuf[0] = 0x30; /* Tag for a Sequence. */
hexbuf[1] = len+2;
hexbuf[2] = 0x80; /* Context tag for an implicit Octet string. */
hexbuf[3] = len;
err = ksba_certreq_add_extension (cr, oidstr_authorityKeyIdentifier,
0,
hexbuf, 4+len);
xfree (hexbuf);
if (err)
{
log_error ("error setting the authority-key-id: %s\n",
gpg_strerror (err));
goto leave;
}
}
/* Insert the SubjectKeyId. */
string = get_parameter_value (para, pSUBJKEYID, 0);
if (string)
{
char *hexbuf;
/* Allocate a buffer for in-place conversion. We also add 2
extra bytes space for the tag and length field. */
hexbuf = xtrymalloc (2 + strlen (string) + 1);
if (!hexbuf)
{
err = gpg_error_from_syserror ();
goto leave;
}
strcpy (hexbuf+2, string);
for (p=hexbuf+2, len=0; p[0] && p[1]; p += 2)
((unsigned char*)hexbuf)[2+len++] = xtoi_2 (p);
if (len > 127)
{
err = gpg_error (GPG_ERR_TOO_LARGE);
xfree (hexbuf);
goto leave;
}
hexbuf[0] = 0x04; /* Tag for an Octet string. */
hexbuf[1] = len;
err = ksba_certreq_add_extension (cr, oidstr_subjectKeyIdentifier, 0,
hexbuf, 2+len);
xfree (hexbuf);
if (err)
{
log_error ("error setting the subject-key-id: %s\n",
gpg_strerror (err));
goto leave;
}
}
/* Insert additional extensions. */
for (seq=0; (string = get_parameter_value (para, pEXTENSION, seq)); seq++)
{
char *hexbuf;
char *oidstr;
int crit = 0;
s = strpbrk (string, " \t:");
if (!s)
{
err = gpg_error (GPG_ERR_INTERNAL);
goto leave;
}
oidstr = xtrymalloc (s - string + 1);
if (!oidstr)
{
err = gpg_error_from_syserror ();
goto leave;
}
memcpy (oidstr, string, (s-string));
oidstr[(s-string)] = 0;
s++;
while (spacep (s))
s++;
if (!*s)
{
err = gpg_error (GPG_ERR_INTERNAL);
xfree (oidstr);
goto leave;
}
if (strchr ("cC", *s))
crit = 1;
s++;
while (spacep (s))
s++;
if (*s == ':')
s++;
while (spacep (s))
s++;
hexbuf = xtrystrdup (s);
if (!hexbuf)
{
err = gpg_error_from_syserror ();
xfree (oidstr);
goto leave;
}
for (p=hexbuf, len=0; p[0] && p[1]; p += 2)
((unsigned char*)hexbuf)[len++] = xtoi_2 (p);
err = ksba_certreq_add_extension (cr, oidstr, crit,
hexbuf, len);
xfree (oidstr);
xfree (hexbuf);
}
}
else
sigkey = public;

View File

@ -2004,6 +2004,8 @@ gpgsm_parse_validation_model (const char *model)
return 0;
else if ( !ascii_strcasecmp (model, "chain") )
return 1;
else if ( !ascii_strcasecmp (model, "steed") )
return 2;
else
return -1;
}

View File

@ -195,7 +195,9 @@ struct server_control_s
certificates up the chain (0 = none, 1 = only
signer) */
int use_ocsp; /* Set to true if OCSP should be used. */
int validation_model; /* Set to 1 for the chain model. */
int validation_model; /* 0 := standard model (shell),
1 := chain model,
2 := STEED model. */
};
@ -307,7 +309,7 @@ int gpgsm_create_cms_signature (ctrl_t ctrl,
/* Flags used with gpgsm_validate_chain. */
#define VALIDATE_FLAG_NO_DIRMNGR 1
#define VALIDATE_FLAG_CHAIN_MODEL 2
#define VALIDATE_FLAG_STEED 4
int gpgsm_walk_cert_chain (ctrl_t ctrl,
ksba_cert_t start, ksba_cert_t *r_next);
@ -326,6 +328,7 @@ int gpgsm_cert_use_verify_p (ksba_cert_t cert);
int gpgsm_cert_use_decrypt_p (ksba_cert_t cert);
int gpgsm_cert_use_cert_p (ksba_cert_t cert);
int gpgsm_cert_use_ocsp_p (ksba_cert_t cert);
int gpgsm_cert_has_well_known_private_key (ksba_cert_t cert);
int gpgsm_certs_identical_p (ksba_cert_t cert_a, ksba_cert_t cert_b);
int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert,
certlist_t *listaddr, int is_encrypt_to);

View File

@ -1,6 +1,6 @@
/* keylist.c - Print certificates in various formats.
* Copyright (C) 1998, 1999, 2000, 2001, 2003,
* 2004, 2005, 2008, 2009 Free Software Foundation, Inc.
* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2008, 2009,
* 2010, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -187,6 +187,7 @@ static struct
/* GnuPG extensions */
{ "1.3.6.1.4.1.11591.2.1.1", "pkaAddress" },
{ "1.3.6.1.4.1.11591.2.2.1", "standaloneCertificate" },
{ "1.3.6.1.4.1.11591.2.2.2", "wellKnownPrivateKey" },
/* Extensions used by the Bundesnetzagentur. */
{ "1.3.6.1.4.1.8301.3.5", "validityModel" },
@ -420,7 +421,12 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
&& *not_after && strcmp (current_time, not_after) > 0 )
*truststring = 'e';
else if (valerr)
*truststring = 'i';
{
if (gpgsm_cert_has_well_known_private_key (cert))
*truststring = 'w'; /* Well, this is dummy CA. */
else
*truststring = 'i';
}
else if (ctrl->with_validation && !is_root)
*truststring = 'f';
}
@ -432,12 +438,17 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
{
struct rootca_flags_s dummy_flags;
rc = gpgsm_agent_istrusted (ctrl, cert, NULL, &dummy_flags);
if (!rc)
*truststring = 'u'; /* Yes, we trust this one (ultimately). */
else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
*truststring = 'n'; /* No, we do not trust this one. */
/* (in case of an error we can't tell anything.) */
if (gpgsm_cert_has_well_known_private_key (cert))
*truststring = 'w'; /* Well, this is dummy CA. */
else
{
rc = gpgsm_agent_istrusted (ctrl, cert, NULL, &dummy_flags);
if (!rc)
*truststring = 'u'; /* Yes, we trust this one (ultimately). */
else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
*truststring = 'n'; /* No, we do not trust this one. */
/* (in case of an error we can't tell anything.) */
}
}
if (*truststring)

View File

@ -277,7 +277,7 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
else if (!strcmp (key, "validation-model"))
{
int i = gpgsm_parse_validation_model (value);
if ( i >= 0 && i <= 1 )
if ( i >= 0 && i <= 2 )
ctrl->validation_model = i;
else
err = gpg_error (GPG_ERR_ASS_PARAMETER);

View File

@ -624,6 +624,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
}
gpgsm_status (ctrl, STATUS_TRUST_FULLY,
(verifyflags & VALIDATE_FLAG_STEED)?
"0 steed":
(verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
"0 chain": "0 shell");

View File

@ -41,6 +41,8 @@ EXTRA_DIST = runtest inittests $(testscripts) ChangeLog-2011 \
text-1.txt text-2.txt text-3.txt \
text-1.osig.pem text-1.dsig.pem text-1.osig-bad.pem \
text-2.osig.pem text-2.osig-bad.pem \
samplekeys/steed-self-signing-nonthority.pem \
samplekeys/68A638998DFABAC510EA645CE34F9686B2EDF7EA.key \
samplekeys/32100C27173EF6E9C4E9A25D3D69F86D37A4F939.key \
samplekeys/cert_g10code_pete1.pem \
samplekeys/cert_g10code_test1.pem \

View File

@ -0,0 +1,10 @@
(private-key
(rsa
(n #0093687D92A7BCD1E6FC11263B50657A8FA4B9CEE3F90E23384D62778CA1B6CBE0F60B20354A5F74899EB3C8DDF3081D32475C71869BB0C5DAF0051A2F44596E7406F1DCC7B29D88735E49341F09F4DFCAB5A08B76614C37220CF7E2CDB8A38E79644F3A250FFAE5D0BBA6917C67523D2812FDE8D3BEA9947F6A55402B1600C12F#)
(e #010001#)
(d #11BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE905D3988DFC39FEF462A0655AC906CBC12F6D322795D3988DFC39FEF462A0655AC906CBC12F6D322795D3988DFC39FEF462A0655AC906CBC12F6D322795D3983C1#)
(p "\x00ÂBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAÏ")
(q "\x00ÂBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¡")
(u #00B28879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C221372887A30#)
)
)

View File

@ -1,6 +1,6 @@
This is a collection of keys we use with the regression tests.
opensc-tests.p12 PKCS#12 key and certificates taken from OpenSC.
opensc-tests.p12 PKCS#12 key and certificates taken from OpenSC.
Passphrase is "password"
ov-user.p12 Private tests keys from www.openvalidation.org.
@ -17,5 +17,8 @@ gte.pem GTE CyberTrust Global Root
cert-with-117-akas.pem A certificate with 117 subjectAltNames.
steed-self-signing-nonthority.pem
The STEED Self-Signing Nonthority.
68A638998DFABAC510EA645CE34F9686B2EDF7EA.key
The private Key of The STEED Self-Signing Nonthority.

View File

@ -0,0 +1,54 @@
ID: 0x72B0BD08
S/N: 01
Issuer: CN=The STEED Self-Signing Nonthority
Subject: CN=The STEED Self-Signing Nonthority
sha1_fpr: E6:99:39:A2:5F:5D:93:F2:06:71:5D:C9:FC:1A:25:DC:72:B0:BD:08
md5_fpr: C9:83:C8:13:91:53:5A:C2:9A:BA:AF:0E:9C:AF:93:0E
certid: BA9A5990A0E94A627D08D4D06FD15EC561FD15E8.01
keygrip: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
notBefore: 2011-11-11 00:00:00
notAfter: 2106-02-06 00:00:00
hashAlgo: 1.2.840.113549.1.1.5 (sha1WithRSAEncryption)
keyType: 1024 bit RSA
subjKeyId: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
authKeyId: [none]
keyUsage: certSign crlSign
extKeyUsage: [none]
policies: [none]
chainLength: 1
crlDP: [none]
authInfo: [none]
subjInfo: [none]
extn: 1.3.6.1.4.1.11591.2.2.2 (wellKnownPrivateKey) [3 octets]
-----BEGIN CERTIFICATE-----
MIICKDCCAZGgAwIBAgIBATANBgkqhkiG9w0BAQUFADAsMSowKAYDVQQDEyFUaGUg
U1RFRUQgU2VsZi1TaWduaW5nIE5vbnRob3JpdHkwIBcNMTExMTExMDAwMDAwWhgP
MjEwNjAyMDYwMDAwMDBaMCwxKjAoBgNVBAMTIVRoZSBTVEVFRCBTZWxmLVNpZ25p
bmcgTm9udGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAk2h9kqe8
0eb8ESY7UGV6j6S5zuP5DiM4TWJ3jKG2y+D2CyA1Sl90iZ6zyN3zCB0yR1xxhpuw
xdrwBRovRFludAbx3MeynYhzXkk0Hwn038q1oIt2YUw3Igz34s24o455ZE86JQ/6
5dC7ppF8Z1I9KBL96NO+qZR/alVAKxYAwS8CAwEAAaNYMFYwEgYDVR0TAQH/BAgw
BgEB/wIBATARBgorBgEEAdpHAgICBAMBAf8wHQYDVR0OBBYEFGimOJmN+rrFEOpk
XONPloay7ffqMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQB3JwUn
AbOdGv5ErojNSSP+yGZIy5av4wnkzK840Uj3jY6A5cuHroZGOD60hqLV2Hy0npox
zte4phWEKWmZiXd8SCmd3MFNgZSieiixye0qxSmuqYft2j6NhEXD5xc/iTTjFT42
SjGPLKAICuMBuGPnoozOEVlgqwaDqKOUph5sqw==
-----END CERTIFICATE-----
Created using these parameters:
Key-Type: RSA
Key-Length: 1024
Key-Grip: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
Key-Usage: cert
Serial: 1
Name-DN: CN=The STEED Self-Signing Nonthority
Not-Before: 2011-11-11
Not-After: 2106-02-06
Subject-Key-Id: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
Extension: 2.5.29.19 c 30060101ff020101
Extension: 1.3.6.1.4.1.11591.2.2.2 n 0101ff
Signing-Key: 68A638998DFABAC510EA645CE34F9686B2EDF7EA

View File

@ -5,10 +5,6 @@
commit log, and generate a top-level ChangeLog file from logs at
"make dist". See doc/HACKING for details.
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
* Makefile.am: Port to NPth.
2011-08-26 Werner Koch <wk@g10code.com>
* gpgconf-comp.c (gc_component): Mark for translation. Suggested

View File

@ -67,25 +67,25 @@ enum cmd_and_opt_values
/* The list of commands and options. */
static ARGPARSE_OPTS opts[] = {
ARGPARSE_group (301, N_("@\nOptions:\n ")),
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("quiet")),
ARGPARSE_s_n (oHex, "hex", N_("print data out hex encoded")),
ARGPARSE_s_n (oDecode,"decode", N_("decode received data lines")),
ARGPARSE_s_s (oRawSocket, "raw-socket",
ARGPARSE_s_s (oRawSocket, "raw-socket",
N_("|NAME|connect to Assuan socket NAME")),
ARGPARSE_s_s (oTcpSocket, "tcp-socket",
ARGPARSE_s_s (oTcpSocket, "tcp-socket",
N_("|ADDR|connect to Assuan server at ADDR")),
ARGPARSE_s_n (oExec, "exec",
ARGPARSE_s_n (oExec, "exec",
N_("run the Assuan server given on the command line")),
ARGPARSE_s_n (oNoExtConnect, "no-ext-connect",
N_("do not use extended connect mode")),
ARGPARSE_s_s (oRun, "run",
ARGPARSE_s_s (oRun, "run",
N_("|FILE|run commands from FILE on startup")),
ARGPARSE_s_n (oSubst, "subst", N_("run /subst on startup")),
ARGPARSE_s_n (oSubst, "subst", N_("run /subst on startup")),
ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
ARGPARSE_s_s (oHomedir, "homedir", "@" ),
ARGPARSE_s_s (oHomedir, "homedir", "@" ),
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
ARGPARSE_end ()
@ -216,7 +216,7 @@ gnu_getcwd (void)
#ifdef HAVE_W32CE_SYSTEM
strcpy (buffer, "/");
return buffer;
#else
#else
if (getcwd (buffer, size) == buffer)
return buffer;
xfree (buffer);
@ -246,22 +246,22 @@ unescape_string (const char *string)
{
switch (*s)
{
case 'b':
case 't':
case 'v':
case 'n':
case 'f':
case 'r':
case '"':
case '\'':
case 'b':
case 't':
case 'v':
case 'n':
case 'f':
case 'r':
case '"':
case '\'':
case '\\': n++; break;
case 'x':
case 'x':
if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
n++;
break;
default:
if (s[1] && s[2]
if (s[1] && s[2]
&& octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
n++;
break;
@ -272,7 +272,7 @@ unescape_string (const char *string)
esc = 1;
else
n++;
}
}
buffer = xmalloc (n+1);
d = (unsigned char*)buffer;
@ -291,7 +291,7 @@ unescape_string (const char *string)
case '"': *d++ = '\"'; break;
case '\'': *d++ = '\''; break;
case '\\': *d++ = '\\'; break;
case 'x':
case 'x':
if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
{
s++;
@ -301,7 +301,7 @@ unescape_string (const char *string)
break;
default:
if (s[1] && s[2]
if (s[1] && s[2]
&& octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
{
*d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2);
@ -315,7 +315,7 @@ unescape_string (const char *string)
esc = 1;
else
*d++ = *s;
}
}
*d = 0;
return buffer;
}
@ -334,7 +334,7 @@ unpercent_string (const char *string, int with_plus)
for (s=(const unsigned char *)string; *s; s++)
{
if (*s == '%' && s[1] && s[2])
{
{
s++;
n++;
s++;
@ -350,7 +350,7 @@ unpercent_string (const char *string, int with_plus)
for (s=(const unsigned char *)string; *s; s++)
{
if (*s == '%' && s[1] && s[2])
{
{
s++;
*p++ = xtoi_2 (s);
s++;
@ -387,7 +387,7 @@ set_var (const char *name, const char *value)
xfree (var->value);
var->value = value? xstrdup (value) : NULL;
return var->value;
}
}
static void
@ -455,12 +455,12 @@ arithmetic_op (int operator, const char *operands)
case '+': result += value; break;
case '-': result -= value; break;
case '*': result *= value; break;
case '/':
case '/':
if (!value)
return NULL;
result /= value;
break;
case '%':
case '%':
if (!value)
return NULL;
result %= value;
@ -480,10 +480,10 @@ arithmetic_op (int operator, const char *operands)
/* Extended version of get_var. This returns a malloced string and
understand the function syntax: "func args".
understand the function syntax: "func args".
Defined functions are
get - Return a value described by the next argument:
cwd - The current working directory.
homedir - The gnupg homedir.
@ -525,7 +525,7 @@ arithmetic_op (int operator, const char *operands)
Example: get_var_ext ("get sysconfdir") -> "/etc/gnupg"
*/
static char *
get_var_ext (const char *name)
@ -630,7 +630,7 @@ get_var_ext (const char *name)
{
s++;
intvalue = (int)strtol (s, NULL, 0);
result = xasprintf ("%s <%s>",
result = xasprintf ("%s <%s>",
gpg_strerror (intvalue), gpg_strsource (intvalue));
}
else if ( (s - name) == 1 && strchr ("+-*/%!|&", *name))
@ -642,7 +642,7 @@ get_var_ext (const char *name)
log_error ("unknown variable function `%.*s'\n", (int)(s-name), name);
result = NULL;
}
xfree (free_me);
recursion_count--;
return result;
@ -667,7 +667,7 @@ substitute_line (char *buffer)
p = strchr (line, '$');
if (!p)
return result; /* No more variables. */
if (p[1] == '$') /* Escaped dollar sign. */
{
memmove (p, p+1, strlen (p+1)+1);
@ -751,7 +751,7 @@ static char *
substitute_line_copy (const char *buffer)
{
char *result, *p;
p = xstrdup (buffer?buffer:"");
result = substitute_line (p);
if (!result)
@ -777,7 +777,7 @@ assign_variable (char *line, int syslet)
p++;
if (!*p)
set_var (name, NULL); /* Remove variable. */
set_var (name, NULL); /* Remove variable. */
else if (syslet)
{
free_me = opt.enable_varsubst? substitute_line_copy (p) : NULL;
@ -791,7 +791,7 @@ assign_variable (char *line, int syslet)
xfree (tmp);
xfree (free_me);
}
else
else
{
tmp = opt.enable_varsubst? substitute_line_copy (p) : NULL;
if (tmp)
@ -857,11 +857,11 @@ show_definq (void)
for (d=definq_list; d; d = d->next)
if (d->name)
printf ("%-20s %c %s\n",
printf ("%-20s %c %s\n",
d->name, d->is_var? 'v' : d->is_prog? 'p':'f', d->file);
for (d=definq_list; d; d = d->next)
if (!d->name)
printf ("%-20s %c %s\n", "*",
printf ("%-20s %c %s\n", "*",
d->is_var? 'v': d->is_prog? 'p':'f', d->file);
}
@ -871,14 +871,14 @@ static void
clear_definq (void)
{
while (definq_list)
{
{
definq_t tmp = definq_list->next;
xfree (definq_list->name);
xfree (definq_list);
definq_list = tmp;
}
definq_list_tail = &definq_list;
}
}
static void
@ -1005,7 +1005,7 @@ do_open (char *line)
HANDLE prochandle, handle, newhandle;
handle = (void*)_get_osfhandle (fd);
prochandle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, server_pid);
if (!prochandle)
{
@ -1030,7 +1030,7 @@ do_open (char *line)
log_info ("file `%s' opened in \"%s\" mode, fd=%d (libc=%d)\n",
name, mode, (int)open_fd_table[fd].handle, fd);
set_int_var (varname, (int)open_fd_table[fd].handle);
#else
#else
if (opt.verbose)
log_info ("file `%s' opened in \"%s\" mode, fd=%d\n",
name, mode, fd);
@ -1117,14 +1117,14 @@ do_serverpid (assuan_context_t ctx)
int rc;
membuf_t mb;
char *buffer;
init_membuf (&mb, 100);
rc = assuan_transact (ctx, "GETINFO pid", getinfo_pid_cb, &mb,
NULL, NULL, NULL, NULL);
put_membuf (&mb, "", 1);
buffer = get_membuf (&mb, NULL);
if (rc || !buffer)
log_error ("command \"%s\" failed: %s\n",
log_error ("command \"%s\" failed: %s\n",
"GETINFO pid", gpg_strerror (rc));
else
{
@ -1136,6 +1136,22 @@ do_serverpid (assuan_context_t ctx)
}
/* Return true if the command is either "HELP" or "SCD HELP". */
static int
help_cmd_p (const char *line)
{
if (!ascii_strncasecmp (line, "SCD", 3)
&& (spacep (line+3) || !line[3]))
{
for (line += 3; spacep (line); line++)
;
}
return (!ascii_strncasecmp (line, "HELP", 4)
&& (spacep (line+4) || !line[4]));
}
/* gpg-connect-agent's entry point. */
int
main (int argc, char **argv)
@ -1156,7 +1172,7 @@ main (int argc, char **argv)
loopline_t head;
loopline_t *tail;
loopline_t current;
unsigned int nestlevel;
unsigned int nestlevel;
int oneshot;
char *condition;
} loopstack[20];
@ -1197,7 +1213,7 @@ main (int argc, char **argv)
case oExec: opt.exec = 1; break;
case oNoExtConnect: opt.connect_flags &= ~(1); break;
case oRun: opt_run = pargs.r.ret_str; break;
case oSubst:
case oSubst:
opt.enable_varsubst = 1;
opt.trim_leading_spaces = 1;
break;
@ -1339,7 +1355,7 @@ main (int argc, char **argv)
log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
}
for (loopidx=0; loopidx < DIM (loopstack); loopidx++)
loopstack[loopidx].collecting = 0;
loopidx = -1;
@ -1396,7 +1412,7 @@ main (int argc, char **argv)
linesize = 0;
keep_line = 1;
}
n = read_line (script_fp? script_fp:stdin,
n = read_line (script_fp? script_fp:stdin,
&line, &linesize, &maxlength);
}
if (n < 0)
@ -1422,7 +1438,7 @@ main (int argc, char **argv)
log_info ("end of script\n");
continue;
}
break;
break;
}
if (!maxlength)
{
@ -1433,11 +1449,11 @@ main (int argc, char **argv)
log_info (_("line shortened due to embedded Nul character\n"));
if (line[n-1] == '\n')
line[n-1] = 0;
if (opt.trim_leading_spaces)
{
const char *s = line;
while (spacep (s))
s++;
if (s != line)
@ -1463,7 +1479,7 @@ main (int argc, char **argv)
loopstack[loopidx+1].nestlevel--;
else if (!strncmp (line, "/while", 6) && (!line[6]||spacep(line+6)))
loopstack[loopidx+1].nestlevel++;
if (loopstack[loopidx+1].nestlevel)
continue;
/* We reached the corresponding /end. */
@ -1546,7 +1562,7 @@ main (int argc, char **argv)
{
current_datasink = fopen (fname, "wb");
if (!current_datasink)
log_error ("can't open `%s': %s\n",
log_error ("can't open `%s': %s\n",
fname, strerror (errno));
}
xfree (tmpline);
@ -1783,7 +1799,7 @@ main (int argc, char **argv)
"/cleardef Delete all definitions.\n"
"/sendfd FILE MODE Open FILE and pass descriptor to server.\n"
"/recvfd Receive FD from server and print.\n"
"/open VAR FILE MODE Open FILE and assign the file descriptor to VAR.\n"
"/open VAR FILE MODE Open FILE and assign the file descriptor to VAR.\n"
"/close FD Close file with descriptor FD.\n"
"/showopen Show descriptors of all open files.\n"
"/serverpid Retrieve the pid of the server.\n"
@ -1799,7 +1815,7 @@ main (int argc, char **argv)
}
else
log_error (_("unknown command `%s'\n"), cmd );
continue;
}
@ -1822,9 +1838,7 @@ main (int argc, char **argv)
if (*line == '#' || !*line)
continue; /* Don't expect a response for a comment line. */
rc = read_and_print_response (ctx, (!ascii_strncasecmp (line, "HELP", 4)
&& (spacep (line+4) || !line[4])),
&cmderr);
rc = read_and_print_response (ctx, help_cmd_p (line), &cmderr);
if (rc)
log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
if ((rc || cmderr) && script_fp)
@ -1833,7 +1847,7 @@ main (int argc, char **argv)
fclose (script_fp);
script_fp = NULL;
}
/* FIXME: If the last command was BYE or the server died for
some other reason, we won't notice until we get the next
@ -1844,8 +1858,8 @@ main (int argc, char **argv)
if (opt.verbose)
log_info ("closing connection to agent\n");
return 0;
return 0;
}
@ -1911,7 +1925,7 @@ handle_inquire (assuan_context_t ctx, char *line)
log_error ("error executing `%s': %s\n",
d->file, strerror (errno));
else if (opt.verbose)
log_error ("handling inquiry `%s' by running `%s'\n",
log_error ("handling inquiry `%s' by running `%s'\n",
name, d->file);
}
else
@ -1974,7 +1988,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
*r_goterr = 0;
for (;;)
{
do
do
{
rc = assuan_read_line (ctx, &line, &linelen);
if (rc)
@ -1985,7 +1999,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
fwrite (line, linelen, 1, stdout);
putchar ('\n');
}
}
}
while (*line == '#' || !linelen);
if (linelen >= 1
@ -1999,7 +2013,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
for (j=2, s=(unsigned char*)line+2; j < linelen; j++, s++ )
{
if (*s == '%' && j+2 < linelen)
{
{
s++; j++;
c = xtoi_2 ( s );
s++; j++;
@ -2054,7 +2068,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
need_d = 0;
}
if (*s == '%' && j+2 < linelen)
{
{
s++; j++;
c = xtoi_2 ( s );
s++; j++;
@ -2073,7 +2087,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
putchar ('\n');
}
}
else
else
{
if (need_lf)
{
@ -2083,7 +2097,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
}
if (linelen >= 1
&& line[0] == 'S'
&& line[0] == 'S'
&& (line[1] == '\0' || line[1] == ' '))
{
if (!current_datasink || current_datasink != stdout)
@ -2091,7 +2105,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
fwrite (line, linelen, 1, stdout);
putchar ('\n');
}
}
}
else if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
@ -2121,11 +2135,11 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
}
*r_goterr = 1;
return 0;
}
}
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[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
if (!current_datasink || current_datasink != stdout)