1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-12-22 10:19:57 +01:00

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 accept --with-libgpg-error-prefix as well as --with-gpg-error-prefix
* m4/gpg-error.m4: Update from git master. * 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> 2011-09-23 Werner Koch <wk@g10code.com>
* configure.ac: Remove check for gcry_kdf_derive. * configure.ac: Remove check for gcry_kdf_derive.

View File

@ -116,6 +116,7 @@ gen-ChangeLog:
if test -d $(top_srcdir)/.git; then \ if test -d $(top_srcdir)/.git; then \
(cd $(top_srcdir) && \ (cd $(top_srcdir) && \
./scripts/gitlog-to-changelog \ ./scripts/gitlog-to-changelog \
--append-dot --tear-off \
--amend=scripts/git-log-fix \ --amend=scripts/git-log-fix \
--since=$(gen_start_date) ) > $(distdir)/cl-t; \ --since=$(gen_start_date) ) > $(distdir)/cl-t; \
cat $(top_srcdir)/scripts/git-log-footer >> $(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. * 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. * 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) Noteworthy changes in version 2.1.0beta2 (2011-03-08)
----------------------------------------------------- -----------------------------------------------------

View File

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

View File

@ -12,17 +12,6 @@
(ssh_handler_request_identities): Do not call card_key_available (ssh_handler_request_identities): Do not call card_key_available
if the scdaemon is disabled. 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> 2011-09-12 Ben Kibbey <bjk@luxsci.net>
* genkey.c (agent_ask_new_passphrase): Allow for an empty passphrase * genkey.c (agent_ask_new_passphrase): Allow for an empty passphrase

View File

@ -73,17 +73,20 @@ struct
/* True if we handle sigusr2. */ /* True if we handle sigusr2. */
int sigusr2_enabled; 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. */ Assuan command UPDATESTARTUPTTY. */
session_env_t startup_env; session_env_t startup_env;
char *startup_lc_ctype; char *startup_lc_ctype;
char *startup_lc_messages; char *startup_lc_messages;
const char *pinentry_program; /* Filename of the program to start as /* Filename of the program to start as pinentry. */
pinentry. */ const char *pinentry_program;
const char *scdaemon_program; /* Filename of the program to handle
smartcard tasks. */ /* Filename of the program to handle smartcard tasks. */
const char *scdaemon_program;
int disable_scdaemon; /* Never use the SCdaemon. */ int disable_scdaemon; /* Never use the SCdaemon. */
int no_grab; /* Don't let the pinentry grab the keyboard */ int no_grab; /* Don't let the pinentry grab the keyboard */
/* The name of the file pinentry shall tocuh before exiting. If /* The name of the file pinentry shall tocuh before exiting. If
@ -98,31 +101,51 @@ struct
/* Flag disallowing bypassing of the warning. */ /* Flag disallowing bypassing of the warning. */
int enforce_passphrase_constraints; int enforce_passphrase_constraints;
/* The require minmum length of a passphrase. */ /* The require minmum length of a passphrase. */
unsigned int min_passphrase_len; unsigned int min_passphrase_len;
/* The minimum number of non-alpha characters in a passphrase. */ /* The minimum number of non-alpha characters in a passphrase. */
unsigned int min_passphrase_nonalpha; unsigned int min_passphrase_nonalpha;
/* File name with a patternfile or NULL if not enabled. */ /* File name with a patternfile or NULL if not enabled. */
const char *check_passphrase_pattern; const char *check_passphrase_pattern;
/* If not 0 the user is asked to change his passphrase after these /* If not 0 the user is asked to change his passphrase after these
number of days. */ number of days. */
unsigned int max_passphrase_days; unsigned int max_passphrase_days;
/* If set, a passphrase history will be written and checked at each /* If set, a passphrase history will be written and checked at each
passphrase change. */ passphrase change. */
int enable_passhrase_history; int enable_passhrase_history;
int running_detached; /* We are running detached from the tty. */ 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; 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; int allow_mark_trusted;
/* If this global option is true, the Assuan command
PRESET_PASSPHRASE is allowed. */
int allow_preset_passphrase; int allow_preset_passphrase;
/* If this global option is true, the Assuan option
pinentry-mode=loopback is allowed. */
int allow_loopback_pinentry; int allow_loopback_pinentry;
int keep_tty; /* Don't switch the TTY (for pinentry) on request */ 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 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; } opt;
/* Bit values for the --debug option. */
#define DBG_COMMAND_VALUE 1 /* debug commands i/o */ #define DBG_COMMAND_VALUE 1 /* debug commands i/o */
#define DBG_MPI_VALUE 2 /* debug mpi details */ #define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */ #define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
@ -130,8 +153,9 @@ struct
#define DBG_CACHE_VALUE 64 /* debug the caching */ #define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */ #define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */ #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_COMMAND (opt.debug & DBG_COMMAND_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE) #define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
@ -139,14 +163,18 @@ struct
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE) #define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
/* Forward reference for local definitions in command.c. */
struct server_local_s; struct server_local_s;
/* Forward reference for local definitions in call-scd.c. */
struct scd_local_s; struct scd_local_s;
/* Collection of data per session (aka connection). */ /* Collection of data per session (aka connection). */
struct server_control_s struct server_control_s
{ {
/* Private data used to fire up the connection thread. We use this /* 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 { struct {
gnupg_fd_t fd; gnupg_fd_t fd;
} thread_startup; } thread_startup;
@ -157,6 +185,7 @@ struct server_control_s
/* Private data of the SCdaemon (call-scd.c). */ /* Private data of the SCdaemon (call-scd.c). */
struct scd_local_s *scd_local; struct scd_local_s *scd_local;
/* Environment settings for the connection. */
session_env_t session_env; session_env_t session_env;
char *lc_ctype; char *lc_ctype;
char *lc_messages; char *lc_messages;
@ -177,37 +206,47 @@ struct server_control_s
unsigned char keygrip[20]; unsigned char keygrip[20];
int have_keygrip; int have_keygrip;
int use_auth_call; /* Hack to send the PKAUTH command instead of the /* A flag to enable a hack to send the PKAUTH command instead of the
PKSIGN command to the scdaemon. */ PKSIGN command to the scdaemon. */
int in_passwd; /* Hack to inhibit enforced passphrase change int use_auth_call;
during an explicit passwd command. */
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 struct pin_entry_info_s
{ {
int min_digits; /* min. number of digits required or 0 for freeform entry */ int min_digits; /* min. number of digits required or 0 for freeform entry */
int max_digits; /* max. number of allowed digits allowed*/ int max_digits; /* max. number of allowed digits allowed*/
int max_tries; int max_tries; /* max. number of allowed tries. */
int failed_tries; int failed_tries; /* Number of tries so far failed. */
int with_qualitybar; /* Set if the quality bar should be displayed. */ 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 */ 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 */ 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 */ const char *cb_errtext; /* used by the cb to display a specific error */
size_t max_length; /* allocated length of the buffer */ size_t max_length; /* Allocated length of the buffer PIN. */
char pin[1]; 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 enum
{ {
PRIVATE_KEY_UNKNOWN = 0, PRIVATE_KEY_UNKNOWN = 0, /* Type of key is not known. */
PRIVATE_KEY_CLEAR = 1, PRIVATE_KEY_CLEAR = 1, /* The key is not protected. */
PRIVATE_KEY_PROTECTED = 2, PRIVATE_KEY_PROTECTED = 2, /* The key is protected. */
PRIVATE_KEY_SHADOWED = 3, PRIVATE_KEY_SHADOWED = 3, /* The key is a stub for a smartcard
PROTECTED_SHARED_SECRET = 4 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); assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
} }
else if (pid > 0) else if (pid > 0)
kill (pid, SIGKILL); /* Need to use SIGKILL due to bad kill (pid, SIGINT);
interaction of SIGINT with Pth. */
#endif #endif
/* Now wait for the thread to terminate. */ /* Now wait for the thread to terminate. */

View File

@ -1,5 +1,6 @@
/* call-scd.c - fork of the scdaemon to do SC operations /* 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. * This file is part of GnuPG.
* *
@ -44,15 +45,6 @@
#define MAX_OPEN_FDS 20 #define MAX_OPEN_FDS 20
#endif #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. */ /* Definition of module local data of the CTRL structure. */
struct scd_local_s struct scd_local_s
{ {
@ -1115,16 +1107,28 @@ pass_status_thru (void *opaque, const char *line)
char keyword[200]; char keyword[200];
int i; int i;
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++) for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
keyword[i] = *line; keyword[i] = *line;
keyword[i] = 0; keyword[i] = 0;
/* truncate any remaining keyword stuff. */
/* Truncate any remaining keyword stuff. */
for (; *line && !spacep (line); line++) for (; *line && !spacep (line); line++)
; ;
while (spacep (line)) while (spacep (line))
line++; line++;
assuan_write_status (ctx, keyword, line); assuan_write_status (ctx, keyword, line);
}
return 0; return 0;
} }

View File

@ -50,31 +50,57 @@
/* The size of the import/export KEK key (in bytes). */ /* The size of the import/export KEK key (in bytes). */
#define KEYWRAP_KEYSIZE (128/8) #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)) #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 #if MAX_DIGEST_LEN < 20
#error MAX_DIGEST_LEN shorter than keygrip #error MAX_DIGEST_LEN shorter than keygrip
#endif #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 struct server_local_s
{ {
/* Our Assuan context. */
assuan_context_t assuan_ctx; 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; int use_cache_for_signing;
char *keydesc; /* Allocated description for the next key
operation. */ /* An allocated description for the next key operation. This is
int pause_io_logging; /* Used to suppress I/O logging during a command */ used if a pinnetry needs to be popped up. */
int stopme; /* If set to true the agent will be terminated after char *keydesc;
the end of this session. */
int allow_pinentry_notify; /* Set if pinentry notifications should /* Flags to suppress I/O logging during a command. */
be done. */ int pause_io_logging;
void *import_key; /* Malloced KEK for the import_key command. */
void *export_key; /* Malloced KEK for the export_key command. */ /* If this flags is set to true the agent will be terminated after
int allow_fully_canceled; /* Client is aware of GPG_ERR_FULLY_CANCELED. */ the end of the current session. */
char *last_cache_nonce; /* Last CACHE_NOCNE sent as status (malloced). */ int stopme;
char *last_passwd_nonce; /* Last PASSWD_NOCNE sent as status (malloced). */
/* 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 static void
clear_nonce_cache (ctrl_t ctrl) 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 static gpg_error_t
reset_notify (assuan_context_t ctx, char *line) reset_notify (assuan_context_t ctx, char *line)
{ {
@ -196,8 +227,13 @@ reset_notify (assuan_context_t ctx, char *line)
} }
/* Skip over options. /* Skip over options in LINE.
Blanks after the options are also removed. */
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 * static char *
skip_options (const char *line) skip_options (const char *line)
{ {
@ -213,7 +249,11 @@ skip_options (const char *line)
return (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 static int
has_option (const char *line, const char *name) 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))); 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 /* 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 and ignores an argument, i.e. with NAME being "--hash" it would
return true for "--hash" as well as for "--hash=foo". */ 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] == '=')); && (!s[n] || spacep (s+n) || s[n] == '='));
} }
/* Return a pointer to the argument of the option with NAME. If such /* 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 * static char *
option_value (const char *line, const char *name) 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 static void
plus_to_blank (char *s) plus_to_blank (char *s)
{ {
@ -296,6 +338,7 @@ parse_hexstring (assuan_context_t ctx, const char *string, size_t *len)
return 0; return 0;
} }
/* Parse the keygrip in STRING into the provided buffer BUF. BUF must /* 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. */ returns an error. */
@ -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 gpg_error_t
agent_write_status (ctrl_t ctrl, const char *keyword, ...) agent_write_status (ctrl_t ctrl, const char *keyword, ...)
{ {
@ -463,6 +510,7 @@ bump_key_eventcounter (void)
eventcounter.any++; eventcounter.any++;
} }
/* This function should be called for all card reader status /* This function should be called for all card reader status
changes. This function is assured not to do any context changes. This function is assured not to do any context
switches. */ 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 static gpg_error_t
cmd_keyinfo (assuan_context_t ctx, char *line) 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 static int
send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw) 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"); return set_error (GPG_ERR_NOT_SUPPORTED, "no --use-standard-socket");
ctrl->server_local->stopme = 1; ctrl->server_local->stopme = 1;
#ifdef ASSUAN_FORCE_CLOSE
assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1); assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
return 0; 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 static gpg_error_t
option_handler (assuan_context_t ctx, const char *key, const char *value) 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 static int
register_commands (assuan_context_t ctx) 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); assuan_set_pointer (ctx, ctrl);
ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local); ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
ctrl->server_local->assuan_ctx = ctx; ctrl->server_local->assuan_ctx = ctx;
ctrl->server_local->message_fd = -1;
ctrl->server_local->use_cache_for_signing = 1; ctrl->server_local->use_cache_for_signing = 1;
ctrl->digest.raw_value = 0; 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 gpg_error_t
pinentry_loopback(ctrl_t ctrl, const char *keyword, pinentry_loopback(ctrl_t ctrl, const char *keyword,
unsigned char **buffer, size_t *size, unsigned char **buffer, size_t *size,

View File

@ -299,6 +299,9 @@ ASSUAN_SYSTEM_NPTH_IMPL;
Functions. 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 * static char *
make_libversion (const char *libname, const char *(*getfnc)(const 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 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 * static const char *
my_strusage (int level) 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 static void
cleanup (void) cleanup (void)
{ {
@ -1150,11 +1158,11 @@ main (int argc, char **argv )
if (csh_style) if (csh_style)
{ {
*strchr (infostr, '=') = ' '; *strchr (infostr, '=') = ' ';
es_printf ("setenv %s\n", infostr); es_printf ("setenv %s;\n", infostr);
if (opt.ssh_support) if (opt.ssh_support)
{ {
*strchr (infostr_ssh_sock, '=') = ' '; *strchr (infostr_ssh_sock, '=') = ' ';
es_printf ("setenv %s\n", infostr_ssh_sock); es_printf ("setenv %s;\n", infostr_ssh_sock);
} }
} }
else else
@ -1238,6 +1246,8 @@ main (int argc, char **argv )
} }
/* Exit entry point. This function should be called instead of a
plain exit. */
void void
agent_exit (int rc) 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 static void
agent_init_default_ctrl (ctrl_t ctrl) 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 static void
agent_deinit_default_ctrl (ctrl_t ctrl) agent_deinit_default_ctrl (ctrl_t ctrl)
{ {
@ -1690,6 +1707,7 @@ agent_sighup_action (void)
} }
/* A helper function to handle SIGUSR2. */
static void static void
agent_sigusr2_action (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 static void
handle_signal (int signo) 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); 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 static gpg_error_t

View File

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

View File

@ -583,7 +583,8 @@ use_hardlinks_p (const char *tname)
strcpy (lname, tname); strcpy (lname, tname);
strcat (lname, "x"); 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)) if (stat (tname, &sb))
res = -1; /* Ooops. */ res = -1; /* Ooops. */
@ -1004,7 +1005,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
{ {
struct stat sb; 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)) if (stat (h->tname, &sb))
{ {

View File

@ -217,6 +217,17 @@ struct notify_list_s
}; };
typedef struct notify_list_s *notify_list_t; 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. */ /* An internal stream object. */
struct estream_internal struct estream_internal
{ {
@ -231,6 +242,7 @@ struct estream_internal
es_cookie_read_function_t func_read; es_cookie_read_function_t func_read;
es_cookie_write_function_t func_write; es_cookie_write_function_t func_write;
es_cookie_seek_function_t func_seek; es_cookie_seek_function_t func_seek;
cookie_ioctl_function_t func_ioctl;
es_cookie_close_function_t func_close; es_cookie_close_function_t func_close;
int strategy; int strategy;
es_syshd_t syshd; /* A copy of the sytem handle. */ 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; 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. */ /* Destroy function for memory objects. */
static int static int
@ -1608,6 +1647,7 @@ es_initialize (estream_t stream,
stream->intern->func_read = functions.func_read; stream->intern->func_read = functions.func_read;
stream->intern->func_write = functions.func_write; stream->intern->func_write = functions.func_write;
stream->intern->func_seek = functions.func_seek; stream->intern->func_seek = functions.func_seek;
stream->intern->func_ioctl = NULL;
stream->intern->func_close = functions.func_close; stream->intern->func_close = functions.func_close;
stream->intern->strategy = _IOFBF; stream->intern->strategy = _IOFBF;
stream->intern->syshd = *syshd; 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)) if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags, 0))
(*estream_functions_mem.func_close) (cookie); (*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; 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. /* Register or unregister a close notification function for STREAM.
FNC is the function to call and FNC_VALUE the value passed as FNC is the function to call and FNC_VALUE the value passed as
second argument. To register the notification the value for MODE second argument. To register the notification the value for MODE

View File

@ -1,5 +1,5 @@
/* estream.h - Extended stream I/O Library /* 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. * This file is part of Libestream.
* *
@ -88,6 +88,7 @@
#define es_freopen _ESTREAM_PREFIX(es_freopen) #define es_freopen _ESTREAM_PREFIX(es_freopen)
#define es_fopencookie _ESTREAM_PREFIX(es_fopencookie) #define es_fopencookie _ESTREAM_PREFIX(es_fopencookie)
#define es_fclose _ESTREAM_PREFIX(es_fclose) #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_onclose _ESTREAM_PREFIX(es_onclose)
#define es_fileno _ESTREAM_PREFIX(es_fileno) #define es_fileno _ESTREAM_PREFIX(es_fileno)
#define es_fileno_unlocked _ESTREAM_PREFIX(es_fileno_unlocked) #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, const char *ES__RESTRICT mode,
es_cookie_io_functions_t functions); es_cookie_io_functions_t functions);
int es_fclose (estream_t stream); 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, int es_onclose (estream_t stream, int mode,
void (*fnc) (estream_t, void*), void *fnc_value); void (*fnc) (estream_t, void*), void *fnc_value);
int es_fileno (estream_t stream); int es_fileno (estream_t stream);

View File

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

View File

@ -15,21 +15,6 @@
* certcache.c (classify_pattern): Remove unused variable and make * certcache.c (classify_pattern): Remove unused variable and make
explicit substring search work. 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> 2011-06-01 Marcus Brinkmann <mb@g10code.com>
* Makefile.am (dirmngr_ldap_CFLAGS): Add $(LIBGCRYPT_CFLAGS), * Makefile.am (dirmngr_ldap_CFLAGS): Add $(LIBGCRYPT_CFLAGS),

View File

@ -1038,7 +1038,7 @@ main (int argc, char **argv)
if (csh_style) if (csh_style)
{ {
*strchr (infostr, '=') = ' '; *strchr (infostr, '=') = ' ';
es_printf ( "setenv %s\n", infostr); es_printf ( "setenv %s;\n", infostr);
} }
else 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 u = The key is ultimately valid. This often means
that the secret key is available, but any key may that the secret key is available, but any key may
be marked as ultimately valid. 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 If the validity information is given for a UID or UAT
record, it describes the validity calculated based on this record, it describes the validity calculated based on this
@ -347,6 +351,7 @@ more arguments in future versions.
"pgp" for the standard PGP WoT. "pgp" for the standard PGP WoT.
"shell" for the standard X.509 model. "shell" for the standard X.509 model.
"chain" for the chain model. "chain" for the chain model.
"steed" for the STEED model.
Note that we use the term "TRUST_" in the status names for Note that we use the term "TRUST_" in the status names for
historic reasons; we now speak of validity. 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.1.1 pkaAddress
1.3.6.1.4.1.11591.2.2 X.509 extensions 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.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 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 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 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. 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 <=== ===> What follows is probably out of date <===
@ -39,15 +40,17 @@ RFCs
1750 Randomness Recommendations for Security. 1750 Randomness Recommendations for Security.
1991 PGP Message Exchange Formats. 1991 PGP Message Exchange Formats (obsolete)
2015 MIME Security with Pretty Good Privacy (PGP).
2144 The CAST-128 Encryption Algorithm. 2144 The CAST-128 Encryption Algorithm.
2279 UTF-8, a transformation format of ISO 10646. 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= d2qclY03eJ7zx6Zpq8VFuVvOxvmFZ4mMe706runhCq+rHc5x6x0/oIMhDrk=
-----END CERTIFICATE----- -----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 :CUSTOM_ID: i-get-sed-errors-when-running-configure-on-mac-os-x
:END: :END:
This will be fixed after GnuPG has been upgraded to autoconf-2.50. This problem has been fixed for all modern GnuPG versions.
Until then, find the line setting CDPATH in the configure script (By using an autoconf 2.50 generated configure script).
and place an:
: unset CDPATH
statement below it.
** Why does GnuPG 1.0.6 bail out on keyrings used with 1.0.7? ** Why does GnuPG 1.0.6 bail out on keyrings used with 1.0.7?
:PROPERTIES: :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. 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 * Acknowledgements
:PROPERTIES: :PROPERTIES:
:CUSTOM_ID: acknowledgements :CUSTOM_ID: acknowledgements

View File

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

View File

@ -178,9 +178,11 @@ show memory statistics.
@item 9 (512) @item 9 (512)
write hashed data to files named @code{dbgmd-000*} write hashed data to files named @code{dbgmd-000*}
@item 10 (1024) @item 10 (1024)
trace Assuan protocol trace Assuan protocol. See also option @option{--debug-assuan-log-cats}.
@item 11 (2048) @item 11 (2048)
trace APDU I/O to the card. This may reveal sensitive data. trace APDU I/O to the card. This may reveal sensitive data.
@item 12 (4096)
trace some card reader related function calls.
@end table @end table
@item --debug-all @item --debug-all
@ -215,6 +217,15 @@ dump. This options enables it and also changes the working directory to
@opindex debug-log-tid @opindex debug-log-tid
This option appends a thread ID to the PID in the log output. 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 @item --no-detach
@opindex no-detach @opindex no-detach
@ -318,6 +329,7 @@ stripping off the two leading dashes.
* DINSIG Card:: The DINSIG card application * DINSIG Card:: The DINSIG card application
* PKCS#15 Card:: The PKCS#15 card application * PKCS#15 Card:: The PKCS#15 card application
* Geldkarte Card:: The Geldkarte application * Geldkarte Card:: The Geldkarte application
* Undefined Card:: The Undefined stub application
@end menu @end menu
@node OpenPGP Card @node OpenPGP Card
@ -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 Geldkarte. The Geldkarte is a small amount debit card application which
comes with almost all German banking cards. 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 *******************************************
@c *************** **************** @c *************** ****************

View File

@ -1,5 +1,5 @@
/* photoid.c - photo ID handling code /* 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. * This file is part of GnuPG.
* *
@ -141,8 +141,7 @@ generate_photo_id(PKT_public_key *pk,const char *photo_name)
iobuf_close(file); iobuf_close(file);
/* Is it a JPEG? */ /* Is it a JPEG? */
if(photo[0]!=0xFF || photo[1]!=0xD8 || if(photo[0]!=0xFF || photo[1]!=0xD8)
photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F')
{ {
log_error(_("`%s' is not a JPEG file\n"),filename); log_error(_("`%s' is not a JPEG file\n"),filename);
xfree(photo); xfree(photo);

View File

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

View File

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

View File

@ -9,7 +9,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: gnupg-2.1.0\n" "Project-Id-Version: gnupg-2.1.0\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\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" "Last-Translator: Werner Koch <wk@gnupg.org>\n"
"Language-Team: German <de@li.org>\n" "Language-Team: German <de@li.org>\n"
"MIME-Version: 1.0\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" msgid "detected card with S/N: %s\n"
msgstr "Erkannte Karte hat die Seriennummer: %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" 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 #, c-format
msgid "no suitable card key found: %s\n" msgid "no suitable card key found: %s\n"
@ -5434,17 +5434,11 @@ msgstr "|AN|Neue Admin-PIN"
msgid "|N|New PIN" msgid "|N|New PIN"
msgstr "|N|Neue 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" 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" 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" msgid "error reading application data\n"
msgstr "Fehler beim Lesen der Anwendungsdaten\n" msgstr "Fehler beim Lesen der Anwendungsdaten\n"
@ -5880,6 +5874,18 @@ msgstr ""
msgid "line %d: invalid hash algorithm given\n" msgid "line %d: invalid hash algorithm given\n"
msgstr "Zeile %d: Ungültiges Hashverfahren\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 #, c-format
msgid "line %d: error reading key `%s' from card: %s\n" 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" 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" "Syntax: gpg-check-pattern [optionen] Musterdatei\n"
"Die von stdin gelesene Passphrase gegen die Musterdatei prüfen\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" #~ msgid " - probably dead - removing lock"
#~ msgstr " - existiert wahrscheinlich nicht mehr - entferne Sperre" #~ msgstr " - existiert wahrscheinlich nicht mehr - entferne Sperre"

View File

@ -87,10 +87,6 @@
(handle_control): New. (handle_control): New.
(main): Handle the case 6 of handle_control. (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> 2011-08-10 Werner Koch <wk@g10code.com>
* command.c (cmd_killscd): Use the new assuan force close flag * 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_SOURCES = \
scdaemon.c scdaemon.h \ scdaemon.c scdaemon.h \
command.c \ command.c \
atr.c atr.h \
apdu.c apdu.h \ apdu.c apdu.h \
ccid-driver.c ccid-driver.h \ ccid-driver.c ccid-driver.h \
iso7816.c iso7816.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_FILE_NOT_FOUND : return "file not found";
case SW_RECORD_NOT_FOUND:return "record not found"; case SW_RECORD_NOT_FOUND:return "record not found";
case SW_REF_NOT_FOUND : return "reference not found"; case SW_REF_NOT_FOUND : return "reference not found";
case SW_BAD_LC : return "bad Lc"; case SW_NOT_ENOUGH_MEMORY: return "not enough memory space in the file";
case SW_BAD_P0_P1 : return "bad P0 or P1"; 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_INS_NOT_SUP : return "instruction not supported";
case SW_CLA_NOT_SUP : return "class not supported"; case SW_CLA_NOT_SUP : return "class not supported";
case SW_SUCCESS : return "success"; case SW_SUCCESS : return "success";
@ -2052,7 +2055,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
{ {
int sw; int sw;
unsigned char *pin_verify; unsigned char *pin_verify;
unsigned long len = PIN_VERIFY_STRUCTURE_SIZE; int len = PIN_VERIFY_STRUCTURE_SIZE;
unsigned char result[2]; unsigned char result[2];
size_t resultlen = 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[22] = p1; /* abData[3] */
pin_verify[23] = 0x00; /* abData[4] */ 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, sw = control_pcsc (slot, reader_table[slot].pcsc.verify_ioctl,
pin_verify, len, result, &resultlen); pin_verify, len, result, &resultlen);
xfree (pin_verify); xfree (pin_verify);
if (sw || resultlen < 2) if (sw || resultlen < 2)
return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE; return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
sw = (result[resultlen-2] << 8) | result[resultlen-1]; 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; return sw;
} }
@ -2125,7 +2139,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
{ {
int sw; int sw;
unsigned char *pin_modify; unsigned char *pin_modify;
unsigned long len = PIN_MODIFY_STRUCTURE_SIZE; int len = PIN_MODIFY_STRUCTURE_SIZE;
unsigned char result[2]; unsigned char result[2];
size_t resultlen = 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[27] = p1; /* abData[3] */
pin_modify[28] = 0x00; /* abData[4] */ 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, sw = control_pcsc (slot, reader_table[slot].pcsc.modify_ioctl,
pin_modify, len, result, &resultlen); pin_modify, len, result, &resultlen);
xfree (pin_modify); xfree (pin_modify);
if (sw || resultlen < 2) if (sw || resultlen < 2)
{
log_error ("control_pcsc failed: %d\n", sw);
return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE; return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
}
sw = (result[resultlen-2] << 8) | result[resultlen-1]; 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; return sw;
} }
@ -2783,6 +2806,9 @@ apdu_open_reader (const char *portstr, int *r_no_service)
static int pcsc_api_loaded, ct_api_loaded; static int pcsc_api_loaded, ct_api_loaded;
int slot; int slot;
if (DBG_READER)
log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
if (r_no_service) if (r_no_service)
*r_no_service = 0; *r_no_service = 0;
@ -2797,6 +2823,8 @@ apdu_open_reader (const char *portstr, int *r_no_service)
if (slot != -1) if (slot != -1)
{ {
once_available = 1; once_available = 1;
if (DBG_READER)
log_debug ("leave: apdu_open_reader => slot=%d [ccid]\n", slot);
return slot; /* got one */ return slot; /* got one */
} }
@ -2807,15 +2835,23 @@ apdu_open_reader (const char *portstr, int *r_no_service)
and over again. To reset this flag "gpgconf --kill scdaemon" and over again. To reset this flag "gpgconf --kill scdaemon"
can be used. */ can be used. */
if (once_available) if (once_available)
{
if (DBG_READER)
log_debug ("leave: apdu_open_reader => slot=-1 (once_avail)\n");
return -1; return -1;
}
/* If a CCID reader specification has been given, the user does /* If a CCID reader specification has been given, the user does
not want a fallback to other drivers. */ not want a fallback to other drivers. */
if (portstr) if (portstr)
for (s=portstr, i=0; *s; s++) for (s=portstr, i=0; *s; s++)
if (*s == ':' && (++i == 3)) if (*s == ':' && (++i == 3))
{
if (DBG_READER)
log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
return -1; return -1;
} }
}
#endif /* HAVE_LIBUSB */ #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) if (slot == -1 && r_no_service && pcsc_no_service)
*r_no_service = 1; *r_no_service = 1;
if (DBG_READER)
log_debug ("leave: apdu_open_reader => slot=%d [pc/sc]\n", slot);
return slot; return slot;
} }
@ -2993,13 +3031,31 @@ apdu_close_reader (int slot)
{ {
int sw; 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 ) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
{
if (DBG_READER)
log_debug ("leave: apdu_close_reader => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER; return SW_HOST_NO_DRIVER;
}
sw = apdu_disconnect (slot); sw = apdu_disconnect (slot);
if (sw) if (sw)
{
if (DBG_READER)
log_debug ("leave: apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
return sw; return sw;
}
if (reader_table[slot].close_reader) 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; return SW_HOST_NOT_SUPPORTED;
} }
@ -3038,13 +3094,32 @@ apdu_shutdown_reader (int slot)
{ {
int sw; 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 ) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
{
if (DBG_READER)
log_debug ("leave: apdu_shutdown_reader => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER; return SW_HOST_NO_DRIVER;
}
sw = apdu_disconnect (slot); sw = apdu_disconnect (slot);
if (sw) if (sw)
{
if (DBG_READER)
log_debug ("leave: apdu_shutdown_reader => 0x%x (apdu_disconnect)\n",
sw);
return sw; return sw;
}
if (reader_table[slot].shutdown_reader) 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; 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 /* 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 int
apdu_connect (int slot) apdu_connect (int slot)
{ {
int sw; 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 ) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
{
if (DBG_READER)
log_debug ("leave: apdu_connect => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER; return SW_HOST_NO_DRIVER;
}
/* Only if the access method provides a connect function we use it. /* Only if the access method provides a connect function we use it.
If not, we expect that the card has been implicitly connected by 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. 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 Without that we would force a reset of the card with the next
call to apdu_get_status. */ 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; return sw;
} }
@ -3102,8 +3196,15 @@ apdu_disconnect (int slot)
{ {
int sw; int sw;
if (DBG_READER)
log_debug ("enter: apdu_disconnect: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
{
if (DBG_READER)
log_debug ("leave: apdu_disconnect => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER; return SW_HOST_NO_DRIVER;
}
if (reader_table[slot].disconnect_card) if (reader_table[slot].disconnect_card)
{ {
@ -3116,6 +3217,9 @@ apdu_disconnect (int slot)
} }
else else
sw = 0; sw = 0;
if (DBG_READER)
log_debug ("leave: apdu_disconnect => sw=0x%x\n", sw);
return sw; return sw;
} }
@ -3151,11 +3255,22 @@ apdu_reset (int slot)
{ {
int sw; int sw;
if (DBG_READER)
log_debug ("enter: apdu_reset: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used ) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
{
if (DBG_READER)
log_debug ("leave: apdu_reset => SW_HOST_NO_DRIVER\n");
return SW_HOST_NO_DRIVER; return SW_HOST_NO_DRIVER;
}
if ((sw = lock_slot (slot))) if ((sw = lock_slot (slot)))
{
if (DBG_READER)
log_debug ("leave: apdu_reset => sw=0x%x (lock_slot)\n", sw);
return sw; return sw;
}
reader_table[slot].last_status = 0; reader_table[slot].last_status = 0;
if (reader_table[slot].reset_reader) if (reader_table[slot].reset_reader)
@ -3171,73 +3286,47 @@ apdu_reset (int slot)
} }
unlock_slot (slot); unlock_slot (slot);
if (DBG_READER)
log_debug ("leave: apdu_reset => sw=0x%x\n", sw);
return sw; return sw;
} }
/* Activate a card if it has not yet been done. This is a kind of /* Return the ATR or NULL if none is available. On success the length
reset-if-required. It is useful to test for presence of a card of the ATR is stored at ATRLEN. The caller must free the returned
before issuing a bunch of apdu commands. It does not wait on a value. */
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;
}
unsigned char * unsigned char *
apdu_get_atr (int slot, size_t *atrlen) apdu_get_atr (int slot, size_t *atrlen)
{ {
unsigned char *buf; 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 ) if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
{
if (DBG_READER)
log_debug ("leave: apdu_get_atr => NULL (bad slot)\n");
return NULL; return NULL;
}
if (!reader_table[slot].atrlen) if (!reader_table[slot].atrlen)
{
if (DBG_READER)
log_debug ("leave: apdu_get_atr => NULL (no ATR)\n");
return NULL; return NULL;
}
buf = xtrymalloc (reader_table[slot].atrlen); buf = xtrymalloc (reader_table[slot].atrlen);
if (!buf) if (!buf)
{
if (DBG_READER)
log_debug ("leave: apdu_get_atr => NULL (out of core)\n");
return NULL; return NULL;
}
memcpy (buf, reader_table[slot].atr, reader_table[slot].atrlen); memcpy (buf, reader_table[slot].atr, reader_table[slot].atrlen);
*atrlen = reader_table[slot].atrlen; *atrlen = reader_table[slot].atrlen;
if (DBG_READER)
log_debug ("leave: apdu_get_atr => atrlen=%zu\n", *atrlen);
return buf; return buf;
} }
@ -3308,7 +3397,26 @@ int
apdu_get_status (int slot, int hang, apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed) 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_NOT_SUPPORTED = 0x6a81,
SW_FILE_NOT_FOUND = 0x6a82, SW_FILE_NOT_FOUND = 0x6a82,
SW_RECORD_NOT_FOUND = 0x6a83, 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_BAD_LC = 0x6a87, /* Lc does not match command or p1/p2. */
SW_REF_NOT_FOUND = 0x6a88, SW_REF_NOT_FOUND = 0x6a88,
SW_BAD_P0_P1 = 0x6b00, 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_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_reset (int slot);
int apdu_get_status (int slot, int hang, int apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed); 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 --*/ /*-- app.c --*/
void app_dump_state (void); void app_dump_state (void);
void application_notify_card_reset (int slot); 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, gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name,
app_t *r_app); app_t *r_app);
char *get_supported_applications (void); char *get_supported_applications (void);

View File

@ -198,11 +198,12 @@ application_notify_card_reset (int slot)
used to request a specific application and the connection has used to request a specific application and the connection has
already done a select_application. */ already done a select_application. */
gpg_error_t 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; app_t app;
(void)ctrl;
if (slot < 0 || slot >= DIM (lock_table)) if (slot < 0 || slot >= DIM (lock_table))
return gpg_error (GPG_ERR_INV_VALUE); return gpg_error (GPG_ERR_INV_VALUE);
@ -226,11 +227,14 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
app_t app = NULL; app_t app = NULL;
unsigned char *result = NULL; unsigned char *result = NULL;
size_t resultlen; size_t resultlen;
int want_undefined;
(void)ctrl; (void)ctrl;
*r_app = NULL; *r_app = NULL;
want_undefined = (name && !strcmp (name, "undefined"));
err = lock_reader (slot, ctrl); err = lock_reader (slot, ctrl);
if (err) if (err)
return err; return err;
@ -310,7 +314,10 @@ 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 /* Fixme: We should now first check whether a card is at all
present. */ present. */
/* Try to read the GDO file first to get a default serial number. */ /* 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)
{
err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL); err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
if (!err) if (!err)
err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL); err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
@ -350,6 +357,7 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
xfree (result); xfree (result);
result = NULL; result = NULL;
} }
}
/* For certain error codes, there is no need to try more. */ /* For certain error codes, there is no need to try more. */
if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT if (gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT
@ -357,6 +365,14 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
goto leave; goto leave;
/* Figure out the application to use. */ /* Figure out the application to use. */
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); err = gpg_error (GPG_ERR_NOT_FOUND);
if (err && is_app_allowed ("openpgp") if (err && is_app_allowed ("openpgp")
@ -366,11 +382,11 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
err = app_select_nks (app); err = app_select_nks (app);
if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15"))) if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
err = app_select_p15 (app); 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") if (err && is_app_allowed ("geldkarte")
&& (!name || !strcmp (name, "geldkarte"))) && (!name || !strcmp (name, "geldkarte")))
err = app_select_geldkarte (app); err = app_select_geldkarte (app);
if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
err = app_select_dinsig (app);
if (err && name) if (err && name)
err = gpg_error (GPG_ERR_NOT_SUPPORTED); err = gpg_error (GPG_ERR_NOT_SUPPORTED);
@ -404,8 +420,10 @@ get_supported_applications (void)
"openpgp", "openpgp",
"nks", "nks",
"p15", "p15",
"dinsig",
"geldkarte", "geldkarte",
"dinsig",
/* Note: "undefined" is not listed here because it needs special
treatment by the client. */
NULL NULL
}; };
int idx; int idx;

238
scd/atr.c
View File

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

View File

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

View File

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

View File

@ -74,6 +74,7 @@ struct
#define DBG_HASHING_VALUE 512 /* debug hashing operations */ #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_CARD_IO_VALUE 2048
#define DBG_READER_VALUE 4096 /* Trace reader related functions. */
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE) #define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE) #define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
@ -82,6 +83,7 @@ struct
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE) #define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE) #define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
#define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE) #define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE)
#define DBG_READER (opt.debug & DBG_READER_VALUE)
struct server_local_s; struct server_local_s;
struct app_ctx_s; struct app_ctx_s;
@ -97,9 +99,6 @@ struct server_control_s
/* Local data of the server; used only in command.c. */ /* Local data of the server; used only in command.c. */
struct server_local_s *server_local; 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 /* The application context used with this connection or NULL if none
associated. Note that this is shared with the other connections: associated. Note that this is shared with the other connections:
All connections accessing the same reader are using the same 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. 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 --append-dot append a dot to the first line of each commit message if
there is no other punctuation or blank at the end. 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; --since=DATE convert only the logs since DATE;
the default is to convert all log entries. the default is to convert all log entries.
--format=FMT set format string for commit subject and body; --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 $format_string = '%s%n%b%n';
my $amend_file; my $amend_file;
my $append_dot = 0; my $append_dot = 0;
my $tear_off = 0;
GetOptions GetOptions
( (
help => sub { usage 0 }, help => sub { usage 0 },
@ -183,6 +185,7 @@ sub parse_amend_file($)
'format=s' => \$format_string, 'format=s' => \$format_string,
'amend=s' => \$amend_file, 'amend=s' => \$amend_file,
'append-dot' => \$append_dot, 'append-dot' => \$append_dot,
'tear-off' => \$tear_off,
) or usage 1; ) or usage 1;
@ -281,6 +284,18 @@ sub parse_amend_file($)
@line = grep !/^Signed-off-by: .*>$/, @line; @line = grep !/^Signed-off-by: .*>$/, @line;
@line = grep !/^Co-authored-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. # Remove leading and trailing blank lines.
if (@line) if (@line)
{ {

View File

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

View File

@ -1,6 +1,6 @@
/* certchain.c - certificate chain validation /* certchain.c - certificate chain validation
* Copyright (C) 2001, 2002, 2003, 2004, 2005, * 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. * 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_NO_DIRMNGR - Do not do any dirmngr isvalid checks.
VALIDATE_FLAG_CHAIN_MODEL - Check according to chain model. VALIDATE_FLAG_CHAIN_MODEL - Check according to chain model.
VALIDATE_FLAG_STEED - Check according to the STEED model.
*/ */
static int static int
do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg, 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 We used to do this only later but changed it to call the
check right here so that we can access special flags check right here so that we can access special flags
associated with that specific root certificate. */ associated with that specific root certificate. */
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, istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, NULL,
rootca_flags); rootca_flags);
audit_log_cert (ctrl->audit, AUDIT_ROOT_TRUSTED, audit_log_cert (ctrl->audit, AUDIT_ROOT_TRUSTED,
subject_cert, istrusted_rc); subject_cert, istrusted_rc);
/* If the chain model extended attribute is used, make sure /* If the chain model extended attribute is used, make sure
that our chain model flag is set. */ 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; 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 /* Set the flag for qualified signatures. This flag is
deduced from a list of root certificates allowed for deduced from a list of root certificates allowed for
qualified signatures. */ qualified signatures. */
if (is_qualified == -1) if (is_qualified == -1 && !(flags & VALIDATE_FLAG_STEED))
{ {
gpg_error_t err; gpg_error_t err;
size_t buflen; 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 expired it does not make much sense to ask the user
whether we wants to trust the root certificate. We whether we wants to trust the root certificate. We
should do this only if the certificate under question 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 if ( !any_expired
&& !gpgsm_cert_has_well_known_private_key (subject_cert)
&& (!listmode || !already_asked_marktrusted (subject_cert)) && (!listmode || !already_asked_marktrusted (subject_cert))
&& ask_marktrusted (ctrl, subject_cert, listmode) ) && ask_marktrusted (ctrl, subject_cert, listmode) )
rc = 0; 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. */ /* Check for revocations etc. */
if ((flags & VALIDATE_FLAG_NO_DIRMNGR)) 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 if (opt.no_trusted_cert_crl_check || rootca_flags->relax)
; ;
else else
@ -1586,8 +1600,16 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
performance reasons. */ performance reasons. */
if (is_root) if (is_root)
{ {
istrusted_rc = gpgsm_agent_istrusted (ctrl, issuer_cert, NULL, if (gpgsm_cert_has_well_known_private_key (issuer_cert))
rootca_flags); {
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) if (!istrusted_rc && rootca_flags->relax)
{ {
/* Ignore the error due to the relax flag. */ /* 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. */ be fixed. */
if ((flags & VALIDATE_FLAG_NO_DIRMNGR)) if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
rc = 0; rc = 0;
else if ((flags & VALIDATE_FLAG_STEED))
rc = 0; /* Fixme: XXX */
else if (is_root && (opt.no_trusted_cert_crl_check else if (is_root && (opt.no_trusted_cert_crl_check
|| (!istrusted_rc && rootca_flags->relax))) || (!istrusted_rc && rootca_flags->relax)))
rc = 0; 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 capability of the certificate under question, store the result as
user data in all certificates of the chain. We do this even if the user data in all certificates of the chain. We do this even if the
validation itself failed. */ validation itself failed. */
if (is_qualified != -1) if (is_qualified != -1 && !(flags & VALIDATE_FLAG_STEED))
{ {
gpg_error_t err; gpg_error_t err;
chain_item_t ci; 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 do_validate_chain. This function is a wrapper to handle a root
certificate with the chain_model flag set. If RETFLAGS is not certificate with the chain_model flag set. If RETFLAGS is not
NULL, flags indicating now the verification was done are stored NULL, flags indicating now the verification was done are stored
there. The only defined flag for RETFLAGS is there. The only defined vits for RETFLAGS are
VALIDATE_FLAG_CHAIN_MODEL. VALIDATE_FLAG_CHAIN_MODEL and VALIDATE_FLAG_STEED.
If you are verifying a signature you should set CHECKTIME to the If you are verifying a signature you should set CHECKTIME to the
creation time of the signature. If your are verifying a 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) if (!retflags)
retflags = &dummy_retflags; retflags = &dummy_retflags;
/* If the session requested a certain validation mode make sure the
corresponding flags are set. */
if (ctrl->validation_model == 1) if (ctrl->validation_model == 1)
flags |= VALIDATE_FLAG_CHAIN_MODEL; 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); *retflags = (flags & VALIDATE_FLAG_CHAIN_MODEL);
memset (&rootca_flags, 0, sizeof rootca_flags); memset (&rootca_flags, 0, sizeof rootca_flags);
rc = do_validate_chain (ctrl, cert, checktime, rc = do_validate_chain (ctrl, cert, checktime,
r_exptime, listmode, listfp, flags, r_exptime, listmode, listfp, flags,
&rootca_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) && !(flags & VALIDATE_FLAG_CHAIN_MODEL)
&& (rootca_flags.valid && rootca_flags.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) if (opt.verbose)
do_list (0, listmode, listfp, _("validation model used: %s"), do_list (0, listmode, listfp, _("validation model used: %s"),
(*retflags & VALIDATE_FLAG_STEED)?
"steed" :
(*retflags & VALIDATE_FLAG_CHAIN_MODEL)? (*retflags & VALIDATE_FLAG_CHAIN_MODEL)?
_("chain"):_("shell")); _("chain"):_("shell"));

View File

@ -1,6 +1,6 @@
/* certlist.c - build list of certificates /* certlist.c - build list of certificates
* Copyright (C) 2001, 2003, 2004, 2005, 2007, * Copyright (C) 2001, 2003, 2004, 2005, 2007,
* 2008 Free Software Foundation, Inc. * 2008, 2011 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * 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 static int
same_subject_issuer (const char *subject, const char *issuer, ksba_cert_t cert) same_subject_issuer (const char *subject, const char *issuer, ksba_cert_t cert)
{ {

View File

@ -33,6 +33,22 @@
%commit %commit
%echo done %echo done
EOF 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, pNOTBEFORE,
pNOTAFTER, pNOTAFTER,
pSIGNINGKEY, pSIGNINGKEY,
pHASHALGO pHASHALGO,
pAUTHKEYID,
pSUBJKEYID,
pEXTENSION
}; };
struct para_data_s 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_keyUsage[] = "2.5.29.15";
static const char oidstr_basicConstraints[] = "2.5.29.19"; static const char oidstr_basicConstraints[] = "2.5.29.19";
static const char oidstr_standaloneCertificate[] = "1.3.6.1.4.1.11591.2.2.1"; 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") ) else if ( !ascii_strcasecmp (p, "sign") )
use |= GCRY_PK_USAGE_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; use |= GCRY_PK_USAGE_ENCR;
else if ( !ascii_strcasecmp (p, "cert") )
use |= GCRY_PK_USAGE_CERT;
else else
{ {
log_error ("line %d: invalid usage list\n", r->lnr); 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 }, { "Not-After", pNOTAFTER },
{ "Signing-Key", pSIGNINGKEY }, { "Signing-Key", pSIGNINGKEY },
{ "Hash-Algo", pHASHALGO }, { "Hash-Algo", pHASHALGO },
{ "Authority-Key-Id", pAUTHKEYID },
{ "Subject-Key-Id", pSUBJKEYID },
{ "Extension", pEXTENSION, 1 },
{ NULL, 0 } { NULL, 0 }
}; };
char line[1024], *p; 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. */ /* Create or retrieve the public key. */
if (cardkeyid) /* Take the key from the current smart card. */ 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, err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
"\x03\x02\x04\x30", 4); "\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 else
err = 0; /* Both or none given: don't request one. */ err = 0; /* Both or none given: don't request one. */
if (err) if (err)
@ -889,7 +992,7 @@ create_request (ctrl_t ctrl,
*p++ = '0'; *p++ = '0';
strcpy (p, string); strcpy (p, string);
for (p=hexbuf, len=0; p[0] && p[1]; p += 2) 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. */ /* Now build the S-expression. */
snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len); snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
buf = p = xtrymalloc (1 + strlen (numbuf) + len + 1 + 1); buf = p = xtrymalloc (1 + strlen (numbuf) + len + 1 + 1);
@ -1009,6 +1112,139 @@ create_request (ctrl_t ctrl,
goto leave; 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 else
sigkey = public; sigkey = public;

View File

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

View File

@ -195,7 +195,9 @@ struct server_control_s
certificates up the chain (0 = none, 1 = only certificates up the chain (0 = none, 1 = only
signer) */ signer) */
int use_ocsp; /* Set to true if OCSP should be used. */ 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. */ /* Flags used with gpgsm_validate_chain. */
#define VALIDATE_FLAG_NO_DIRMNGR 1 #define VALIDATE_FLAG_NO_DIRMNGR 1
#define VALIDATE_FLAG_CHAIN_MODEL 2 #define VALIDATE_FLAG_CHAIN_MODEL 2
#define VALIDATE_FLAG_STEED 4
int gpgsm_walk_cert_chain (ctrl_t ctrl, int gpgsm_walk_cert_chain (ctrl_t ctrl,
ksba_cert_t start, ksba_cert_t *r_next); 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_decrypt_p (ksba_cert_t cert);
int gpgsm_cert_use_cert_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_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_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, int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert,
certlist_t *listaddr, int is_encrypt_to); certlist_t *listaddr, int is_encrypt_to);

View File

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

View File

@ -277,7 +277,7 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
else if (!strcmp (key, "validation-model")) else if (!strcmp (key, "validation-model"))
{ {
int i = gpgsm_parse_validation_model (value); int i = gpgsm_parse_validation_model (value);
if ( i >= 0 && i <= 1 ) if ( i >= 0 && i <= 2 )
ctrl->validation_model = i; ctrl->validation_model = i;
else else
err = gpg_error (GPG_ERR_ASS_PARAMETER); 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, gpgsm_status (ctrl, STATUS_TRUST_FULLY,
(verifyflags & VALIDATE_FLAG_STEED)?
"0 steed":
(verifyflags & VALIDATE_FLAG_CHAIN_MODEL)? (verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
"0 chain": "0 shell"); "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.txt text-2.txt text-3.txt \
text-1.osig.pem text-1.dsig.pem text-1.osig-bad.pem \ text-1.osig.pem text-1.dsig.pem text-1.osig-bad.pem \
text-2.osig.pem text-2.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/32100C27173EF6E9C4E9A25D3D69F86D37A4F939.key \
samplekeys/cert_g10code_pete1.pem \ samplekeys/cert_g10code_pete1.pem \
samplekeys/cert_g10code_test1.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

@ -17,5 +17,8 @@ gte.pem GTE CyberTrust Global Root
cert-with-117-akas.pem A certificate with 117 subjectAltNames. 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 commit log, and generate a top-level ChangeLog file from logs at
"make dist". See doc/HACKING for details. "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> 2011-08-26 Werner Koch <wk@g10code.com>
* gpgconf-comp.c (gc_component): Mark for translation. Suggested * gpgconf-comp.c (gc_component): Mark for translation. Suggested

View File

@ -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. */ /* gpg-connect-agent's entry point. */
int int
main (int argc, char **argv) main (int argc, char **argv)
@ -1822,9 +1838,7 @@ main (int argc, char **argv)
if (*line == '#' || !*line) if (*line == '#' || !*line)
continue; /* Don't expect a response for a comment line. */ continue; /* Don't expect a response for a comment line. */
rc = read_and_print_response (ctx, (!ascii_strncasecmp (line, "HELP", 4) rc = read_and_print_response (ctx, help_cmd_p (line), &cmderr);
&& (spacep (line+4) || !line[4])),
&cmderr);
if (rc) if (rc)
log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) ); log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
if ((rc || cmderr) && script_fp) if ((rc || cmderr) && script_fp)