aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcus Brinkmann <[email protected]>2012-01-03 17:13:19 +0000
committerMarcus Brinkmann <[email protected]>2012-01-03 17:13:19 +0000
commit0868997e186cd847663668f9d7a29806a12da2d2 (patch)
tree73645f778a2d16213723121a76d2b38ca90edfcc
parentAdd lost ChangeLog entry. (diff)
parentSilence gcc warning. (diff)
downloadgnupg-npth.tar.gz
gnupg-npth.zip
Merge branch 'master' into npthnpth
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
-rw-r--r--ChangeLog-201115
-rw-r--r--Makefile.am1
-rw-r--r--NEWS19
-rw-r--r--README.maint2
-rw-r--r--agent/ChangeLog-201111
-rw-r--r--agent/agent.h83
-rw-r--r--agent/call-pinentry.c3
-rw-r--r--agent/call-scd.c42
-rw-r--r--agent/command.c107
-rw-r--r--agent/gpg-agent.c26
-rw-r--r--common/asshelp.c13
-rw-r--r--common/asshelp.h1
-rw-r--r--common/dotlock.c6
-rw-r--r--common/estream.c140
-rw-r--r--common/estream.h4
-rw-r--r--configure.ac2
-rw-r--r--dirmngr/ChangeLog-201115
-rw-r--r--dirmngr/dirmngr.c2
-rw-r--r--doc/DETAILS6
-rw-r--r--doc/HACKING13
-rw-r--r--doc/com-certs.pem18
-rw-r--r--doc/faq.org44
-rw-r--r--doc/gpgsm.texi15
-rw-r--r--doc/scdaemon.texi58
-rw-r--r--g10/photoid.c5
-rw-r--r--g13/g13.c3
-rw-r--r--keyserver/gpgkeys_hkp.c20
-rw-r--r--po/de.po32
-rw-r--r--scd/ChangeLog-20114
-rw-r--r--scd/Makefile.am1
-rw-r--r--scd/apdu.c252
-rw-r--r--scd/apdu.h4
-rw-r--r--scd/app-common.h3
-rw-r--r--scd/app.c104
-rw-r--r--scd/atr.c252
-rw-r--r--scd/atr.h2
-rw-r--r--scd/command.c290
-rw-r--r--scd/scdaemon.c9
-rw-r--r--scd/scdaemon.h7
-rwxr-xr-xscripts/gitlog-to-changelog15
-rw-r--r--sm/call-dirmngr.c2
-rw-r--r--sm/certchain.c61
-rw-r--r--sm/certlist.c17
-rw-r--r--sm/certreqgen.c242
-rw-r--r--sm/gpgsm.c2
-rw-r--r--sm/gpgsm.h7
-rw-r--r--sm/keylist.c29
-rw-r--r--sm/server.c2
-rw-r--r--sm/verify.c2
-rw-r--r--tests/Makefile.am2
-rw-r--r--tests/samplekeys/68A638998DFABAC510EA645CE34F9686B2EDF7EA.key10
-rw-r--r--tests/samplekeys/README7
-rw-r--r--tests/samplekeys/steed-self-signing-nonthority.pem54
-rw-r--r--tools/ChangeLog-20114
-rw-r--r--tools/gpg-connect-agent.c156
55 files changed, 1541 insertions, 705 deletions
diff --git a/ChangeLog-2011 b/ChangeLog-2011
index 82f45a8cf..cfba8f473 100644
--- a/ChangeLog-2011
+++ b/ChangeLog-2011
@@ -14,21 +14,6 @@
accept --with-libgpg-error-prefix as well as --with-gpg-error-prefix
* m4/gpg-error.m4: Update from git master.
-2011-10-13 Marcus Brinkmann <[email protected]>
-
- * configure.ac: Fix npth version check.
- * m4/npth.m4: Fix version check.
-
-2011-09-26 Marcus Brinkmann <[email protected]>
-
- * 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 <[email protected]>
* configure.ac: Remove check for gcry_kdf_derive.
diff --git a/Makefile.am b/Makefile.am
index 292748abc..49ec3fc78 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -116,6 +116,7 @@ gen-ChangeLog:
if test -d $(top_srcdir)/.git; then \
(cd $(top_srcdir) && \
./scripts/gitlog-to-changelog \
+ --append-dot --tear-off \
--amend=scripts/git-log-fix \
--since=$(gen_start_date) ) > $(distdir)/cl-t; \
cat $(top_srcdir)/scripts/git-log-footer >> $(distdir)/cl-t; \
diff --git a/NEWS b/NEWS
index 08d6bfe6b..65297dd37 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,8 @@
-Noteworthy changes in version 2.1.0beta3
+Noteworthy changes in version 2.1.0beta4 (unreleased)
+-----------------------------------------------------
+
+
+Noteworthy changes in version 2.1.0beta3 (2011-12-20)
-----------------------------------------------------
* Fixed regression in GPG's secret key export function.
@@ -9,6 +13,19 @@ Noteworthy changes in version 2.1.0beta3
* The Assuan commands KILLAGENT and KILLSCD are working again.
+ * SCdaemon does not anymore block after changing a card (regression
+ fix).
+
+ * gpg-connect-agent does now proberly display the help output for
+ "SCD HELP" commands.
+
+ * Preliminary support for the GPGSM validation model "steed".
+
+ * Improved certificate creation in GPGSM.
+
+ * New option for GPG_AGENT to select a passphrase mode. The loopback
+ mode may be used to bypass Pinentry.
+
Noteworthy changes in version 2.1.0beta2 (2011-03-08)
-----------------------------------------------------
diff --git a/README.maint b/README.maint
index f390afc97..bdcdbf9c0 100644
--- a/README.maint
+++ b/README.maint
@@ -27,8 +27,8 @@ Release process:
* Run "make -C po update-po".
* Write NEWS entries and set the release date in NEWS.
* In configure.ac set "my_issvn" to "no".
- * Put a "Release <version>" line into the top level ChangeLog.
* Commit all changes to GIT and push them.
+ * Do a commit with a "Release <version>" line.
* Run "./autogen.sh --force"
(--force is required for the svn magic in configure.ac and a good
idea in any case)
diff --git a/agent/ChangeLog-2011 b/agent/ChangeLog-2011
index c074d1b65..f56be1f44 100644
--- a/agent/ChangeLog-2011
+++ b/agent/ChangeLog-2011
@@ -12,17 +12,6 @@
(ssh_handler_request_identities): Do not call card_key_available
if the scdaemon is disabled.
-2011-10-13 Marcus Brinkmann <[email protected]>
-
- * 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 <[email protected]>
* genkey.c (agent_ask_new_passphrase): Allow for an empty passphrase
diff --git a/agent/agent.h b/agent/agent.h
index b323718fc..4f4e477a6 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -73,17 +73,20 @@ struct
/* True if we handle sigusr2. */
int sigusr2_enabled;
- /* Environment setting gathered at program start or changed using the
+ /* Environment settings gathered at program start or changed using the
Assuan command UPDATESTARTUPTTY. */
session_env_t startup_env;
char *startup_lc_ctype;
char *startup_lc_messages;
- const char *pinentry_program; /* Filename of the program to start as
- pinentry. */
- const char *scdaemon_program; /* Filename of the program to handle
- smartcard tasks. */
+ /* Filename of the program to start as pinentry. */
+ const char *pinentry_program;
+
+ /* Filename of the program to handle smartcard tasks. */
+ const char *scdaemon_program;
+
int disable_scdaemon; /* Never use the SCdaemon. */
+
int no_grab; /* Don't let the pinentry grab the keyboard */
/* The name of the file pinentry shall tocuh before exiting. If
@@ -98,31 +101,51 @@ struct
/* Flag disallowing bypassing of the warning. */
int enforce_passphrase_constraints;
+
/* The require minmum length of a passphrase. */
unsigned int min_passphrase_len;
+
/* The minimum number of non-alpha characters in a passphrase. */
unsigned int min_passphrase_nonalpha;
+
/* File name with a patternfile or NULL if not enabled. */
const char *check_passphrase_pattern;
+
/* If not 0 the user is asked to change his passphrase after these
number of days. */
unsigned int max_passphrase_days;
+
/* If set, a passphrase history will be written and checked at each
passphrase change. */
int enable_passhrase_history;
int running_detached; /* We are running detached from the tty. */
+ /* If this global option is true, the passphrase cache is ignored
+ for signing operations. */
int ignore_cache_for_signing;
+
+ /* If this global option is true, the user is allowed to
+ interactively mark certificate in trustlist.txt as trusted. */
int allow_mark_trusted;
+
+ /* If this global option is true, the Assuan command
+ PRESET_PASSPHRASE is allowed. */
int allow_preset_passphrase;
+
+ /* If this global option is true, the Assuan option
+ pinentry-mode=loopback is allowed. */
int allow_loopback_pinentry;
+
int keep_tty; /* Don't switch the TTY (for pinentry) on request */
int keep_display; /* Don't switch the DISPLAY (for pinentry) on request */
- int ssh_support; /* Enable ssh-agent emulation. */
+
+ /* This global option enables the ssh-agent subsystem. */
+ int ssh_support;
} opt;
+/* Bit values for the --debug option. */
#define DBG_COMMAND_VALUE 1 /* debug commands i/o */
#define DBG_MPI_VALUE 2 /* debug mpi details */
#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
@@ -130,8 +153,9 @@ struct
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_ASSUAN_VALUE 1024
+#define DBG_ASSUAN_VALUE 1024 /* Enable Assuan debugging. */
+/* Test macros for the debug option. */
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
@@ -139,14 +163,18 @@ struct
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
+/* Forward reference for local definitions in command.c. */
struct server_local_s;
+
+/* Forward reference for local definitions in call-scd.c. */
struct scd_local_s;
/* Collection of data per session (aka connection). */
struct server_control_s
{
/* Private data used to fire up the connection thread. We use this
- structure do avoid an extra allocation for just a few bytes. */
+ structure do avoid an extra allocation for only a few bytes while
+ spawning a new connection thread. */
struct {
gnupg_fd_t fd;
} thread_startup;
@@ -157,6 +185,7 @@ struct server_control_s
/* Private data of the SCdaemon (call-scd.c). */
struct scd_local_s *scd_local;
+ /* Environment settings for the connection. */
session_env_t session_env;
char *lc_ctype;
char *lc_messages;
@@ -177,37 +206,47 @@ struct server_control_s
unsigned char keygrip[20];
int have_keygrip;
- int use_auth_call; /* Hack to send the PKAUTH command instead of the
- PKSIGN command to the scdaemon. */
- int in_passwd; /* Hack to inhibit enforced passphrase change
- during an explicit passwd command. */
+ /* A flag to enable a hack to send the PKAUTH command instead of the
+ PKSIGN command to the scdaemon. */
+ int use_auth_call;
+
+ /* A flag to inhibit enforced passphrase change during an explicit
+ passwd command. */
+ int in_passwd;
- unsigned long s2k_count; /* Other than the calibrated count. */
+ /* The current S2K which might be different from the calibrated
+ count. */
+ unsigned long s2k_count;
};
+/* Information pertaining to pinentry requests. */
struct pin_entry_info_s
{
int min_digits; /* min. number of digits required or 0 for freeform entry */
int max_digits; /* max. number of allowed digits allowed*/
- int max_tries;
- int failed_tries;
+ int max_tries; /* max. number of allowed tries. */
+ int failed_tries; /* Number of tries so far failed. */
int with_qualitybar; /* Set if the quality bar should be displayed. */
int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
void *check_cb_arg; /* optional argument which might be of use in the CB */
const char *cb_errtext; /* used by the cb to display a specific error */
- size_t max_length; /* allocated length of the buffer */
- char pin[1];
+ size_t max_length; /* Allocated length of the buffer PIN. */
+ char pin[1]; /* The buffer to hold the PIN or passphrase.
+ It's actual allocated length is given by
+ MAX_LENGTH (above). */
};
+/* Types of the private keys. */
enum
{
- PRIVATE_KEY_UNKNOWN = 0,
- PRIVATE_KEY_CLEAR = 1,
- PRIVATE_KEY_PROTECTED = 2,
- PRIVATE_KEY_SHADOWED = 3,
- PROTECTED_SHARED_SECRET = 4
+ PRIVATE_KEY_UNKNOWN = 0, /* Type of key is not known. */
+ PRIVATE_KEY_CLEAR = 1, /* The key is not protected. */
+ PRIVATE_KEY_PROTECTED = 2, /* The key is protected. */
+ PRIVATE_KEY_SHADOWED = 3, /* The key is a stub for a smartcard
+ based key. */
+ PROTECTED_SHARED_SECRET = 4 /* RFU. */
};
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index f5dc1aaa9..34ab3840e 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -1261,8 +1261,7 @@ agent_popup_message_stop (ctrl_t ctrl)
assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
}
else if (pid > 0)
- kill (pid, SIGKILL); /* Need to use SIGKILL due to bad
- interaction of SIGINT with Pth. */
+ kill (pid, SIGINT);
#endif
/* Now wait for the thread to terminate. */
diff --git a/agent/call-scd.c b/agent/call-scd.c
index f61858e5f..8a6c8ba68 100644
--- a/agent/call-scd.c
+++ b/agent/call-scd.c
@@ -1,5 +1,6 @@
/* call-scd.c - fork of the scdaemon to do SC operations
- * Copyright (C) 2001, 2002, 2005, 2007, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2005, 2007, 2010,
+ * 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -44,15 +45,6 @@
#define MAX_OPEN_FDS 20
#endif
-/* This Assuan flag is only available since libassuan 2.0.2. Because
- comments lines are comments anyway we can use a replacement which
- might not do anything. assuan_{g,s}et_flag don't return an error
- thus there won't be any ABI problem. */
-#ifndef ASSUAN_CONVEY_COMMENTS
-#define ASSUAN_CONVEY_COMMENTS 4
-#endif
-
-
/* Definition of module local data of the CTRL structure. */
struct scd_local_s
{
@@ -1115,16 +1107,28 @@ pass_status_thru (void *opaque, const char *line)
char keyword[200];
int i;
- for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
- keyword[i] = *line;
- keyword[i] = 0;
- /* truncate any remaining keyword stuff. */
- for (; *line && !spacep (line); line++)
- ;
- while (spacep (line))
- line++;
+ if (line[0] == '#' && (!line[1] || spacep (line+1)))
+ {
+ /* We are called in convey comments mode. Now, if we see a
+ comment marker as keyword we forward the line verbatim to the
+ the caller. This way the comment lines from scdaemon won't
+ appear as status lines with keyword '#'. */
+ assuan_write_line (ctx, line);
+ }
+ else
+ {
+ for (i=0; *line && !spacep (line) && i < DIM(keyword)-1; line++, i++)
+ keyword[i] = *line;
+ keyword[i] = 0;
- assuan_write_status (ctx, keyword, line);
+ /* Truncate any remaining keyword stuff. */
+ for (; *line && !spacep (line); line++)
+ ;
+ while (spacep (line))
+ line++;
+
+ assuan_write_status (ctx, keyword, line);
+ }
return 0;
}
diff --git a/agent/command.c b/agent/command.c
index f310a980c..ad86a3575 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -50,31 +50,57 @@
/* The size of the import/export KEK key (in bytes). */
#define KEYWRAP_KEYSIZE (128/8)
+/* A shortcut to call assuan_set_error using an gpg_err_code_t and a
+ text string. */
#define set_error(e,t) assuan_set_error (ctx, gpg_error (e), (t))
-
+/* Check that the maximum digest length we support has at least the
+ length of the keygrip. */
#if MAX_DIGEST_LEN < 20
#error MAX_DIGEST_LEN shorter than keygrip
#endif
-/* Data used to associate an Assuan context with local server data */
+/* Data used to associate an Assuan context with local server data.
+ This is this modules local part of the server_control_s struct. */
struct server_local_s
{
+ /* Our Assuan context. */
assuan_context_t assuan_ctx;
- int message_fd;
+
+ /* If this flag is true, the passphrase cache is used for signing
+ operations. It defaults to true but may be set on a per
+ connection base. The global option opt.ignore_cache_for_signing
+ takes precedence over this flag. */
int use_cache_for_signing;
- char *keydesc; /* Allocated description for the next key
- operation. */
- int pause_io_logging; /* Used to suppress I/O logging during a command */
- int stopme; /* If set to true the agent will be terminated after
- the end of this session. */
- int allow_pinentry_notify; /* Set if pinentry notifications should
- be done. */
- void *import_key; /* Malloced KEK for the import_key command. */
- void *export_key; /* Malloced KEK for the export_key command. */
- int allow_fully_canceled; /* Client is aware of GPG_ERR_FULLY_CANCELED. */
- char *last_cache_nonce; /* Last CACHE_NOCNE sent as status (malloced). */
- char *last_passwd_nonce; /* Last PASSWD_NOCNE sent as status (malloced). */
+
+ /* An allocated description for the next key operation. This is
+ used if a pinnetry needs to be popped up. */
+ char *keydesc;
+
+ /* Flags to suppress I/O logging during a command. */
+ int pause_io_logging;
+
+ /* If this flags is set to true the agent will be terminated after
+ the end of the current session. */
+ int stopme;
+
+ /* Flag indicating whether pinentry notifications shall be done. */
+ int allow_pinentry_notify;
+
+ /* Malloced KEK (Key-Encryption-Key) for the import_key command. */
+ void *import_key;
+
+ /* Malloced KEK for the export_key command. */
+ void *export_key;
+
+ /* Client is aware of the error code GPG_ERR_FULLY_CANCELED. */
+ int allow_fully_canceled;
+
+ /* Last CACHE_NONCE sent as status (malloced). */
+ char *last_cache_nonce;
+
+ /* Last PASSWD_NONCE sent as status (malloced). */
+ char *last_passwd_nonce;
};
@@ -156,6 +182,8 @@ write_and_clear_outbuf (assuan_context_t ctx, membuf_t *mb)
}
+/* Clear the nonces used to enable the passphrase cache for certain
+ multi-command command sequences. */
static void
clear_nonce_cache (ctrl_t ctrl)
{
@@ -176,6 +204,9 @@ clear_nonce_cache (ctrl_t ctrl)
}
+/* This function is called by Libassuan whenever thee client sends a
+ reset. It has been registered similar to the other Assuan
+ commands. */
static gpg_error_t
reset_notify (assuan_context_t ctx, char *line)
{
@@ -196,8 +227,13 @@ reset_notify (assuan_context_t ctx, char *line)
}
-/* Skip over options.
- Blanks after the options are also removed. */
+/* Skip over options in LINE.
+
+ Blanks after the options are also removed. Options are indicated
+ by two leading dashes followed by a string consisting of non-space
+ characters. The special option "--" indicates an explicit end of
+ options; all what follows will not be considered an option. The
+ first no-option string also indicates the end of option parsing. */
static char *
skip_options (const char *line)
{
@@ -213,7 +249,11 @@ skip_options (const char *line)
return (char*)line;
}
-/* Check whether the option NAME appears in LINE */
+
+/* Check whether the option NAME appears in LINE. An example for a
+ line with options is:
+ --algo=42 --data foo bar
+ This function would then only return true if NAME is "data". */
static int
has_option (const char *line, const char *name)
{
@@ -226,6 +266,7 @@ has_option (const char *line, const char *name)
return (s && (s == line || spacep (s-1)) && (!s[n] || spacep (s+n)));
}
+
/* Same as has_option but does only test for the name of the option
and ignores an argument, i.e. with NAME being "--hash" it would
return true for "--hash" as well as for "--hash=foo". */
@@ -242,8 +283,9 @@ has_option_name (const char *line, const char *name)
&& (!s[n] || spacep (s+n) || s[n] == '='));
}
+
/* Return a pointer to the argument of the option with NAME. If such
- an option is not given, it returns NULL. */
+ an option is not given, NULL is retruned. */
static char *
option_value (const char *line, const char *name)
{
@@ -265,7 +307,7 @@ option_value (const char *line, const char *name)
}
-/* Replace all '+' by a blank. */
+/* Replace all '+' by a blank in the string S. */
static void
plus_to_blank (char *s)
{
@@ -296,8 +338,9 @@ parse_hexstring (assuan_context_t ctx, const char *string, size_t *len)
return 0;
}
+
/* Parse the keygrip in STRING into the provided buffer BUF. BUF must
- provide space for 20 bytes. BUF is not changed if the function
+ provide space for 20 bytes. BUF is not changed if the function
returns an error. */
static int
parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
@@ -319,7 +362,11 @@ parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
}
-/* Write an assuan status line. */
+/* Write an Assuan status line. KEYWORD is the first item on the
+ status line. The following arguments are all separated by a space
+ in the output. The last argument must be a NULL. Linefeeds and
+ carriage returns characters (which are not allowed in an Assuan
+ status line) are silently quoted in C-style. */
gpg_error_t
agent_write_status (ctrl_t ctrl, const char *keyword, ...)
{
@@ -463,6 +510,7 @@ bump_key_eventcounter (void)
eventcounter.any++;
}
+
/* This function should be called for all card reader status
changes. This function is assured not to do any context
switches. */
@@ -1069,6 +1117,8 @@ do_one_keyinfo (ctrl_t ctrl, const unsigned char *grip, assuan_context_t ctx,
}
+/* Entry int for the command KEYINFO. This function handles the
+ command option processing. For details see hlp_keyinfo above. */
static gpg_error_t
cmd_keyinfo (assuan_context_t ctx, char *line)
{
@@ -1140,6 +1190,7 @@ cmd_keyinfo (assuan_context_t ctx, char *line)
+/* Helper for cmd_get_passphrase. */
static int
send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
{
@@ -2259,12 +2310,8 @@ cmd_killagent (assuan_context_t ctx, char *line)
return set_error (GPG_ERR_NOT_SUPPORTED, "no --use-standard-socket");
ctrl->server_local->stopme = 1;
-#ifdef ASSUAN_FORCE_CLOSE
assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
return 0;
-#else
- return gpg_error (GPG_ERR_EOF);
-#endif
}
@@ -2415,6 +2462,8 @@ cmd_getinfo (assuan_context_t ctx, char *line)
+/* This function is called by Libassuan to parse the OPTION command.
+ It has been registered similar to the other Assuan commands. */
static gpg_error_t
option_handler (assuan_context_t ctx, const char *key, const char *value)
{
@@ -2574,7 +2623,8 @@ command_has_option (const char *cmd, const char *cmdopt)
}
-/* Tell the assuan library about our commands */
+/* Tell Libassuan about our commands. Also register the other Assuan
+ handlers. */
static int
register_commands (assuan_context_t ctx)
{
@@ -2685,7 +2735,6 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
assuan_set_pointer (ctx, ctrl);
ctrl->server_local = xcalloc (1, sizeof *ctrl->server_local);
ctrl->server_local->assuan_ctx = ctx;
- ctrl->server_local->message_fd = -1;
ctrl->server_local->use_cache_for_signing = 1;
ctrl->digest.raw_value = 0;
@@ -2733,6 +2782,8 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
}
+/* Helper for the pinentry loopback mode. It merely passes the
+ parameters on to the client. */
gpg_error_t
pinentry_loopback(ctrl_t ctrl, const char *keyword,
unsigned char **buffer, size_t *size,
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 53d25402a..f741f052c 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -299,6 +299,9 @@ ASSUAN_SYSTEM_NPTH_IMPL;
Functions.
*/
+/* Allocate a string describing a library version by calling a GETFNC.
+ This function is expected to be called only once. GETFNC is
+ expected to have a semantic like gcry_check_version (). */
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))
{
@@ -316,7 +319,9 @@ make_libversion (const char *libname, const char *(*getfnc)(const char*))
return result;
}
-
+/* Return strings describing this program. The case values are
+ described in common/argparse.c:strusage. The values here override
+ the default values given by strusage. */
static const char *
my_strusage (int level)
{
@@ -438,6 +443,9 @@ remove_socket (char *name)
}
}
+
+/* Cleanup code for this program. This is either called has an atexit
+ handler or directly. */
static void
cleanup (void)
{
@@ -1150,11 +1158,11 @@ main (int argc, char **argv )
if (csh_style)
{
*strchr (infostr, '=') = ' ';
- es_printf ("setenv %s\n", infostr);
+ es_printf ("setenv %s;\n", infostr);
if (opt.ssh_support)
{
*strchr (infostr_ssh_sock, '=') = ' ';
- es_printf ("setenv %s\n", infostr_ssh_sock);
+ es_printf ("setenv %s;\n", infostr_ssh_sock);
}
}
else
@@ -1238,6 +1246,8 @@ main (int argc, char **argv )
}
+/* Exit entry point. This function should be called instead of a
+ plain exit. */
void
agent_exit (int rc)
{
@@ -1264,6 +1274,11 @@ agent_exit (int rc)
}
+/* Each thread has its own local variables conveyed by a control
+ structure usually identified by an argument named CTRL. This
+ function is called immediately after allocating the control
+ structure. Its purpose is to setup the default values for that
+ structure. */
static void
agent_init_default_ctrl (ctrl_t ctrl)
{
@@ -1289,6 +1304,8 @@ agent_init_default_ctrl (ctrl_t ctrl)
}
+/* Release all resources allocated by default in the control
+ structure. This is the counterpart to agent_init_default_ctrl. */
static void
agent_deinit_default_ctrl (ctrl_t ctrl)
{
@@ -1690,6 +1707,7 @@ agent_sighup_action (void)
}
+/* A helper function to handle SIGUSR2. */
static void
agent_sigusr2_action (void)
{
@@ -1700,6 +1718,8 @@ agent_sigusr2_action (void)
}
+/* The signal handler for this program. It is expected to be run in
+ its own trhead and not in the context of a signal handler. */
static void
handle_signal (int signo)
{
diff --git a/common/asshelp.c b/common/asshelp.c
index c5d8bdf84..7ac6ff0cc 100644
--- a/common/asshelp.c
+++ b/common/asshelp.c
@@ -97,6 +97,19 @@ setup_libassuan_logging (unsigned int *debug_var_address)
assuan_set_log_cb (my_libassuan_log_handler, debug_var_address);
}
+/* Change the Libassuan log categories to those given by NEWCATS.
+ NEWCATS is 0 the default category of ASSUAN_LOG_CONTROL is
+ selected. Note, that setup_libassuan_logging overrides the values
+ given here. */
+void
+set_libassuan_log_cats (unsigned int newcats)
+{
+ if (newcats)
+ log_cats = newcats;
+ else /* Default to log the control channel. */
+ log_cats = (1 << (ASSUAN_LOG_CONTROL - 1));
+}
+
static gpg_error_t
diff --git a/common/asshelp.h b/common/asshelp.h
index 0eb6553f9..728c03949 100644
--- a/common/asshelp.h
+++ b/common/asshelp.h
@@ -26,6 +26,7 @@
#include "session-env.h"
void setup_libassuan_logging (unsigned int *debug_var_address);
+void set_libassuan_log_cats (unsigned int newcats);
gpg_error_t
diff --git a/common/dotlock.c b/common/dotlock.c
index b4734b99f..5e17e64c6 100644
--- a/common/dotlock.c
+++ b/common/dotlock.c
@@ -583,7 +583,8 @@ use_hardlinks_p (const char *tname)
strcpy (lname, tname);
strcat (lname, "x");
- link (tname, lname);
+ /* We ignore the return value of link() because it is unreliable. */
+ (void) link (tname, lname);
if (stat (tname, &sb))
res = -1; /* Ooops. */
@@ -1004,7 +1005,8 @@ dotlock_take_unix (dotlock_t h, long timeout)
{
struct stat sb;
- link (h->tname, h->lockname);
+ /* We ignore the return value of link() because it is unreliable. */
+ (void) link (h->tname, h->lockname);
if (stat (h->tname, &sb))
{
diff --git a/common/estream.c b/common/estream.c
index 383210dff..32602a0f7 100644
--- a/common/estream.c
+++ b/common/estream.c
@@ -217,6 +217,17 @@ struct notify_list_s
};
typedef struct notify_list_s *notify_list_t;
+
+/* A private cookie function to implement an internal IOCTL
+ service. */
+typedef int (*cookie_ioctl_function_t) (void *cookie, int cmd,
+ void *ptr, size_t *len);
+/* IOCTL commands for the private cookie function. */
+#define COOKIE_IOCTL_SNATCH_BUFFER 1
+
+
+
+
/* An internal stream object. */
struct estream_internal
{
@@ -231,6 +242,7 @@ struct estream_internal
es_cookie_read_function_t func_read;
es_cookie_write_function_t func_write;
es_cookie_seek_function_t func_seek;
+ cookie_ioctl_function_t func_ioctl;
es_cookie_close_function_t func_close;
int strategy;
es_syshd_t syshd; /* A copy of the sytem handle. */
@@ -771,6 +783,33 @@ es_func_mem_seek (void *cookie, off_t *offset, int whence)
return 0;
}
+/* An IOCTL function for memory objects. */
+static int
+es_func_mem_ioctl (void *cookie, int cmd, void *ptr, size_t *len)
+{
+ estream_cookie_mem_t mem_cookie = cookie;
+ int ret;
+
+ if (cmd == COOKIE_IOCTL_SNATCH_BUFFER)
+ {
+ /* Return the internal buffer of the stream to the caller and
+ invalidate it for the stream. */
+ *(void**)ptr = mem_cookie->memory;
+ *len = mem_cookie->offset;
+ mem_cookie->memory = NULL;
+ mem_cookie->memory_size = 0;
+ mem_cookie->offset = 0;
+ ret = 0;
+ }
+ else
+ {
+ _set_errno (EINVAL);
+ ret = -1;
+ }
+
+ return ret;
+}
+
/* Destroy function for memory objects. */
static int
@@ -1608,6 +1647,7 @@ es_initialize (estream_t stream,
stream->intern->func_read = functions.func_read;
stream->intern->func_write = functions.func_write;
stream->intern->func_seek = functions.func_seek;
+ stream->intern->func_ioctl = NULL;
stream->intern->func_close = functions.func_close;
stream->intern->strategy = _IOFBF;
stream->intern->syshd = *syshd;
@@ -2667,6 +2707,47 @@ es_fopenmem (size_t memlimit, const char *ES__RESTRICT mode)
if (es_create (&stream, cookie, &syshd, estream_functions_mem, modeflags, 0))
(*estream_functions_mem.func_close) (cookie);
+ if (stream)
+ stream->intern->func_ioctl = es_func_mem_ioctl;
+
+ return stream;
+}
+
+
+
+/* This is the same as es_fopenmem but intializes the memory with a
+ copy of (DATA,DATALEN). The stream is initally set to the
+ beginning. If MEMLIMIT is not 0 but shorter than DATALEN it
+ DATALEN will be used as the value for MEMLIMIT. */
+estream_t
+es_fopenmem_init (size_t memlimit, const char *ES__RESTRICT mode,
+ const void *data, size_t datalen)
+{
+ estream_t stream;
+
+ if (memlimit && memlimit < datalen)
+ memlimit = datalen;
+
+ stream = es_fopenmem (memlimit, mode);
+ if (stream && data && datalen)
+ {
+ if (es_writen (stream, data, datalen, NULL))
+ {
+ int saveerrno = errno;
+ es_fclose (stream);
+ stream = NULL;
+ _set_errno (saveerrno);
+ }
+ else
+ {
+ es_seek (stream, 0L, SEEK_SET, NULL);
+ es_set_indicators (stream, 0, 0);
+ }
+ }
+
+ if (stream)
+ stream->intern->func_ioctl = es_func_mem_ioctl;
+
return stream;
}
@@ -3082,6 +3163,65 @@ es_fclose (estream_t stream)
}
+/* This is a special version of es_fclose which can be used with
+ es_fopenmem to return the memory buffer. This is feature is useful
+ to write to a memory buffer using estream. Note that the function
+ does not close the stream if the stream does not support snatching
+ the buffer. On error NULL is stored at R_BUFFER. Note that if no
+ write operation has happened, NULL may also be stored at BUFFER on
+ success. The caller needs to release the returned memory using
+ es_free. */
+int
+es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen)
+{
+ int err;
+
+ /* Note: There is no need to lock the stream in a close call. The
+ object will be destroyed after the close and thus any other
+ contender for the lock would work on a closed stream. */
+
+ if (r_buffer)
+ {
+ cookie_ioctl_function_t func_ioctl = stream->intern->func_ioctl;
+ size_t buflen;
+
+ *r_buffer = NULL;
+
+ if (!func_ioctl)
+ {
+ _set_errno (EOPNOTSUPP);
+ err = -1;
+ goto leave;
+ }
+
+ if (stream->flags.writing)
+ {
+ err = es_flush (stream);
+ if (err)
+ goto leave;
+ stream->flags.writing = 0;
+ }
+
+ err = func_ioctl (stream->intern->cookie, COOKIE_IOCTL_SNATCH_BUFFER,
+ r_buffer, &buflen);
+ if (err)
+ goto leave;
+ if (r_buflen)
+ *r_buflen = buflen;
+ }
+
+ err = do_close (stream, 0);
+
+ leave:
+ if (err && r_buffer)
+ {
+ mem_free (*r_buffer);
+ *r_buffer = NULL;
+ }
+ return err;
+}
+
+
/* Register or unregister a close notification function for STREAM.
FNC is the function to call and FNC_VALUE the value passed as
second argument. To register the notification the value for MODE
diff --git a/common/estream.h b/common/estream.h
index 49662766e..bbe5b62d6 100644
--- a/common/estream.h
+++ b/common/estream.h
@@ -1,5 +1,5 @@
/* estream.h - Extended stream I/O Library
- * Copyright (C) 2004, 2005, 2006, 2007, 2010 g10 Code GmbH
+ * Copyright (C) 2004, 2005, 2006, 2007, 2010, 2011 g10 Code GmbH
*
* This file is part of Libestream.
*
@@ -88,6 +88,7 @@
#define es_freopen _ESTREAM_PREFIX(es_freopen)
#define es_fopencookie _ESTREAM_PREFIX(es_fopencookie)
#define es_fclose _ESTREAM_PREFIX(es_fclose)
+#define es_fclose_snatch _ESTREAM_PREFIX(es_fclose_snatch)
#define es_onclose _ESTREAM_PREFIX(es_onclose)
#define es_fileno _ESTREAM_PREFIX(es_fileno)
#define es_fileno_unlocked _ESTREAM_PREFIX(es_fileno_unlocked)
@@ -285,6 +286,7 @@ estream_t es_fopencookie (void *ES__RESTRICT cookie,
const char *ES__RESTRICT mode,
es_cookie_io_functions_t functions);
int es_fclose (estream_t stream);
+int es_fclose_snatch (estream_t stream, void **r_buffer, size_t *r_buflen);
int es_onclose (estream_t stream, int mode,
void (*fnc) (estream_t, void*), void *fnc_value);
int es_fileno (estream_t stream);
diff --git a/configure.ac b/configure.ac
index ebf3515b8..043ece692 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,7 +46,7 @@ NEED_LIBGCRYPT_API=1
NEED_LIBGCRYPT_VERSION=1.5.0
NEED_LIBASSUAN_API=2
-NEED_LIBASSUAN_VERSION=2.0.0
+NEED_LIBASSUAN_VERSION=2.0.3
NEED_KSBA_API=1
NEED_KSBA_VERSION=1.2.0
diff --git a/dirmngr/ChangeLog-2011 b/dirmngr/ChangeLog-2011
index b35bec313..84cf55288 100644
--- a/dirmngr/ChangeLog-2011
+++ b/dirmngr/ChangeLog-2011
@@ -15,21 +15,6 @@
* certcache.c (classify_pattern): Remove unused variable and make
explicit substring search work.
-2011-11-24 Werner Koch <[email protected]>
-
- * 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 <[email protected]>
-
- * Makefile.am, certcache.c, crlfetch.c, dirmngr.c, ldap-wrapper.c:
- Port to NPth.
-
2011-06-01 Marcus Brinkmann <[email protected]>
* Makefile.am (dirmngr_ldap_CFLAGS): Add $(LIBGCRYPT_CFLAGS),
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index 333ab9e73..51cefd590 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -1038,7 +1038,7 @@ main (int argc, char **argv)
if (csh_style)
{
*strchr (infostr, '=') = ' ';
- es_printf ( "setenv %s\n", infostr);
+ es_printf ( "setenv %s;\n", infostr);
}
else
{
diff --git a/doc/DETAILS b/doc/DETAILS
index 543ae4d96..ddf7438f5 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -58,6 +58,10 @@ record; gpg2 does this by default and the option is a dummy.
u = The key is ultimately valid. This often means
that the secret key is available, but any key may
be marked as ultimately valid.
+ w = The key has a well known private part.
+ s = The key has special validity. This means that it
+ might be self-signed and expected to be used in
+ the STEED sytem.
If the validity information is given for a UID or UAT
record, it describes the validity calculated based on this
@@ -347,6 +351,7 @@ more arguments in future versions.
"pgp" for the standard PGP WoT.
"shell" for the standard X.509 model.
"chain" for the chain model.
+ "steed" for the STEED model.
Note that we use the term "TRUST_" in the status names for
historic reasons; we now speak of validity.
@@ -1036,6 +1041,7 @@ OIDs below the GnuPG arc:
1.3.6.1.4.1.11591.2.1.1 pkaAddress
1.3.6.1.4.1.11591.2.2 X.509 extensions
1.3.6.1.4.1.11591.2.2.1 standaloneCertificate
+ 1.3.6.1.4.1.11591.2.2.2 wellKnownPrivateKey
1.3.6.1.4.1.11591.2.12242973 invalid encoded OID
diff --git a/doc/HACKING b/doc/HACKING
index d6cb8ab4c..0ef5b891d 100644
--- a/doc/HACKING
+++ b/doc/HACKING
@@ -23,7 +23,8 @@ and ChangeLog entries don't give enough of the big picture. Omit the
leading TABs that you're used to seeing in a "real" ChangeLog file, but
keep the maximum line length at 72 or smaller, so that the generated
ChangeLog lines, each with its leading TAB, will not exceed 80 columns.
-
+If you want to add text which shall not be copied to the ChangeLog,
+separate it by a line consisting of two dashes at the begin of a line.
===> What follows is probably out of date <===
@@ -39,15 +40,17 @@ RFCs
1750 Randomness Recommendations for Security.
-1991 PGP Message Exchange Formats.
-
-2015 MIME Security with Pretty Good Privacy (PGP).
+1991 PGP Message Exchange Formats (obsolete)
2144 The CAST-128 Encryption Algorithm.
2279 UTF-8, a transformation format of ISO 10646.
-2440 OpenPGP.
+2440 OpenPGP (obsolete).
+
+3156 MIME Security with Pretty Good Privacy (PGP).
+
+4880 Current OpenPGP specification.
diff --git a/doc/com-certs.pem b/doc/com-certs.pem
index 43e93b74c..b3d5fa2c3 100644
--- a/doc/com-certs.pem
+++ b/doc/com-certs.pem
@@ -482,3 +482,21 @@ G1RRiCiWgYaEtSIDAP0V9ehpcghfJLlmMBnxSf4n7OZvkd1whvme2rXaQxnZi2qV
d2qclY03eJ7zx6Zpq8VFuVvOxvmFZ4mMe706runhCq+rHc5x6x0/oIMhDrk=
-----END CERTIFICATE-----
+Issuer ...: /CN=The STEED Self-Signing Nonthority
+Serial ...: 01
+Subject ..: /CN=The STEED Self-Signing Nonthority
+
+-----BEGIN CERTIFICATE-----
+MIICKDCCAZGgAwIBAgIBATANBgkqhkiG9w0BAQUFADAsMSowKAYDVQQDEyFUaGUg
+U1RFRUQgU2VsZi1TaWduaW5nIE5vbnRob3JpdHkwIBcNMTExMTExMDAwMDAwWhgP
+MjEwNjAyMDYwMDAwMDBaMCwxKjAoBgNVBAMTIVRoZSBTVEVFRCBTZWxmLVNpZ25p
+bmcgTm9udGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAk2h9kqe8
+0eb8ESY7UGV6j6S5zuP5DiM4TWJ3jKG2y+D2CyA1Sl90iZ6zyN3zCB0yR1xxhpuw
+xdrwBRovRFludAbx3MeynYhzXkk0Hwn038q1oIt2YUw3Igz34s24o455ZE86JQ/6
+5dC7ppF8Z1I9KBL96NO+qZR/alVAKxYAwS8CAwEAAaNYMFYwEgYDVR0TAQH/BAgw
+BgEB/wIBATARBgorBgEEAdpHAgICBAMBAf8wHQYDVR0OBBYEFGimOJmN+rrFEOpk
+XONPloay7ffqMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQB3JwUn
+AbOdGv5ErojNSSP+yGZIy5av4wnkzK840Uj3jY6A5cuHroZGOD60hqLV2Hy0npox
+zte4phWEKWmZiXd8SCmd3MFNgZSieiixye0qxSmuqYft2j6NhEXD5xc/iTTjFT42
+SjGPLKAICuMBuGPnoozOEVlgqwaDqKOUph5sqw==
+-----END CERTIFICATE-----
diff --git a/doc/faq.org b/doc/faq.org
index ee6c0c758..a11fabebd 100644
--- a/doc/faq.org
+++ b/doc/faq.org
@@ -1167,13 +1167,8 @@ update this FAQ in the next month. See the section "Changes" for recent updates
:CUSTOM_ID: i-get-sed-errors-when-running-configure-on-mac-os-x
:END:
- This will be fixed after GnuPG has been upgraded to autoconf-2.50.
- Until then, find the line setting CDPATH in the configure script
- and place an:
-
- : unset CDPATH
-
- statement below it.
+ This problem has been fixed for all modern GnuPG versions.
+ (By using an autoconf 2.50 generated configure script).
** Why does GnuPG 1.0.6 bail out on keyrings used with 1.0.7?
:PROPERTIES:
@@ -1470,6 +1465,41 @@ update this FAQ in the next month. See the section "Changes" for recent updates
of the listing before before starting the import.
+* Bug reporting and hacking
+ :PROPERTIES:
+ :CUSTOM_ID: bugreports-et-al
+ :END:
+
+** Copyright asssignments
+ :PROPERTIES:
+ :CUSTOM_ID: copyright-assigments
+ :END:
+
+** U.S. export restrictions
+ :PROPERTIES:
+ :CUSTOM_ID: us-export-restrictions
+ :END:
+
+GnuPG has originally been developed in Germany because we have been
+able to do that without being affected by the US export restrictions.
+We had to reject any contributions from US citizens or from people
+living the the US. That changed by end of 2000 when the export
+restrictions were basically dropped for all kind of freely available
+software. However there are still some requirements in the US.
+Quoting David Shaw: mail
+#+begin_quote
+For each release of GPG that I contributed to, I sent an email
+containing a pointer to the new source code to the Commerce
+Department. The rules changed slightly in 2004, so that you could
+send a single email and then be done until the information in that
+email changed, so I just sent "www.gnupg.org" and haven't bothered
+with the email since.
+#+end_quote
+
+The rules: http://www.bis.doc.gov/encryption/pubavailencsourcecodenofify.html
+The 2004 rule change: http://edocket.access.gpo.gov/2004/04-26992.htm
+
+
* Acknowledgements
:PROPERTIES:
:CUSTOM_ID: acknowledgements
diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi
index 892083335..bdb03783e 100644
--- a/doc/gpgsm.texi
+++ b/doc/gpgsm.texi
@@ -451,10 +451,11 @@ address and the time when you verified the signature.
@item --validation-model @var{name}
@opindex validation-model
This option changes the default validation model. The only possible
-values are "shell" (which is the default) and "chain" which forces the
-use of the chain model. The chain model is also used if an option in
-the @file{trustlist.txt} or an attribute of the certificate requests it.
-However the standard model (shell) is in that case always tried first.
+values are "shell" (which is the default), "chain" which forces the
+use of the chain model and "steed" for a new simplified model. The
+chain model is also used if an option in the @file{trustlist.txt} or
+an attribute of the certificate requests it. However the standard
+model (shell) is in that case always tried first.
@item --ignore-cert-extension @var{oid}
@opindex ignore-cert-extension
@@ -1042,9 +1043,9 @@ already existing key. Key-Length will be ignored when given.
@item Key-Usage: @var{usage-list}
Space or comma delimited list of key usage, allowed values are
-@samp{encrypt} and @samp{sign}. This is used to generate the keyUsage
-extension. Please make sure that the algorithm is capable of this
-usage. Default is to allow encrypt and sign.
+@samp{encrypt}, @samp{sign} and @samp{cert}. This is used to generate
+the keyUsage extension. Please make sure that the algorithm is
+capable of this usage. Default is to allow encrypt and sign.
@item Name-DN: @var{subject-name}
This is the Distinguished Name (DN) of the subject in RFC-2253 format.
diff --git a/doc/scdaemon.texi b/doc/scdaemon.texi
index 3c8427997..200fed890 100644
--- a/doc/scdaemon.texi
+++ b/doc/scdaemon.texi
@@ -21,16 +21,16 @@
.IR dir ]
.RB [ \-\-options
.IR file ]
-.RI [ options ]
-.B \-\-server
+.RI [ options ]
+.B \-\-server
.br
.B scdaemon
.RB [ \-\-homedir
.IR dir ]
.RB [ \-\-options
.IR file ]
-.RI [ options ]
-.B \-\-daemon
+.RI [ options ]
+.B \-\-daemon
.RI [ command_line ]
@end ifset
@@ -130,7 +130,7 @@ a numeric value or a keyword:
@item none
No debugging at all. A value of less than 1 may be used instead of
the keyword.
-@item basic
+@item basic
Some basic debug messages. A value between 1 and 2 may be used
instead of the keyword.
@item advanced
@@ -165,8 +165,8 @@ usual C-Syntax. The currently defined bits are:
@table @code
@item 0 (1)
command I/O
-@item 1 (2)
-values of big number integers
+@item 1 (2)
+values of big number integers
@item 2 (4)
low level crypto operations
@item 5 (32)
@@ -178,9 +178,11 @@ show memory statistics.
@item 9 (512)
write hashed data to files named @code{dbgmd-000*}
@item 10 (1024)
-trace Assuan protocol
+trace Assuan protocol. See also option @option{--debug-assuan-log-cats}.
@item 11 (2048)
trace APDU I/O to the card. This may reveal sensitive data.
+@item 12 (4096)
+trace some card reader related function calls.
@end table
@item --debug-all
@@ -215,6 +217,15 @@ dump. This options enables it and also changes the working directory to
@opindex debug-log-tid
This option appends a thread ID to the PID in the log output.
+@item --debug-assuan-log-cats @var{cats}
+@opindex debug-assuan-log-cats
+Changes the active Libassuan logging categories to @var{cats}. The
+value for @var{cats} is an unsigned integer given in usual C-Syntax.
+A value of of 0 switches to a default category. If this option is not
+used the categories are taken from the environment variable
+@samp{ASSUAN_DEBUG}. Note that this option has only an effect if the
+Assuan debug flag has also been with the option @option{--debug}. For
+a list of categories see the Libassuan manual.
@item --no-detach
@opindex no-detach
@@ -240,7 +251,7 @@ Use @var{library} to access the smartcard reader. The current default
is @file{libtowitoko.so}. Note that the use of this interface is
deprecated; it may be removed in future releases.
-@item --disable-ccid
+@item --disable-ccid
@opindex disable-ccid
Disable the integrated support for CCID compliant readers. This
allows to fall back to one of the other drivers even if the internal
@@ -318,6 +329,7 @@ stripping off the two leading dashes.
* DINSIG Card:: The DINSIG card application
* PKCS#15 Card:: The PKCS#15 card application
* Geldkarte Card:: The Geldkarte application
+* Undefined Card:: The Undefined stub application
@end menu
@node OpenPGP Card
@@ -325,7 +337,7 @@ stripping off the two leading dashes.
This application is currently only used by @command{gpg} but may in
future also be useful with @command{gpgsm}. Version 1 and version 2 of
-the card is supported.
+the card is supported.
The specifications for these cards are available at
@uref{http://g10code.com/docs/openpgp-card-1.0.pdf} and
@@ -358,6 +370,14 @@ This is a simple application to display information of a German
Geldkarte. The Geldkarte is a small amount debit card application which
comes with almost all German banking cards.
+@node Undefined Card
+@subsection The Undefined card application ``undefined''
+
+This is a stub application to allow the use of the APDU command even
+if no supported application is found on the card. This application is
+not used automatically but must be explicitly requested using the
+SERIALNO command.
+
@c *******************************************
@c *************** ****************
@@ -395,7 +415,7 @@ about reader status changes. Its use is now deprecated in favor of
@end table
-@c
+@c
@c Examples
@c
@mansect examples
@@ -410,7 +430,7 @@ $ scdaemon --server -v
@c man end
-@c
+@c
@c Assuan Protocol
@c
@manpause
@@ -447,7 +467,7 @@ synchronizing access to a token between sessions.
* Scdaemon APDU:: Send a verbatim APDU to the card
@end menu
-@node Scdaemon SERIALNO
+@node Scdaemon SERIALNO
@subsection Return the serial number
This command should be used to check for the presence of a card. It is
@@ -470,7 +490,7 @@ Return the serial number of the card using a status response like:
@end example
The trailing 0 should be ignored for now, it is reserved for a future
-extension. The serial number is the hex encoded value identified by
+extension. The serial number is the hex encoded value identified by
the @code{0x5A} tag in the GDO file (FIX=0x2F02).
@@ -522,7 +542,7 @@ READKEY @var{hexified_certid}
@end example
Return the public key for the given cert or key ID as an standard
-S-Expression.
+S-Expression.
@@ -619,7 +639,7 @@ TO BE WRITTEN.
@example
PASSWD [--reset] [--nullpin] @var{chvno}
@end example
-
+
Change the PIN or reset the retry counter of the card holder
verification vector number @var{chvno}. The option @option{--nullpin}
is used to initialize the PIN of TCOS cards (6 byte NullPIN only).
@@ -663,11 +683,11 @@ and only if the retry counter is still at 3.
Restart the current connection; this is a kind of warm reset. It
deletes the context used by this connection but does not actually
-reset the card.
+reset the card.
This is used by gpg-agent to reuse a primary pipe connection and
may be used by clients to backup from a conflict in the serial
-command; i.e. to select another application.
+command; i.e. to select another application.
@@ -704,7 +724,7 @@ length up to N bytes. If N is not given a default value is used
@mansect see also
@ifset isman
@command{gpg-agent}(1),
-@command{gpgsm}(1),
+@command{gpgsm}(1),
@command{gpg2}(1)
@end ifset
@include see-also-note.texi
diff --git a/g10/photoid.c b/g10/photoid.c
index 9045f0c16..c3d2745a8 100644
--- a/g10/photoid.c
+++ b/g10/photoid.c
@@ -1,5 +1,5 @@
/* photoid.c - photo ID handling code
- * Copyright (C) 2001, 2002, 2005, 2006, 2008 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2005, 2006, 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -141,8 +141,7 @@ generate_photo_id(PKT_public_key *pk,const char *photo_name)
iobuf_close(file);
/* Is it a JPEG? */
- if(photo[0]!=0xFF || photo[1]!=0xD8 ||
- photo[6]!='J' || photo[7]!='F' || photo[8]!='I' || photo[9]!='F')
+ if(photo[0]!=0xFF || photo[1]!=0xD8)
{
log_error(_("`%s' is not a JPEG file\n"),filename);
xfree(photo);
diff --git a/g13/g13.c b/g13/g13.c
index b3603ccaf..34b91c166 100644
--- a/g13/g13.c
+++ b/g13/g13.c
@@ -353,6 +353,8 @@ main ( int argc, char **argv)
i18n_init ();
init_common_subsystems (&argc, &argv);
+ npth_init ();
+
/* Check that the Libgcrypt is suitable. */
if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
@@ -658,6 +660,7 @@ main ( int argc, char **argv)
#endif /*0*/
/* Dispatch command. */
+ err = 0;
switch (cmd)
{
case aGPGConfList:
diff --git a/keyserver/gpgkeys_hkp.c b/keyserver/gpgkeys_hkp.c
index d43a61ab5..ac7039d06 100644
--- a/keyserver/gpgkeys_hkp.c
+++ b/keyserver/gpgkeys_hkp.c
@@ -241,9 +241,10 @@ static int
get_key(char *getkey)
{
CURLcode res;
- char request[MAX_URL+60];
+ char request[MAX_URL+92];
char *offset;
struct curl_writer_ctx ctx;
+ size_t keylen;
memset(&ctx,0,sizeof(ctx));
@@ -269,14 +270,19 @@ get_key(char *getkey)
strcat(request,port);
strcat(request,opt->path);
/* request is MAX_URL+55 bytes long - MAX_URL covers the whole URL,
- including any supplied path. The 60 overcovers this /pks/... etc
- string plus the 8 bytes of key id */
+ including any supplied path. The 92 overcovers this /pks/... etc
+ string plus the 8, 16, or 40 bytes of key id/fingerprint */
append_path(request,"/pks/lookup?op=get&options=mr&search=0x");
- /* fingerprint or long key id. Take the last 8 characters and treat
- it like a short key id */
- if(strlen(getkey)>8)
- offset=&getkey[strlen(getkey)-8];
+ /* send only fingerprint, long key id, or short keyid. see:
+ https://tools.ietf.org/html/draft-shaw-openpgp-hkp-00#section-3.1.1.1 */
+ keylen = strlen(getkey);
+ if(keylen >= 40)
+ offset=&getkey[keylen-40];
+ else if(keylen >= 16)
+ offset=&getkey[keylen-16];
+ else if(keylen >= 8)
+ offset=&getkey[keylen-8];
else
offset=getkey;
diff --git a/po/de.po b/po/de.po
index fe83f7979..8b982587b 100644
--- a/po/de.po
+++ b/po/de.po
@@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: gnupg-2.1.0\n"
"Report-Msgid-Bugs-To: [email protected]\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 <[email protected]>\n"
"Language-Team: German <[email protected]>\n"
"MIME-Version: 1.0\n"
@@ -111,9 +111,9 @@ msgstr "Fehler beim Holen der Karten-Seriennummer: %s\n"
msgid "detected card with S/N: %s\n"
msgstr "Erkannte Karte hat die Seriennummer: %s\n"
-#, fuzzy, c-format
+#, c-format
msgid "no authentication key for ssh on card: %s\n"
-msgstr "Fehler beim Holen der AuthentisierungsschlĂ¼ssel-ID der Karte: %s\n"
+msgstr "Auf der Karte ist kein AuthentisierungsschlĂ¼ssel fĂ¼r SSH: %s\n"
#, c-format
msgid "no suitable card key found: %s\n"
@@ -5434,17 +5434,11 @@ msgstr "|AN|Neue Admin-PIN"
msgid "|N|New PIN"
msgstr "|N|Neue PIN"
-#, fuzzy
-msgid "||Please enter the Reset Code for the card and New PIN"
-msgstr "Bitte geben Sie den RĂ¼ckstellcode fĂ¼r diese Karte ein"
-
-#, fuzzy
msgid "||Please enter the Admin PIN and New Admin PIN"
-msgstr "|A|Bitte die Admin-PIN eingeben."
+msgstr "|A|Bitte die Admin-PIN sowie die neue Admin-PIN eingeben."
-#, fuzzy
msgid "||Please enter the PIN and New PIN"
-msgstr "||Bitte die PIN eingeben"
+msgstr "||Bitte die PIN sowie die neue PIN eingeben"
msgid "error reading application data\n"
msgstr "Fehler beim Lesen der Anwendungsdaten\n"
@@ -5881,6 +5875,18 @@ msgid "line %d: invalid hash algorithm given\n"
msgstr "Zeile %d: UngĂ¼ltiges Hashverfahren\n"
#, c-format
+msgid "line %d: invalid authority-key-id\n"
+msgstr "Zeile %d: UngĂ¼ltige AuthentisierungsschlĂ¼ssel-ID\n"
+
+#, c-format
+msgid "line %d: invalid subject-key-id\n"
+msgstr "Zeile %d: ungĂ¼ltige \"Subject-Key-Id\"\n"
+
+#, c-format
+msgid "line %d: invalid extension syntax\n"
+msgstr "Zeile %d: UngĂ¼ltiger Syntax der Extension\n"
+
+#, c-format
msgid "line %d: error reading key `%s' from card: %s\n"
msgstr "Zeile %d: Fehler beim Lesen des SchlĂ¼ssels `%s' von der Karte: %s\n"
@@ -7925,6 +7931,10 @@ msgstr ""
"Syntax: gpg-check-pattern [optionen] Musterdatei\n"
"Die von stdin gelesene Passphrase gegen die Musterdatei prĂ¼fen\n"
+#, fuzzy
+#~ msgid "||Please enter the Reset Code for the card and New PIN"
+#~ msgstr "Bitte geben Sie den RĂ¼ckstellcode fĂ¼r diese Karte ein"
+
#~ msgid " - probably dead - removing lock"
#~ msgstr " - existiert wahrscheinlich nicht mehr - entferne Sperre"
diff --git a/scd/ChangeLog-2011 b/scd/ChangeLog-2011
index 5a87a4c79..9184af4c5 100644
--- a/scd/ChangeLog-2011
+++ b/scd/ChangeLog-2011
@@ -87,10 +87,6 @@
(handle_control): New.
(main): Handle the case 6 of handle_control.
-2011-10-13 Marcus Brinkmann <[email protected]>
-
- * Makefile.am, apdu.c, app.c, command.c, scdaemon.c: Port to Npth.
-
2011-08-10 Werner Koch <[email protected]>
* command.c (cmd_killscd): Use the new assuan force close flag
diff --git a/scd/Makefile.am b/scd/Makefile.am
index d9a3ddbde..09aea0e84 100644
--- a/scd/Makefile.am
+++ b/scd/Makefile.am
@@ -37,6 +37,7 @@ card_apps = app-openpgp.c app-nks.c app-dinsig.c app-p15.c app-geldkarte.c
scdaemon_SOURCES = \
scdaemon.c scdaemon.h \
command.c \
+ atr.c atr.h \
apdu.c apdu.h \
ccid-driver.c ccid-driver.h \
iso7816.c iso7816.h \
diff --git a/scd/apdu.c b/scd/apdu.c
index e4ebc3586..e914f7b24 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -465,8 +465,11 @@ apdu_strerror (int rc)
case SW_FILE_NOT_FOUND : return "file not found";
case SW_RECORD_NOT_FOUND:return "record not found";
case SW_REF_NOT_FOUND : return "reference not found";
- case SW_BAD_LC : return "bad Lc";
- case SW_BAD_P0_P1 : return "bad P0 or P1";
+ case SW_NOT_ENOUGH_MEMORY: return "not enough memory space in the file";
+ case SW_INCONSISTENT_LC: return "Lc inconsistent with TLV structure.";
+ case SW_INCORRECT_P0_P1: return "incorrect parameters P0,P1";
+ case SW_BAD_LC : return "Lc inconsistent with P0,P1";
+ case SW_BAD_P0_P1 : return "bad P0,P1";
case SW_INS_NOT_SUP : return "instruction not supported";
case SW_CLA_NOT_SUP : return "class not supported";
case SW_SUCCESS : return "success";
@@ -2052,7 +2055,7 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
{
int sw;
unsigned char *pin_verify;
- unsigned long len = PIN_VERIFY_STRUCTURE_SIZE;
+ int len = PIN_VERIFY_STRUCTURE_SIZE;
unsigned char result[2];
size_t resultlen = 2;
@@ -2108,12 +2111,23 @@ pcsc_keypad_verify (int slot, int class, int ins, int p0, int p1,
pin_verify[22] = p1; /* abData[3] */
pin_verify[23] = 0x00; /* abData[4] */
+ if (DBG_CARD_IO)
+ log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
+ class, ins, p0, p1, len, pininfo->maxlen);
+
sw = control_pcsc (slot, reader_table[slot].pcsc.verify_ioctl,
pin_verify, len, result, &resultlen);
xfree (pin_verify);
if (sw || resultlen < 2)
return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
sw = (result[resultlen-2] << 8) | result[resultlen-1];
+ {
+ log_error ("control_pcsc failed: %d\n", sw);
+ return sw? sw: SW_HOST_INCOMPLETE_CARD_RESPONSE;
+ }
+ sw = (result[resultlen-2] << 8) | result[resultlen-1];
+ if (DBG_CARD_IO)
+ log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen);
return sw;
}
@@ -2125,7 +2139,7 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
{
int sw;
unsigned char *pin_modify;
- unsigned long len = PIN_MODIFY_STRUCTURE_SIZE;
+ int len = PIN_MODIFY_STRUCTURE_SIZE;
unsigned char result[2];
size_t resultlen = 2;
@@ -2192,12 +2206,21 @@ pcsc_keypad_modify (int slot, int class, int ins, int p0, int p1,
pin_modify[27] = p1; /* abData[3] */
pin_modify[28] = 0x00; /* abData[4] */
+ if (DBG_CARD_IO)
+ log_debug ("send secure: c=%02X i=%02X p1=%02X p2=%02X len=%d pinmax=%d\n",
+ class, ins, p0, p1, len, (int)pininfo->maxlen);
+
sw = control_pcsc (slot, reader_table[slot].pcsc.modify_ioctl,
pin_modify, len, result, &resultlen);
xfree (pin_modify);
if (sw || resultlen < 2)
- return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
+ {
+ log_error ("control_pcsc failed: %d\n", sw);
+ return sw? sw : SW_HOST_INCOMPLETE_CARD_RESPONSE;
+ }
sw = (result[resultlen-2] << 8) | result[resultlen-1];
+ if (DBG_CARD_IO)
+ log_debug (" response: sw=%04X datalen=%d\n", sw, (unsigned int)resultlen);
return sw;
}
@@ -2783,6 +2806,9 @@ apdu_open_reader (const char *portstr, int *r_no_service)
static int pcsc_api_loaded, ct_api_loaded;
int slot;
+ if (DBG_READER)
+ log_debug ("enter: apdu_open_reader: portstr=%s\n", portstr);
+
if (r_no_service)
*r_no_service = 0;
@@ -2797,6 +2823,8 @@ apdu_open_reader (const char *portstr, int *r_no_service)
if (slot != -1)
{
once_available = 1;
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=%d [ccid]\n", slot);
return slot; /* got one */
}
@@ -2807,14 +2835,22 @@ apdu_open_reader (const char *portstr, int *r_no_service)
and over again. To reset this flag "gpgconf --kill scdaemon"
can be used. */
if (once_available)
- return -1;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=-1 (once_avail)\n");
+ return -1;
+ }
/* If a CCID reader specification has been given, the user does
not want a fallback to other drivers. */
if (portstr)
for (s=portstr, i=0; *s; s++)
if (*s == ':' && (++i == 3))
- return -1;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=-1 (no ccid)\n");
+ return -1;
+ }
}
#endif /* HAVE_LIBUSB */
@@ -2939,6 +2975,8 @@ apdu_open_reader (const char *portstr, int *r_no_service)
if (slot == -1 && r_no_service && pcsc_no_service)
*r_no_service = 1;
+ if (DBG_READER)
+ log_debug ("leave: apdu_open_reader => slot=%d [pc/sc]\n", slot);
return slot;
}
@@ -2993,13 +3031,31 @@ apdu_close_reader (int slot)
{
int sw;
+ if (DBG_READER)
+ log_debug ("enter: apdu_close_reader: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_close_reader => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
sw = apdu_disconnect (slot);
if (sw)
- return sw;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_close_reader => 0x%x (apdu_disconnect)\n", sw);
+ return sw;
+ }
if (reader_table[slot].close_reader)
- return reader_table[slot].close_reader (slot);
+ {
+ sw = reader_table[slot].close_reader (slot);
+ if (DBG_READER)
+ log_debug ("leave: apdu_close_reader => 0x%x (close_reader)\n", sw);
+ return sw;
+ }
+ if (DBG_READER)
+ log_debug ("leave: apdu_close_reader => SW_HOST_NOT_SUPPORTED\n");
return SW_HOST_NOT_SUPPORTED;
}
@@ -3038,13 +3094,32 @@ apdu_shutdown_reader (int slot)
{
int sw;
+ if (DBG_READER)
+ log_debug ("enter: apdu_shutdown_reader: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_shutdown_reader => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
sw = apdu_disconnect (slot);
if (sw)
- return sw;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_shutdown_reader => 0x%x (apdu_disconnect)\n",
+ sw);
+ return sw;
+ }
if (reader_table[slot].shutdown_reader)
- return reader_table[slot].shutdown_reader (slot);
+ {
+ sw = reader_table[slot].shutdown_reader (slot);
+ if (DBG_READER)
+ log_debug ("leave: apdu_shutdown_reader => 0x%x (close_reader)\n", sw);
+ return sw;
+ }
+ if (DBG_READER)
+ log_debug ("leave: apdu_shutdown_reader => SW_HOST_NOT_SUPPORTED\n");
return SW_HOST_NOT_SUPPORTED;
}
@@ -3062,14 +3137,24 @@ apdu_enum_reader (int slot, int *used)
/* Connect a card. This is used to power up the card and make sure
- that an ATR is available. */
+ that an ATR is available. Depending on the reader backend it may
+ return an error for an inactive card or if no card is
+ available. */
int
apdu_connect (int slot)
{
int sw;
+ unsigned int status;
+
+ if (DBG_READER)
+ log_debug ("enter: apdu_connect: slot=%d\n", slot);
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_connect => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
/* Only if the access method provides a connect function we use it.
If not, we expect that the card has been implicitly connected by
@@ -3091,7 +3176,16 @@ apdu_connect (int slot)
scdaemon is fired up and apdu_get_status has not yet been called.
Without that we would force a reset of the card with the next
call to apdu_get_status. */
- apdu_get_status_internal (slot, 1, 1, NULL, NULL);
+ apdu_get_status_internal (slot, 1, 1, &status, NULL);
+ if (sw)
+ ;
+ else if (!(status & APDU_CARD_PRESENT))
+ sw = SW_HOST_NO_CARD;
+ else if ((status & APDU_CARD_PRESENT) && !(status & APDU_CARD_ACTIVE))
+ sw = SW_HOST_CARD_INACTIVE;
+
+ if (DBG_READER)
+ log_debug ("leave: apdu_connect => sw=0x%x\n", sw);
return sw;
}
@@ -3102,8 +3196,15 @@ apdu_disconnect (int slot)
{
int sw;
+ if (DBG_READER)
+ log_debug ("enter: apdu_disconnect: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_disconnect => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
if (reader_table[slot].disconnect_card)
{
@@ -3116,6 +3217,9 @@ apdu_disconnect (int slot)
}
else
sw = 0;
+
+ if (DBG_READER)
+ log_debug ("leave: apdu_disconnect => sw=0x%x\n", sw);
return sw;
}
@@ -3151,11 +3255,22 @@ apdu_reset (int slot)
{
int sw;
+ if (DBG_READER)
+ log_debug ("enter: apdu_reset: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_reset => SW_HOST_NO_DRIVER\n");
+ return SW_HOST_NO_DRIVER;
+ }
if ((sw = lock_slot (slot)))
- return sw;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_reset => sw=0x%x (lock_slot)\n", sw);
+ return sw;
+ }
reader_table[slot].last_status = 0;
if (reader_table[slot].reset_reader)
@@ -3171,73 +3286,47 @@ apdu_reset (int slot)
}
unlock_slot (slot);
+ if (DBG_READER)
+ log_debug ("leave: apdu_reset => sw=0x%x\n", sw);
return sw;
}
-/* Activate a card if it has not yet been done. This is a kind of
- reset-if-required. It is useful to test for presence of a card
- before issuing a bunch of apdu commands. It does not wait on a
- locked card. */
-int
-apdu_activate (int slot)
-{
- int sw;
- unsigned int s;
-
- if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return SW_HOST_NO_DRIVER;
-
- if ((sw = trylock_slot (slot)))
- return sw;
-
- if (reader_table[slot].get_status_reader)
- sw = reader_table[slot].get_status_reader (slot, &s);
-
- if (!sw)
- {
- if (!(s & 2)) /* Card not present. */
- sw = SW_HOST_NO_CARD;
- else if ( ((s & 2) && !(s & 4))
- || !reader_table[slot].atrlen )
- {
- /* We don't have an ATR or a card is present though inactive:
- do a reset now. */
- if (reader_table[slot].reset_reader)
- {
- reader_table[slot].last_status = 0;
- sw = reader_table[slot].reset_reader (slot);
- if (!sw)
- {
- /* If we got to here we know that a card is present
- and usable. Thus remember this. */
- reader_table[slot].last_status = (APDU_CARD_USABLE
- | APDU_CARD_PRESENT
- | APDU_CARD_ACTIVE);
- }
- }
- }
- }
-
- unlock_slot (slot);
- return sw;
-}
-
-
+/* Return the ATR or NULL if none is available. On success the length
+ of the ATR is stored at ATRLEN. The caller must free the returned
+ value. */
unsigned char *
apdu_get_atr (int slot, size_t *atrlen)
{
unsigned char *buf;
+ if (DBG_READER)
+ log_debug ("enter: apdu_get_atr: slot=%d\n", slot);
+
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
- return NULL;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_get_atr => NULL (bad slot)\n");
+ return NULL;
+ }
if (!reader_table[slot].atrlen)
- return NULL;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_get_atr => NULL (no ATR)\n");
+ return NULL;
+ }
+
buf = xtrymalloc (reader_table[slot].atrlen);
if (!buf)
- return NULL;
+ {
+ if (DBG_READER)
+ log_debug ("leave: apdu_get_atr => NULL (out of core)\n");
+ return NULL;
+ }
memcpy (buf, reader_table[slot].atr, reader_table[slot].atrlen);
*atrlen = reader_table[slot].atrlen;
+ if (DBG_READER)
+ log_debug ("leave: apdu_get_atr => atrlen=%zu\n", *atrlen);
return buf;
}
@@ -3308,7 +3397,26 @@ int
apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed)
{
- return apdu_get_status_internal (slot, hang, 0, status, changed);
+ int sw;
+
+ if (DBG_READER)
+ log_debug ("enter: apdu_get_status: slot=%d hang=%d\n", slot, hang);
+ sw = apdu_get_status_internal (slot, hang, 0, status, changed);
+ if (DBG_READER)
+ {
+ if (status && changed)
+ log_debug ("leave: apdu_get_status => sw=0x%x status=%u changecnt=%u\n",
+ sw, *status, *changed);
+ else if (status)
+ log_debug ("leave: apdu_get_status => sw=0x%x status=%u\n",
+ sw, *status);
+ else if (changed)
+ log_debug ("leave: apdu_get_status => sw=0x%x changed=%u\n",
+ sw, *changed);
+ else
+ log_debug ("leave: apdu_get_status => sw=0x%x\n", sw);
+ }
+ return sw;
}
diff --git a/scd/apdu.h b/scd/apdu.h
index ac1eeeb3b..75025469e 100644
--- a/scd/apdu.h
+++ b/scd/apdu.h
@@ -41,6 +41,9 @@ enum {
SW_NOT_SUPPORTED = 0x6a81,
SW_FILE_NOT_FOUND = 0x6a82,
SW_RECORD_NOT_FOUND = 0x6a83,
+ SW_NOT_ENOUGH_MEMORY= 0x6a84, /* Not enough memory space in the file. */
+ SW_INCONSISTENT_LC = 0x6a85, /* Lc inconsistent with TLV structure. */
+ SW_INCORRECT_P0_P1 = 0x6a86,
SW_BAD_LC = 0x6a87, /* Lc does not match command or p1/p2. */
SW_REF_NOT_FOUND = 0x6a88,
SW_BAD_P0_P1 = 0x6b00,
@@ -108,7 +111,6 @@ int apdu_disconnect (int slot);
int apdu_set_progress_cb (int slot, gcry_handler_progress_t cb, void *cb_arg);
-int apdu_activate (int slot);
int apdu_reset (int slot);
int apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed);
diff --git a/scd/app-common.h b/scd/app-common.h
index 6a1e2a763..e3d23c2b4 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -143,7 +143,8 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
/*-- app.c --*/
void app_dump_state (void);
void application_notify_card_reset (int slot);
-gpg_error_t check_application_conflict (ctrl_t ctrl, const char *name);
+gpg_error_t check_application_conflict (ctrl_t ctrl, int slot,
+ const char *name);
gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name,
app_t *r_app);
char *get_supported_applications (void);
diff --git a/scd/app.c b/scd/app.c
index 97260082e..79e3eac0f 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -198,18 +198,19 @@ application_notify_card_reset (int slot)
used to request a specific application and the connection has
already done a select_application. */
gpg_error_t
-check_application_conflict (ctrl_t ctrl, const char *name)
+check_application_conflict (ctrl_t ctrl, int slot, const char *name)
{
- int slot = ctrl->reader_slot;
app_t app;
+ (void)ctrl;
+
if (slot < 0 || slot >= DIM (lock_table))
return gpg_error (GPG_ERR_INV_VALUE);
app = lock_table[slot].initialized ? lock_table[slot].app : NULL;
if (app && app->apptype && name)
if ( ascii_strcasecmp (app->apptype, name))
- return gpg_error (GPG_ERR_CONFLICT);
+ return gpg_error (GPG_ERR_CONFLICT);
return 0;
}
@@ -226,11 +227,14 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
app_t app = NULL;
unsigned char *result = NULL;
size_t resultlen;
+ int want_undefined;
(void)ctrl;
*r_app = NULL;
+ want_undefined = (name && !strcmp (name, "undefined"));
+
err = lock_reader (slot, ctrl);
if (err)
return err;
@@ -310,45 +314,49 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
/* Fixme: We should now first check whether a card is at all
present. */
- /* Try to read the GDO file first to get a default serial number. */
- err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
- if (!err)
- err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
- if (!err)
- err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
- if (!err)
+ /* Try to read the GDO file first to get a default serial number.
+ We skip this if the undefined application has been requested. */
+ if (!want_undefined)
{
- size_t n;
- const unsigned char *p;
-
- p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
- if (p)
- resultlen -= (p-result);
- if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
+ err = iso7816_select_file (slot, 0x3F00, 1, NULL, NULL);
+ if (!err)
+ err = iso7816_select_file (slot, 0x2F02, 0, NULL, NULL);
+ if (!err)
+ err = iso7816_read_binary (slot, 0, 0, &result, &resultlen);
+ if (!err)
{
- /* The object it does not fit into the buffer. This is an
- invalid encoding (or the buffer is too short. However, I
- have some test cards with such an invalid encoding and
- therefore I use this ugly workaround to return something
- I can further experiment with. */
- log_info ("enabling BMI testcard workaround\n");
- n--;
+ size_t n;
+ const unsigned char *p;
+
+ p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
+ if (p)
+ resultlen -= (p-result);
+ if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
+ {
+ /* The object it does not fit into the buffer. This is an
+ invalid encoding (or the buffer is too short. However, I
+ have some test cards with such an invalid encoding and
+ therefore I use this ugly workaround to return something
+ I can further experiment with. */
+ log_info ("enabling BMI testcard workaround\n");
+ n--;
+ }
+
+ if (p && n <= resultlen)
+ {
+ /* The GDO file is pretty short, thus we simply reuse it for
+ storing the serial number. */
+ memmove (result, p, n);
+ app->serialno = result;
+ app->serialnolen = n;
+ err = app_munge_serialno (app);
+ if (err)
+ goto leave;
+ }
+ else
+ xfree (result);
+ result = NULL;
}
-
- if (p && n <= resultlen)
- {
- /* The GDO file is pretty short, thus we simply reuse it for
- storing the serial number. */
- memmove (result, p, n);
- app->serialno = result;
- app->serialnolen = n;
- err = app_munge_serialno (app);
- if (err)
- goto leave;
- }
- else
- xfree (result);
- result = NULL;
}
/* For certain error codes, there is no need to try more. */
@@ -357,7 +365,15 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
goto leave;
/* Figure out the application to use. */
- err = gpg_error (GPG_ERR_NOT_FOUND);
+ if (want_undefined)
+ {
+ /* We switch to the "undefined" application only if explicitly
+ requested. */
+ app->apptype = "UNDEFINED";
+ err = 0;
+ }
+ else
+ err = gpg_error (GPG_ERR_NOT_FOUND);
if (err && is_app_allowed ("openpgp")
&& (!name || !strcmp (name, "openpgp")))
@@ -366,11 +382,11 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
err = app_select_nks (app);
if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
err = app_select_p15 (app);
- if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
- err = app_select_dinsig (app);
if (err && is_app_allowed ("geldkarte")
&& (!name || !strcmp (name, "geldkarte")))
err = app_select_geldkarte (app);
+ if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
+ err = app_select_dinsig (app);
if (err && name)
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
@@ -404,8 +420,10 @@ get_supported_applications (void)
"openpgp",
"nks",
"p15",
- "dinsig",
"geldkarte",
+ "dinsig",
+ /* Note: "undefined" is not listed here because it needs special
+ treatment by the client. */
NULL
};
int idx;
diff --git a/scd/atr.c b/scd/atr.c
index 16f26fb7d..b8668a41d 100644
--- a/scd/atr.c
+++ b/scd/atr.c
@@ -1,5 +1,5 @@
/* atr.c - ISO 7816 ATR fucntions
- * Copyright (C) 2003 Free Software Foundation, Inc.
+ * Copyright (C) 2003, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -24,10 +24,9 @@
#include <string.h>
#include <assert.h>
-#include "scdaemon.h"
-#include "apdu.h"
+#include "../common/estream.h"
+#include "../common/logging.h"
#include "atr.h"
-#include "dynload.h"
static int const fi_table[16] = { 0, 372, 558, 744, 1116,1488, 1860, -1,
-1, 512, 768, 1024, 1536, 2048, -1, -1 };
@@ -35,37 +34,42 @@ static int const di_table[16] = { -1, 1, 2, 4, 8, 16, -1, -1,
0, -1, -2, -4, -8, -16, -32, -64};
-/* Dump the ATR of the card at SLOT in a human readable format to
- stream FP. */
-int
-atr_dump (int slot, FILE *fp)
+/* Dump the ATR in (BUFFER,BUFLEN) to a human readable format and
+ return that as a malloced buffer. The caller must release this
+ buffer using es_free! On error this function returns NULL and sets
+ ERRNO. */
+char *
+atr_dump (const void *buffer, size_t buflen)
{
- unsigned char *atrbuffer, *atr;
- size_t atrlen;
+ const unsigned char *atr = buffer;
+ size_t atrlen = buflen;
+ estream_t fp;
int have_ta, have_tb, have_tc, have_td;
int n_historical;
int idx, val;
unsigned char chksum;
+ char *result;
- atr = atrbuffer = apdu_get_atr (slot, &atrlen);
- if (!atr)
- return gpg_error (GPG_ERR_GENERAL);
+ fp = es_fopenmem (0, "rwb");
+ if (!fp)
+ return NULL;
- fprintf (fp, "Info on ATR of length %u at slot %d\n",
- (unsigned int)atrlen, slot);
if (!atrlen)
{
- fprintf (fp, "error: empty ATR\n");
+ es_fprintf (fp, "error: empty ATR\n");
goto bailout;
}
+ for (idx=0; idx < atrlen ; idx++)
+ es_fprintf (fp, "%s%02X", idx?" ":"", atr[idx]);
+ es_putc ('\n', fp);
if (*atr == 0x3b)
- fputs ("direct convention\n", fp);
+ es_fputs ("Direct convention\n", fp);
else if (*atr == 0x3f)
- fputs ("inverse convention\n", fp);
+ es_fputs ("Inverse convention\n", fp);
else
- fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
+ es_fprintf (fp,"error: invalid TS character 0x%02x\n", *atr);
if (!--atrlen)
goto bailout;
atr++;
@@ -79,34 +83,34 @@ atr_dump (int slot, FILE *fp)
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
n_historical = (*atr & 0x0f);
- fprintf (fp, "%d historical characters indicated\n", n_historical);
+ es_fprintf (fp, "%d historical characters indicated\n", n_historical);
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
- fputs ("error: ATR shorter than indicated by format character\n", fp);
+ es_fputs ("error: ATR shorter than indicated by format character\n", fp);
if (!--atrlen)
goto bailout;
atr++;
if (have_ta)
{
- fputs ("TA1: F=", fp);
+ es_fputs ("TA1: F=", fp);
val = fi_table[(*atr >> 4) & 0x0f];
if (!val)
- fputs ("internal clock", fp);
+ es_fputs ("internal clock", fp);
else if (val == -1)
- fputs ("RFU", fp);
+ es_fputs ("RFU", fp);
else
- fprintf (fp, "%d", val);
- fputs (" D=", fp);
+ es_fprintf (fp, "%d", val);
+ es_fputs (" D=", fp);
val = di_table[*atr & 0x0f];
if (!val)
- fputs ("[impossible value]\n", fp);
+ es_fputs ("[impossible value]\n", fp);
else if (val == -1)
- fputs ("RFU\n", fp);
+ es_fputs ("RFU\n", fp);
else if (val < 0 )
- fprintf (fp, "1/%d\n", val);
+ es_fprintf (fp, "1/%d\n", val);
else
- fprintf (fp, "%d\n", val);
+ es_fprintf (fp, "%d\n", val);
if (!--atrlen)
goto bailout;
@@ -115,8 +119,9 @@ atr_dump (int slot, FILE *fp)
if (have_tb)
{
- fprintf (fp, "TB1: II=%d PI1=%d%s\n", (*atr >> 5) & 3, *atr & 0x1f,
- (*atr & 0x80)? " [high bit not cleared]":"");
+ es_fprintf (fp, "TB1: II=%d PI1=%d%s\n",
+ ((*atr >> 5) & 3), (*atr & 0x1f),
+ (*atr & 0x80)? " [high bit not cleared]":"");
if (!--atrlen)
goto bailout;
atr++;
@@ -125,9 +130,9 @@ atr_dump (int slot, FILE *fp)
if (have_tc)
{
if (*atr == 255)
- fputs ("TC1: guard time shortened to 1 etu\n", fp);
+ es_fputs ("TC1: guard time shortened to 1 etu\n", fp);
else
- fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
+ es_fprintf (fp, "TC1: (extra guard time) N=%d\n", *atr);
if (!--atrlen)
goto bailout;
@@ -140,10 +145,11 @@ atr_dump (int slot, FILE *fp)
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
- fprintf (fp, "TD1: protocol T%d supported\n", *atr & 0x0f);
+ es_fprintf (fp, "TD1: protocol T%d supported\n", (*atr & 0x0f));
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
- fputs ("error: ATR shorter than indicated by format character\n", fp);
+ es_fputs ("error: ATR shorter than indicated by format character\n",
+ fp);
if (!--atrlen)
goto bailout;
@@ -154,12 +160,12 @@ atr_dump (int slot, FILE *fp)
if (have_ta)
{
- fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
- (*atr & 0x80)? "no-":"",
- (*atr & 0x10)? "im": "ex",
- (*atr & 0x0f));
+ es_fprintf (fp, "TA2: (PTS) %stoggle, %splicit, T=%02X\n",
+ (*atr & 0x80)? "no-":"",
+ (*atr & 0x10)? "im": "ex",
+ (*atr & 0x0f));
if ((*atr & 0x60))
- fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
+ es_fprintf (fp, "note: reserved bits are set (TA2=0x%02X)\n", *atr);
if (!--atrlen)
goto bailout;
atr++;
@@ -167,7 +173,7 @@ atr_dump (int slot, FILE *fp)
if (have_tb)
{
- fprintf (fp, "TB2: PI2=%d\n", *atr);
+ es_fprintf (fp, "TB2: PI2=%d\n", *atr);
if (!--atrlen)
goto bailout;
atr++;
@@ -175,7 +181,7 @@ atr_dump (int slot, FILE *fp)
if (have_tc)
{
- fprintf (fp, "TC2: PWI=%d\n", *atr);
+ es_fprintf (fp, "TC2: PWI=%d\n", *atr);
if (!--atrlen)
goto bailout;
atr++;
@@ -187,10 +193,11 @@ atr_dump (int slot, FILE *fp)
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
- fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
+ es_fprintf (fp, "TD2: protocol T%d supported\n", *atr & 0x0f);
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
- fputs ("error: ATR shorter than indicated by format character\n", fp);
+ es_fputs ("error: ATR shorter than indicated by format character\n",
+ fp);
if (!--atrlen)
goto bailout;
@@ -203,7 +210,7 @@ atr_dump (int slot, FILE *fp)
{
if (have_ta)
{
- fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
+ es_fprintf (fp, "TA%d: IFSC=%d\n", idx, *atr);
if (!--atrlen)
goto bailout;
atr++;
@@ -211,7 +218,7 @@ atr_dump (int slot, FILE *fp)
if (have_tb)
{
- fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
+ es_fprintf (fp, "TB%d: BWI=%d CWI=%d\n",
idx, (*atr >> 4) & 0x0f, *atr & 0x0f);
if (!--atrlen)
goto bailout;
@@ -220,7 +227,7 @@ atr_dump (int slot, FILE *fp)
if (have_tc)
{
- fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
+ es_fprintf (fp, "TC%d: 0x%02X\n", idx, *atr);
if (!--atrlen)
goto bailout;
atr++;
@@ -232,11 +239,12 @@ atr_dump (int slot, FILE *fp)
have_tb = !!(*atr & 0x20);
have_tc = !!(*atr & 0x40);
have_td = !!(*atr & 0x80);
- fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
+ es_fprintf (fp, "TD%d: protocol T%d supported\n", idx, *atr & 0x0f);
if (have_ta + have_tb + have_tc + have_td + n_historical > atrlen)
- fputs ("error: ATR shorter than indicated by format character\n",
- fp);
+ es_fputs ("error: "
+ "ATR shorter than indicated by format character\n",
+ fp);
if (!--atrlen)
goto bailout;
@@ -247,150 +255,36 @@ atr_dump (int slot, FILE *fp)
}
if (n_historical + 1 > atrlen)
- fputs ("error: ATR shorter than required for historical bytes "
- "and checksum\n", fp);
+ es_fputs ("error: ATR shorter than required for historical bytes "
+ "and checksum\n", fp);
if (n_historical)
{
- fputs ("Historical:", fp);
+ es_fputs ("HCH:", fp);
for (; n_historical && atrlen ; n_historical--, atrlen--, atr++)
- fprintf (fp, " %02X", *atr);
- putchar ('\n');
+ es_fprintf (fp, " %02X", *atr);
+ es_putc ('\n', fp);
}
if (!atrlen)
- fputs ("error: checksum missing\n", fp);
+ es_fputs ("error: checksum missing\n", fp);
else if (*atr == chksum)
- fprintf (fp, "TCK: %02X (good)\n", *atr);
+ es_fprintf (fp, "TCK: %02X (good)\n", *atr);
else
- fprintf (fp, "TCK: %02X (bad; calculated %02X)\n", *atr, chksum);
+ es_fprintf (fp, "TCK: %02X (bad; computed %02X)\n", *atr, chksum);
atrlen--;
if (atrlen)
- fprintf (fp, "error: %u bytes garbage at end of ATR\n",
- (unsigned int)atrlen );
+ es_fprintf (fp, "error: %u bytes garbage at end of ATR\n",
+ (unsigned int)atrlen );
bailout:
- xfree (atrbuffer);
-
- return 0;
-}
-
-
-/* Note: This code has not yet been tested! It shall return -1 on
- error or the number of historical bytes and store them at
- HISTORICAL. */
-int
-atr_get_historical (int slot, unsigned char historical[])
-{
- int result = -1;
- unsigned char *atrbuffer = NULL;
- unsigned char *atr;
- size_t atrlen;
- int have_ta, have_tb, have_tc, have_td;
- int n_historical;
- int idx;
- unsigned char chksum;
-
- atr = atrbuffer = apdu_get_atr (slot, &atrlen);
- if (!atr || atrlen < 2)
- goto leave;
- atrlen--;
- atr++;
-
- chksum = *atr;
- for (idx=1; idx < atrlen-1; idx++)
- chksum ^= atr[idx];
-
- have_ta = !!(*atr & 0x10);
- have_tb = !!(*atr & 0x20);
- have_tc = !!(*atr & 0x40);
- have_td = !!(*atr & 0x80);
- n_historical = (*atr & 0x0f);
-
- if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
- goto leave; /* ATR shorter than indicated by format character. */
- atrlen--;
- atr++;
-
- if (have_ta + have_tb + have_tc >= atrlen)
- goto leave;
- atrlen -= have_ta + have_tb + have_tc;
- atr += have_ta + have_tb + have_tc;
-
- if (have_td)
- {
- 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 (have_ta + have_tb + have_tc >= atrlen)
- goto leave;
- atrlen -= have_ta + have_tb + have_tc;
- atr += have_ta + have_tb + have_tc;
-
- if (have_td)
+ es_putc ('\0', fp); /* We want a string. */
+ if (es_fclose_snatch (fp, (void**)&result, NULL))
{
- have_ta = !!(*atr & 0x10);
- have_tb = !!(*atr & 0x20);
- have_tc = !!(*atr & 0x40);
- have_td = !!(*atr & 0x80);
- if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
- goto leave; /* ATR shorter than indicated by format character. */
- atrlen--;
- atr++;
+ log_error ("oops: es_fclose_snatch failed: %s\n", strerror (errno));
+ return NULL;
}
- else
- have_ta = have_tb = have_tc = have_td = 0;
-
- 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;
}
diff --git a/scd/atr.h b/scd/atr.h
index 5f07522d1..b06a83a60 100644
--- a/scd/atr.h
+++ b/scd/atr.h
@@ -20,7 +20,7 @@
#ifndef ATR_H
#define ATR_H
-int atr_dump (int slot, FILE *fp);
+char *atr_dump (const void *buffer, size_t buflen);
diff --git a/scd/command.c b/scd/command.c
index fe409d560..5e7feb5be 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -1,6 +1,6 @@
/* command.c - SCdaemon command handler
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
- * 2007, 2008, 2009 Free Software Foundation, Inc.
+ * 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -35,11 +35,13 @@
#include <ksba.h>
#include "app-common.h"
#include "apdu.h" /* Required for apdu_*_reader (). */
+#include "atr.h"
#include "exechelp.h"
#ifdef HAVE_LIBUSB
#include "ccid-driver.h"
#endif
+
/* Maximum length allowed as a PIN; used for INQUIRE NEEDPIN */
#define MAXLEN_PIN 100
@@ -60,33 +62,39 @@
int _r = (r); \
if (gpg_err_code (_r) == GPG_ERR_CARD_NOT_PRESENT \
|| gpg_err_code (_r) == GPG_ERR_CARD_REMOVED \
+ || gpg_err_code (_r) == GPG_ERR_CARD_RESET \
|| gpg_err_code (_r) == GPG_ERR_ENODEV ) \
- update_card_removed ((c)->reader_slot, 1); \
+ update_card_removed ((c)->server_local->vreader_idx, 1); \
} while (0)
-#define IS_LOCKED(c) \
- (locked_session && locked_session != (c)->server_local \
- && (c)->reader_slot != -1 && locked_session->ctrl_backlink \
- && (c)->reader_slot == locked_session->ctrl_backlink->reader_slot)
+#define IS_LOCKED(c) \
+ (locked_session \
+ && locked_session != (c)->server_local \
+ && (c)->server_local->vreader_idx != -1 \
+ && locked_session->ctrl_backlink \
+ && ((c)->server_local->vreader_idx \
+ == locked_session->ctrl_backlink->server_local->vreader_idx))
/* Flag indicating that the reader has been disabled. */
static int reader_disabled;
-/* This structure is used to keep track of open readers (slots). */
-struct slot_status_s
+/* This structure is used to keep track of user readers. To
+ eventually accommodate this structure for RFID cards, where more
+ than one card is used per reader, we name it virtual reader. */
+struct vreader_s
{
int valid; /* True if the other objects are valid. */
- int slot; /* Slot number of the reader or -1 if not open. */
+ int slot; /* APDU slot number of the reader or -1 if not open. */
int reset_failed; /* A reset failed. */
int any; /* Flag indicating whether any status check has been
done. This is set once to indicate that the status
tracking for the slot has been initialized. */
- unsigned int status; /* Last status of the slot. */
- unsigned int changed; /* Last change counter of the slot. */
+ unsigned int status; /* Last status of the reader. */
+ unsigned int changed; /* Last change counter of the reader. */
};
@@ -113,6 +121,9 @@ struct server_local_s
int event_signal; /* Or 0 if not used. */
#endif
+ /* Index into the vreader table (command.c) or -1 if not open. */
+ int vreader_idx;
+
/* True if the card has been removed and a reset is required to
continue operation. */
int card_removed;
@@ -131,10 +142,8 @@ struct server_local_s
};
-/* The table with information on all used slots. FIXME: This is a
- different slot number than the one used by the APDU layer, and
- should be renamed. */
-static struct slot_status_s slot_table[10];
+/* The table with information on all used virtual readers. */
+static struct vreader_s vreader_table[10];
/* To keep track of all running sessions, we link all active server
@@ -175,26 +184,41 @@ initialize_module_command (void)
}
-/* Update the CARD_REMOVED element of all sessions using the reader
- given by SLOT to VALUE. */
+/* Helper to return the slot number for a given virtual reader index
+ VRDR. In case on an error -1 is returned. */
+static int
+vreader_slot (int vrdr)
+{
+ if (vrdr == -1 || !(vrdr >= 0 && vrdr < DIM(vreader_table)))
+ return -1;
+ if (!vreader_table [vrdr].valid)
+ return -1;
+ return vreader_table[vrdr].slot;
+}
+
+
+/* Update the CARD_REMOVED element of all sessions using the virtual
+ reader given by VRDR to VALUE. */
static void
-update_card_removed (int slot, int value)
+update_card_removed (int vrdr, int value)
{
struct server_local_s *sl;
+ if (vrdr == -1)
+ return;
+
for (sl=session_list; sl; sl = sl->next_session)
if (sl->ctrl_backlink
- && sl->ctrl_backlink->reader_slot == slot)
+ && sl->ctrl_backlink->server_local->vreader_idx == vrdr)
{
sl->card_removed = value;
}
/* Let the card application layer know about the removal. */
if (value)
- application_notify_card_reset (slot);
+ application_notify_card_reset (vreader_slot (vrdr));
}
-
/* Check whether the option NAME appears in LINE. Returns 1 or 0. */
static int
has_option (const char *line, const char *name)
@@ -280,10 +304,10 @@ hex_to_buffer (const char *string, size_t *r_length)
static void
do_reset (ctrl_t ctrl, int send_reset)
{
- int slot = ctrl->reader_slot;
- int err;
+ int vrdr = ctrl->server_local->vreader_idx;
+ int slot;
- if (!(slot == -1 || (slot >= 0 && slot < DIM(slot_table))))
+ if (!(vrdr == -1 || (vrdr >= 0 && vrdr < DIM(vreader_table))))
BUG ();
/* If there is an active application, release it. Tell all other
@@ -299,7 +323,7 @@ do_reset (ctrl_t ctrl, int send_reset)
for (sl=session_list; sl; sl = sl->next_session)
if (sl->ctrl_backlink
- && sl->ctrl_backlink->reader_slot == slot)
+ && sl->ctrl_backlink->server_local->vreader_idx == vrdr)
{
sl->app_ctx_marked_for_release = 1;
}
@@ -308,13 +332,22 @@ do_reset (ctrl_t ctrl, int send_reset)
/* If we want a real reset for the card, send the reset APDU and
tell the application layer about it. */
+ slot = vreader_slot (vrdr);
if (slot != -1 && send_reset && !IS_LOCKED (ctrl) )
{
- if (apdu_reset (slot))
+ application_notify_card_reset (slot);
+ switch (apdu_reset (slot))
{
- slot_table[slot].valid = 0;
+ 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;
}
- application_notify_card_reset (slot);
}
/* If we hold a lock, unlock now. */
@@ -327,25 +360,24 @@ do_reset (ctrl_t ctrl, int send_reset)
/* Reset the card removed flag for the current reader. We need to
take the lock here so that the ticker thread won't concurrently
try to update the file. Calling update_reader_status_file is
- required to get hold of the new status of the card in the slot
+ required to get hold of the new status of the card in the vreader
table. */
err = npth_mutex_lock (&status_file_update_lock);
if (err)
{
- log_error ("failed to acquire status_fle_update lock: %s\n",
- strerror (err));
- ctrl->reader_slot = -1;
+ log_error ("failed to acquire status_file_update lock\n");
+ ctrl->server_local->vreader_idx = -1;
return;
}
update_reader_status_file (0); /* Update slot status table. */
- update_card_removed (slot, 0); /* Clear card_removed flag. */
+ update_card_removed (vrdr, 0); /* Clear card_removed flag. */
err = npth_mutex_unlock (&status_file_update_lock);
if (err)
log_error ("failed to release status_file_update lock: %s\n",
strerror (err));
/* Do this last, so that the update_card_removed above does its job. */
- ctrl->reader_slot = -1;
+ ctrl->server_local->vreader_idx = -1;
}
@@ -385,35 +417,38 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
}
-/* Return the slot of the current reader or open the reader if no
- other sessions are using a reader. Note, that we currently support
+/* Return the index of the current reader or open the reader if no
+ other sessions are using that reader. If it is not possible to
+ open the reader -1 is returned. Note, that we currently support
only one reader but most of the code (except for this function)
should be able to cope with several readers. */
static int
-get_reader_slot (void)
+get_current_reader (void)
{
- struct slot_status_s *ss;
+ struct vreader_s *vr;
- ss = &slot_table[0]; /* One reader for now. */
+ /* We only support one reader for now. */
+ vr = &vreader_table[0];
- /* Initialize the item if needed. */
- if (!ss->valid)
+ /* Initialize the vreader item if not yet done. */
+ if (!vr->valid)
{
- ss->slot = -1;
- ss->valid = 1;
+ vr->slot = -1;
+ vr->valid = 1;
}
/* Try to open the reader. */
- if (ss->slot == -1)
+ if (vr->slot == -1)
{
int no_service_flag;
- ss->slot = apdu_open_reader (opt.reader_port, &no_service_flag);
+
+ vr->slot = apdu_open_reader (opt.reader_port, &no_service_flag);
/* If we still don't have a slot, we have no readers.
Invalidate for now until a reader is attached. */
- if(ss->slot == -1)
+ if (vr->slot == -1)
{
- ss->valid = 0;
+ vr->valid = 0;
}
if (no_service_flag)
@@ -423,18 +458,17 @@ get_reader_slot (void)
}
}
- /* Return the slot_table index. */
- return 0;
+ /* Return the vreader index or -1. */
+ return vr->valid ? 0 : -1;
}
-/* If the card has not yet been opened, do it. Note that this
- function returns an Assuan error, so don't map the error a second
- time. */
+
+/* If the card has not yet been opened, do it. */
static gpg_error_t
open_card (ctrl_t ctrl, const char *apptype)
{
gpg_error_t err;
- int slot;
+ int vrdr;
if (reader_disabled)
return gpg_error (GPG_ERR_NOT_OPERATIONAL);
@@ -462,21 +496,25 @@ open_card (ctrl_t ctrl, const char *apptype)
need to check that the client didn't requested a specific
application different from the one in use before we continue. */
if (ctrl->app_ctx)
- return check_application_conflict (ctrl, apptype);
+ {
+ return check_application_conflict
+ (ctrl, vreader_slot (ctrl->server_local->vreader_idx), apptype);
+ }
- /* Setup the slot and select the application. */
- if (ctrl->reader_slot != -1)
- slot = ctrl->reader_slot;
+ /* Setup the vreader and select the application. */
+ if (ctrl->server_local->vreader_idx != -1)
+ vrdr = ctrl->server_local->vreader_idx;
else
- slot = get_reader_slot ();
- ctrl->reader_slot = slot;
- if (slot == -1)
+ vrdr = get_current_reader ();
+ ctrl->server_local->vreader_idx = vrdr;
+ if (vrdr == -1)
err = gpg_error (reader_disabled? GPG_ERR_NOT_OPERATIONAL: GPG_ERR_CARD);
else
{
/* Fixme: We should move the apdu_connect call to
select_application. */
int sw;
+ int slot = vreader_slot (vrdr);
ctrl->server_local->disconnect_allowed = 0;
sw = apdu_connect (slot);
@@ -484,6 +522,8 @@ open_card (ctrl_t ctrl, const char *apptype)
{
if (sw == SW_HOST_NO_CARD)
err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
+ else if (sw == SW_HOST_CARD_INACTIVE)
+ err = gpg_error (GPG_ERR_CARD_RESET);
else
err = gpg_error (GPG_ERR_CARD);
}
@@ -523,8 +563,10 @@ cmd_serialno (assuan_context_t ctx, char *line)
char *serial_and_stamp;
char *serial;
time_t stamp;
+ int retries = 0;
/* Clear the remove flag so that the open_card is able to reread it. */
+ retry:
if (!reader_disabled && ctrl->server_local->card_removed)
{
if ( IS_LOCKED (ctrl) )
@@ -533,7 +575,12 @@ cmd_serialno (assuan_context_t ctx, char *line)
}
if ((rc = open_card (ctrl, *line? line:NULL)))
- return rc;
+ {
+ /* In case of an inactive card, retry once. */
+ if (gpg_err_code (rc) == GPG_ERR_CARD_RESET && retries++ < 1)
+ goto retry;
+ return rc;
+ }
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
if (rc)
@@ -1613,8 +1660,8 @@ static const char hlp_getinfo[] =
"\n"
"socket_name - Return the name of the socket.\n"
"\n"
- "status - Return the status of the current slot (in the future, may\n"
- "also return the status of all slots). The status is a list of\n"
+ "status - Return the status of the current reader (in the future, may\n"
+ "also return the status of all readers). The status is a list of\n"
"one-character flags. The following flags are currently defined:\n"
" 'u' Usable card present. This is the normal state during operation.\n"
" 'r' Card removed. A reset is necessary.\n"
@@ -1658,22 +1705,18 @@ cmd_getinfo (assuan_context_t ctx, char *line)
else if (!strcmp (line, "status"))
{
ctrl_t ctrl = assuan_get_pointer (ctx);
- int slot = ctrl->reader_slot;
+ int vrdr = ctrl->server_local->vreader_idx;
char flag = 'r';
- if (!ctrl->server_local->card_removed && slot != -1)
+ if (!ctrl->server_local->card_removed && vrdr != -1)
{
- struct slot_status_s *ss;
+ struct vreader_s *vr;
- if (!(slot >= 0 && slot < DIM(slot_table)))
+ if (!(vrdr >= 0 && vrdr < DIM(vreader_table)))
BUG ();
- ss = &slot_table[slot];
-
- if (!ss->valid)
- BUG ();
-
- if (ss->any && (ss->status & 1))
+ vr = &vreader_table[vrdr];
+ if (vr->valid && vr->any && (vr->status & 1))
flag = 'u';
}
rc = assuan_send_data (ctx, &flag, 1);
@@ -1759,7 +1802,7 @@ cmd_disconnect (assuan_context_t ctx, char *line)
static const char hlp_apdu[] =
- "APDU [--atr] [--more] [--exlen[=N]] [hexstring]\n"
+ "APDU [--[dump-]atr] [--more] [--exlen[=N]] [hexstring]\n"
"\n"
"Send an APDU to the current reader. This command bypasses the high\n"
"level functions and sends the data directly to the card. HEXSTRING\n"
@@ -1788,8 +1831,12 @@ cmd_apdu (assuan_context_t ctx, char *line)
int handle_more;
const char *s;
size_t exlen;
+ int slot;
- with_atr = has_option (line, "--atr");
+ if (has_option (line, "--dump-atr"))
+ with_atr = 2;
+ else
+ with_atr = has_option (line, "--atr");
handle_more = has_option (line, "--more");
if ((s=has_option_name (line, "--exlen")))
@@ -1810,21 +1857,46 @@ cmd_apdu (assuan_context_t ctx, char *line)
if ((rc = open_card (ctrl, NULL)))
return rc;
+ slot = vreader_slot (ctrl->server_local->vreader_idx);
+
if (with_atr)
{
unsigned char *atr;
size_t atrlen;
char hexbuf[400];
- atr = apdu_get_atr (ctrl->reader_slot, &atrlen);
+ atr = apdu_get_atr (slot, &atrlen);
if (!atr || atrlen > sizeof hexbuf - 2 )
{
rc = gpg_error (GPG_ERR_INV_CARD);
goto leave;
}
- bin2hex (atr, atrlen, hexbuf);
+ if (with_atr == 2)
+ {
+ char *string, *p, *pend;
+
+ string = atr_dump (atr, atrlen);
+ if (string)
+ {
+ for (rc=0, p=string; !rc && (pend = strchr (p, '\n')); p = pend+1)
+ {
+ rc = assuan_send_data (ctx, p, pend - p + 1);
+ if (!rc)
+ rc = assuan_send_data (ctx, NULL, 0);
+ }
+ if (!rc && *p)
+ rc = assuan_send_data (ctx, p, strlen (p));
+ es_free (string);
+ if (rc)
+ goto leave;
+ }
+ }
+ else
+ {
+ bin2hex (atr, atrlen, hexbuf);
+ send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
+ }
xfree (atr);
- send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
}
apdu = hex_to_buffer (line, &apdulen);
@@ -1838,7 +1910,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
unsigned char *result = NULL;
size_t resultlen;
- rc = apdu_send_direct (ctrl->reader_slot, exlen,
+ rc = apdu_send_direct (slot, exlen,
apdu, apdulen, handle_more,
&result, &resultlen);
if (rc)
@@ -1869,15 +1941,8 @@ cmd_killscd (assuan_context_t ctx, char *line)
(void)line;
ctrl->server_local->stopme = 1;
-#ifdef ASSUAN_FORCE_CLOSE
assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
return 0;
-#else
- /* Actually returning an EOF does not anymore work with modern
- Libassuan versions. However we keep that non working code until
- we make a Libassuan with the force close flag a requirement. */
- return gpg_error (GPG_ERR_EOF);
-#endif
}
@@ -1988,12 +2053,13 @@ scd_command_handler (ctrl_t ctrl, int fd)
session_list = ctrl->server_local;
ctrl->server_local->ctrl_backlink = ctrl;
ctrl->server_local->assuan_ctx = ctx;
+ ctrl->server_local->vreader_idx = -1;
/* We open the reader right at startup so that the ticker is able to
update the status file. */
- if (ctrl->reader_slot == -1)
+ if (ctrl->server_local->vreader_idx == -1)
{
- ctrl->reader_slot = get_reader_slot ();
+ ctrl->server_local->vreader_idx = get_current_reader ();
}
/* Command processing loop. */
@@ -2195,32 +2261,33 @@ update_reader_status_file (int set_card_removed_flag)
int idx;
unsigned int status, changed;
- /* Make sure that the reader has been opened. Like get_reader_slot,
+ /* Make sure that a reader has been opened. Like get_current_reader,
this part of the code assumes that there is only one reader. */
- if (!slot_table[0].valid)
- (void)get_reader_slot ();
+ if (!vreader_table[0].valid)
+ (void)get_current_reader ();
/* Note, that we only try to get the status, because it does not
make sense to wait here for a operation to complete. If we are
busy working with a card, delays in the status file update should
be acceptable. */
- for (idx=0; idx < DIM(slot_table); idx++)
+ for (idx=0; idx < DIM(vreader_table); idx++)
{
- struct slot_status_s *ss = slot_table + idx;
+ struct vreader_s *vr = vreader_table + idx;
struct server_local_s *sl;
int sw_apdu;
- if (!ss->valid || ss->slot == -1)
+ if (!vr->valid || vr->slot == -1)
continue; /* Not valid or reader not yet open. */
- sw_apdu = apdu_get_status (ss->slot, 0, &status, &changed);
+ sw_apdu = apdu_get_status (vr->slot, 0, &status, &changed);
if (sw_apdu == SW_HOST_NO_READER)
{
/* Most likely the _reader_ has been unplugged. */
- apdu_close_reader(ss->slot);
- ss->valid = 0;
+ application_notify_card_reset (vr->slot);
+ apdu_close_reader (vr->slot);
+ vr->slot = -1;
status = 0;
- changed = ss->changed;
+ changed = vr->changed;
}
else if (sw_apdu)
{
@@ -2228,21 +2295,21 @@ update_reader_status_file (int set_card_removed_flag)
continue;
}
- if (!ss->any || ss->status != status || ss->changed != changed )
+ if (!vr->any || vr->status != status || vr->changed != changed )
{
char *fname;
char templ[50];
FILE *fp;
- log_info ("updating slot %d status: 0x%04X->0x%04X (%u->%u)\n",
- ss->slot, ss->status, status, ss->changed, changed);
- ss->status = status;
- ss->changed = changed;
+ log_info ("updating reader %d (%d) status: 0x%04X->0x%04X (%u->%u)\n",
+ idx, vr->slot, vr->status, status, vr->changed, changed);
+ vr->status = status;
+ vr->changed = changed;
- /* FIXME: Should this be IDX instead of ss->slot? This
+ /* FIXME: Should this be IDX instead of vr->slot? This
depends on how client sessions will associate the reader
status with their session. */
- snprintf (templ, sizeof templ, "reader_%d.status", ss->slot);
+ snprintf (templ, sizeof templ, "reader_%d.status", vr->slot);
fname = make_filename (opt.homedir, templ, NULL );
fp = fopen (fname, "w");
if (fp)
@@ -2270,8 +2337,8 @@ update_reader_status_file (int set_card_removed_flag)
envs[0] = envstr;
envs[1] = NULL;
- sprintf (numbuf1, "%d", ss->slot);
- sprintf (numbuf2, "0x%04X", ss->status);
+ sprintf (numbuf1, "%d", vr->slot);
+ sprintf (numbuf2, "0x%04X", vr->status);
sprintf (numbuf3, "0x%04X", status);
args[0] = "--reader-port";
args[1] = numbuf1;
@@ -2299,10 +2366,10 @@ update_reader_status_file (int set_card_removed_flag)
/* Set the card removed flag for all current sessions. We
will set this on any card change because a reset or
SERIALNO request must be done in any case. */
- if (ss->any && set_card_removed_flag)
+ if (vr->any && set_card_removed_flag)
update_card_removed (idx, 1);
- ss->any = 1;
+ vr->any = 1;
/* Send a signal to all clients who applied for it. */
send_client_notifications ();
@@ -2318,8 +2385,9 @@ update_reader_status_file (int set_card_removed_flag)
{
/* FIXME: Use a real timeout. */
/* At least one connection and all allow a disconnect. */
- log_info ("disconnecting card in slot %d\n", ss->slot);
- apdu_disconnect (ss->slot);
+ log_info ("disconnecting card in reader %d (%d)\n",
+ idx, vr->slot);
+ apdu_disconnect (vr->slot);
}
}
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index 5b24a09f8..f674cfc76 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -74,6 +74,7 @@ enum cmd_and_opt_values
oDebugAllowCoreDump,
oDebugCCIDDriver,
oDebugLogTid,
+ oDebugAssuanLogCats,
oNoGreeting,
oNoOptions,
oHomedir,
@@ -123,6 +124,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oDebugCCIDDriver, "debug-ccid-driver", "@"),
ARGPARSE_s_n (oDebugDisableTicker, "debug-disable-ticker", "@"),
ARGPARSE_s_n (oDebugLogTid, "debug-log-tid", "@"),
+ ARGPARSE_p_u (oDebugAssuanLogCats, "debug-assuan-log-cats", "@"),
ARGPARSE_s_n (oNoDetach, "no-detach", N_("do not detach from the console")),
ARGPARSE_s_s (oLogFile, "log-file", N_("|FILE|write a log to FILE")),
ARGPARSE_s_s (oReaderPort, "reader-port",
@@ -542,6 +544,9 @@ main (int argc, char **argv )
case oDebugLogTid:
log_set_pid_suffix_cb (tid_log_callback);
break;
+ case oDebugAssuanLogCats:
+ set_libassuan_log_cats (pargs.r.ret_ulong);
+ break;
case oOptions:
/* config files may not be nested (silently ignore them) */
@@ -826,7 +831,7 @@ main (int argc, char **argv )
if (csh_style)
{
*strchr (infostr, '=') = ' ';
- es_printf ( "setenv %s\n", infostr);
+ es_printf ( "setenv %s;\n", infostr);
}
else
{
@@ -909,7 +914,7 @@ scd_exit (int rc)
static void
scd_init_default_ctrl (ctrl_t ctrl)
{
- ctrl->reader_slot = -1;
+ (void)ctrl;
}
static void
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index 0cf2f249d..74e8b7d44 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -72,8 +72,9 @@ struct
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_ASSUAN_VALUE 1024
+#define DBG_ASSUAN_VALUE 1024
#define DBG_CARD_IO_VALUE 2048
+#define DBG_READER_VALUE 4096 /* Trace reader related functions. */
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
@@ -82,6 +83,7 @@ struct
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
#define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE)
+#define DBG_READER (opt.debug & DBG_READER_VALUE)
struct server_local_s;
struct app_ctx_s;
@@ -97,9 +99,6 @@ struct server_control_s
/* Local data of the server; used only in command.c. */
struct server_local_s *server_local;
- /* Slot of the open reader or -1 if not open. */
- int reader_slot;
-
/* The application context used with this connection or NULL if none
associated. Note that this is shared with the other connections:
All connections accessing the same reader are using the same
diff --git a/scripts/gitlog-to-changelog b/scripts/gitlog-to-changelog
index 40a803554..d9f594f86 100755
--- a/scripts/gitlog-to-changelog
+++ b/scripts/gitlog-to-changelog
@@ -64,6 +64,7 @@ OPTIONS:
makes a change to SHA1's commit log text or metadata.
--append-dot append a dot to the first line of each commit message if
there is no other punctuation or blank at the end.
+ --tear-off tear off all commit log lines after a '--' line.
--since=DATE convert only the logs since DATE;
the default is to convert all log entries.
--format=FMT set format string for commit subject and body;
@@ -175,6 +176,7 @@ sub parse_amend_file($)
my $format_string = '%s%n%b%n';
my $amend_file;
my $append_dot = 0;
+ my $tear_off = 0;
GetOptions
(
help => sub { usage 0 },
@@ -183,6 +185,7 @@ sub parse_amend_file($)
'format=s' => \$format_string,
'amend=s' => \$amend_file,
'append-dot' => \$append_dot,
+ 'tear-off' => \$tear_off,
) or usage 1;
@@ -281,6 +284,18 @@ sub parse_amend_file($)
@line = grep !/^Signed-off-by: .*>$/, @line;
@line = grep !/^Co-authored-by: /, @line;
+ # Remove everything after a line with 2 dashes at the beginning.
+ if ($tear_off)
+ {
+ my @tmpline;
+ foreach (@line)
+ {
+ last if /^--\s*$/;
+ push @tmpline,$_;
+ }
+ @line = @tmpline;
+ }
+
# Remove leading and trailing blank lines.
if (@line)
{
diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c
index cdaa9dcfa..92f7a0e2c 100644
--- a/sm/call-dirmngr.c
+++ b/sm/call-dirmngr.c
@@ -816,7 +816,7 @@ get_cached_cert (assuan_context_t ctx,
char hexfpr[2*20+1];
struct membuf mb;
char *buf;
- size_t buflen;
+ size_t buflen = 0;
ksba_cert_t cert;
*r_cert = NULL;
diff --git a/sm/certchain.c b/sm/certchain.c
index 1a2632504..54c7a5772 100644
--- a/sm/certchain.c
+++ b/sm/certchain.c
@@ -1,6 +1,6 @@
/* certchain.c - certificate chain validation
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
- * 2006, 2007, 2008 Free Software Foundation, Inc.
+ * 2006, 2007, 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -1193,6 +1193,7 @@ ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode)
VALIDATE_FLAG_NO_DIRMNGR - Do not do any dirmngr isvalid checks.
VALIDATE_FLAG_CHAIN_MODEL - Check according to chain model.
+ VALIDATE_FLAG_STEED - Check according to the STEED model.
*/
static int
do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
@@ -1305,13 +1306,21 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
We used to do this only later but changed it to call the
check right here so that we can access special flags
associated with that specific root certificate. */
- istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, NULL,
- rootca_flags);
+ if (gpgsm_cert_has_well_known_private_key (subject_cert))
+ {
+ memset (rootca_flags, 0, sizeof *rootca_flags);
+ istrusted_rc = ((flags & VALIDATE_FLAG_STEED)
+ ? 0 : gpg_error (GPG_ERR_NOT_TRUSTED));
+ }
+ else
+ istrusted_rc = gpgsm_agent_istrusted (ctrl, subject_cert, NULL,
+ rootca_flags);
audit_log_cert (ctrl->audit, AUDIT_ROOT_TRUSTED,
subject_cert, istrusted_rc);
/* If the chain model extended attribute is used, make sure
that our chain model flag is set. */
- if (has_validation_model_chain (subject_cert, listmode, listfp))
+ if (!(flags & VALIDATE_FLAG_STEED)
+ && has_validation_model_chain (subject_cert, listmode, listfp))
rootca_flags->chain_model = 1;
}
@@ -1383,7 +1392,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
/* Set the flag for qualified signatures. This flag is
deduced from a list of root certificates allowed for
qualified signatures. */
- if (is_qualified == -1)
+ if (is_qualified == -1 && !(flags & VALIDATE_FLAG_STEED))
{
gpg_error_t err;
size_t buflen;
@@ -1437,8 +1446,11 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
expired it does not make much sense to ask the user
whether we wants to trust the root certificate. We
should do this only if the certificate under question
- will then be usable. */
+ will then be usable. If the certificate has a well
+ known private key asking the user does not make any
+ sense. */
if ( !any_expired
+ && !gpgsm_cert_has_well_known_private_key (subject_cert)
&& (!listmode || !already_asked_marktrusted (subject_cert))
&& ask_marktrusted (ctrl, subject_cert, listmode) )
rc = 0;
@@ -1455,6 +1467,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
/* Check for revocations etc. */
if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
;
+ else if ((flags & VALIDATE_FLAG_STEED))
+ ; /* Fixme: check revocations via DNS. */
else if (opt.no_trusted_cert_crl_check || rootca_flags->relax)
;
else
@@ -1586,8 +1600,16 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
performance reasons. */
if (is_root)
{
- istrusted_rc = gpgsm_agent_istrusted (ctrl, issuer_cert, NULL,
- rootca_flags);
+ if (gpgsm_cert_has_well_known_private_key (issuer_cert))
+ {
+ memset (rootca_flags, 0, sizeof *rootca_flags);
+ istrusted_rc = ((flags & VALIDATE_FLAG_STEED)
+ ? 0 : gpg_error (GPG_ERR_NOT_TRUSTED));
+ }
+ else
+ istrusted_rc = gpgsm_agent_istrusted
+ (ctrl, issuer_cert, NULL, rootca_flags);
+
if (!istrusted_rc && rootca_flags->relax)
{
/* Ignore the error due to the relax flag. */
@@ -1627,6 +1649,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
be fixed. */
if ((flags & VALIDATE_FLAG_NO_DIRMNGR))
rc = 0;
+ else if ((flags & VALIDATE_FLAG_STEED))
+ rc = 0; /* Fixme: XXX */
else if (is_root && (opt.no_trusted_cert_crl_check
|| (!istrusted_rc && rootca_flags->relax)))
rc = 0;
@@ -1722,7 +1746,7 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
capability of the certificate under question, store the result as
user data in all certificates of the chain. We do this even if the
validation itself failed. */
- if (is_qualified != -1)
+ if (is_qualified != -1 && !(flags & VALIDATE_FLAG_STEED))
{
gpg_error_t err;
chain_item_t ci;
@@ -1780,8 +1804,8 @@ do_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime_arg,
do_validate_chain. This function is a wrapper to handle a root
certificate with the chain_model flag set. If RETFLAGS is not
NULL, flags indicating now the verification was done are stored
- there. The only defined flag for RETFLAGS is
- VALIDATE_FLAG_CHAIN_MODEL.
+ there. The only defined vits for RETFLAGS are
+ VALIDATE_FLAG_CHAIN_MODEL and VALIDATE_FLAG_STEED.
If you are verifying a signature you should set CHECKTIME to the
creation time of the signature. If your are verifying a
@@ -1801,16 +1825,27 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
if (!retflags)
retflags = &dummy_retflags;
+ /* If the session requested a certain validation mode make sure the
+ corresponding flags are set. */
if (ctrl->validation_model == 1)
flags |= VALIDATE_FLAG_CHAIN_MODEL;
+ else if (ctrl->validation_model == 2)
+ flags |= VALIDATE_FLAG_STEED;
+ /* If the chain model was forced, set this immediately into
+ RETFLAGS. */
*retflags = (flags & VALIDATE_FLAG_CHAIN_MODEL);
+
memset (&rootca_flags, 0, sizeof rootca_flags);
rc = do_validate_chain (ctrl, cert, checktime,
r_exptime, listmode, listfp, flags,
&rootca_flags);
- if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED
+ if (!rc && (flags & VALIDATE_FLAG_STEED))
+ {
+ *retflags |= VALIDATE_FLAG_STEED;
+ }
+ else if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED
&& !(flags & VALIDATE_FLAG_CHAIN_MODEL)
&& (rootca_flags.valid && rootca_flags.chain_model))
{
@@ -1824,6 +1859,8 @@ gpgsm_validate_chain (ctrl_t ctrl, ksba_cert_t cert, ksba_isotime_t checktime,
if (opt.verbose)
do_list (0, listmode, listfp, _("validation model used: %s"),
+ (*retflags & VALIDATE_FLAG_STEED)?
+ "steed" :
(*retflags & VALIDATE_FLAG_CHAIN_MODEL)?
_("chain"):_("shell"));
diff --git a/sm/certlist.c b/sm/certlist.c
index 0e9031953..241364a3a 100644
--- a/sm/certlist.c
+++ b/sm/certlist.c
@@ -1,6 +1,6 @@
/* certlist.c - build list of certificates
* Copyright (C) 2001, 2003, 2004, 2005, 2007,
- * 2008 Free Software Foundation, Inc.
+ * 2008, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -210,6 +210,21 @@ gpgsm_cert_use_ocsp_p (ksba_cert_t cert)
}
+/* Return true if CERT has the well known private key extension. */
+int
+gpgsm_cert_has_well_known_private_key (ksba_cert_t cert)
+{
+ int idx;
+ const char *oid;
+
+ for (idx=0; !ksba_cert_get_extension (cert, idx,
+ &oid, NULL, NULL, NULL);idx++)
+ if (!strcmp (oid, "1.3.6.1.4.1.11591.2.2.2") )
+ return 1; /* Yes. */
+ return 0; /* No. */
+}
+
+
static int
same_subject_issuer (const char *subject, const char *issuer, ksba_cert_t cert)
{
diff --git a/sm/certreqgen.c b/sm/certreqgen.c
index 41a6d7f05..de7c39c65 100644
--- a/sm/certreqgen.c
+++ b/sm/certreqgen.c
@@ -33,6 +33,22 @@
%commit
%echo done
EOF
+
+ This parameter file was used to create the STEED CA:
+ Key-Type: RSA
+ Key-Length: 1024
+ Key-Grip: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
+ Key-Usage: cert
+ Serial: 1
+ Name-DN: CN=The STEED Self-Signing Nonthority
+ Not-Before: 2011-11-11
+ Not-After: 2106-02-06
+ Subject-Key-Id: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
+ Extension: 2.5.29.19 c 30060101ff020101
+ Extension: 1.3.6.1.4.1.11591.2.2.2 n 0101ff
+ Signing-Key: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
+ %commit
+
*/
@@ -68,7 +84,10 @@ enum para_name
pNOTBEFORE,
pNOTAFTER,
pSIGNINGKEY,
- pHASHALGO
+ pHASHALGO,
+ pAUTHKEYID,
+ pSUBJKEYID,
+ pEXTENSION
};
struct para_data_s
@@ -89,6 +108,8 @@ struct reqgen_ctrl_s
};
+static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35";
+static const char oidstr_subjectKeyIdentifier[] = "2.5.29.14";
static const char oidstr_keyUsage[] = "2.5.29.15";
static const char oidstr_basicConstraints[] = "2.5.29.19";
static const char oidstr_standaloneCertificate[] = "1.3.6.1.4.1.11591.2.2.1";
@@ -170,8 +191,11 @@ parse_parameter_usage (struct para_data_s *para, enum para_name key)
;
else if ( !ascii_strcasecmp (p, "sign") )
use |= GCRY_PK_USAGE_SIGN;
- else if ( !ascii_strcasecmp (p, "encrypt") )
+ else if ( !ascii_strcasecmp (p, "encrypt")
+ || !ascii_strcasecmp (p, "encr") )
use |= GCRY_PK_USAGE_ENCR;
+ else if ( !ascii_strcasecmp (p, "cert") )
+ use |= GCRY_PK_USAGE_CERT;
else
{
log_error ("line %d: invalid usage list\n", r->lnr);
@@ -225,6 +249,9 @@ read_parameters (ctrl_t ctrl, estream_t fp, estream_t out_fp)
{ "Not-After", pNOTAFTER },
{ "Signing-Key", pSIGNINGKEY },
{ "Hash-Algo", pHASHALGO },
+ { "Authority-Key-Id", pAUTHKEYID },
+ { "Subject-Key-Id", pSUBJKEYID },
+ { "Extension", pEXTENSION, 1 },
{ NULL, 0 }
};
char line[1024], *p;
@@ -594,6 +621,74 @@ proc_parameters (ctrl_t ctrl, struct para_data_s *para,
}
}
+ /* Check the optional AuthorityKeyId. */
+ string = get_parameter_value (para, pAUTHKEYID, 0);
+ if (string)
+ {
+ for (s=string, i=0; hexdigitp (s); s++, i++)
+ ;
+ if (*s || (i&1))
+ {
+ r = get_parameter (para, pAUTHKEYID, 0);
+ log_error (_("line %d: invalid authority-key-id\n"), r->lnr);
+ xfree (cardkeyid);
+ return gpg_error (GPG_ERR_INV_PARAMETER);
+ }
+ }
+
+ /* Check the optional SubjectKeyId. */
+ string = get_parameter_value (para, pSUBJKEYID, 0);
+ if (string)
+ {
+ for (s=string, i=0; hexdigitp (s); s++, i++)
+ ;
+ if (*s || (i&1))
+ {
+ r = get_parameter (para, pSUBJKEYID, 0);
+ log_error (_("line %d: invalid subject-key-id\n"), r->lnr);
+ xfree (cardkeyid);
+ return gpg_error (GPG_ERR_INV_PARAMETER);
+ }
+ }
+
+ /* Check the optional extensions. */
+ for (seq=0; (string=get_parameter_value (para, pEXTENSION, seq)); seq++)
+ {
+ int okay = 0;
+
+ s = strpbrk (string, " \t:");
+ if (s)
+ {
+ s++;
+ while (spacep (s))
+ s++;
+ if (*s && strchr ("nNcC", *s))
+ {
+ s++;
+ while (spacep (s))
+ s++;
+ if (*s == ':')
+ s++;
+ if (*s)
+ {
+ while (spacep (s))
+ s++;
+ for (i=0; hexdigitp (s); s++, i++)
+ ;
+ if (!((*s && *s != ':') || !i || (i&1)))
+ okay = 1;
+ }
+ }
+ }
+ if (!okay)
+ {
+ r = get_parameter (para, pEXTENSION, seq);
+ log_error (_("line %d: invalid extension syntax\n"), r->lnr);
+ xfree (cardkeyid);
+ return gpg_error (GPG_ERR_INV_PARAMETER);
+ }
+ }
+
/* Create or retrieve the public key. */
if (cardkeyid) /* Take the key from the current smart card. */
{
@@ -838,6 +933,14 @@ create_request (ctrl_t ctrl,
err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
"\x03\x02\x04\x30", 4);
}
+ else if (use == GCRY_PK_USAGE_CERT)
+ {
+ /* For certify only we encode the bits:
+ KSBA_KEYUSAGE_KEY_CERT_SIGN
+ KSBA_KEYUSAGE_CRL_SIGN */
+ err = ksba_certreq_add_extension (cr, oidstr_keyUsage, 1,
+ "\x03\x02\x01\x06", 4);
+ }
else
err = 0; /* Both or none given: don't request one. */
if (err)
@@ -889,7 +992,7 @@ create_request (ctrl_t ctrl,
*p++ = '0';
strcpy (p, string);
for (p=hexbuf, len=0; p[0] && p[1]; p += 2)
- ((unsigned char*)hexbuf)[len++] = xtoi_2 (s);
+ ((unsigned char*)hexbuf)[len++] = xtoi_2 (p);
/* Now build the S-expression. */
snprintf (numbuf, DIM(numbuf), "%u:", (unsigned int)len);
buf = p = xtrymalloc (1 + strlen (numbuf) + len + 1 + 1);
@@ -1009,6 +1112,139 @@ create_request (ctrl_t ctrl,
goto leave;
}
}
+
+ /* Insert the AuthorityKeyId. */
+ string = get_parameter_value (para, pAUTHKEYID, 0);
+ if (string)
+ {
+ char *hexbuf;
+
+ /* Allocate a buffer for in-place conversion. We also add 4
+ extra bytes space for the tags and lengths fields. */
+ hexbuf = xtrymalloc (4 + strlen (string) + 1);
+ if (!hexbuf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ strcpy (hexbuf+4, string);
+ for (p=hexbuf+4, len=0; p[0] && p[1]; p += 2)
+ ((unsigned char*)hexbuf)[4+len++] = xtoi_2 (p);
+ if (len > 125)
+ {
+ err = gpg_error (GPG_ERR_TOO_LARGE);
+ xfree (hexbuf);
+ goto leave;
+ }
+ hexbuf[0] = 0x30; /* Tag for a Sequence. */
+ hexbuf[1] = len+2;
+ hexbuf[2] = 0x80; /* Context tag for an implicit Octet string. */
+ hexbuf[3] = len;
+ err = ksba_certreq_add_extension (cr, oidstr_authorityKeyIdentifier,
+ 0,
+ hexbuf, 4+len);
+ xfree (hexbuf);
+ if (err)
+ {
+ log_error ("error setting the authority-key-id: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+ }
+
+ /* Insert the SubjectKeyId. */
+ string = get_parameter_value (para, pSUBJKEYID, 0);
+ if (string)
+ {
+ char *hexbuf;
+
+ /* Allocate a buffer for in-place conversion. We also add 2
+ extra bytes space for the tag and length field. */
+ hexbuf = xtrymalloc (2 + strlen (string) + 1);
+ if (!hexbuf)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ strcpy (hexbuf+2, string);
+ for (p=hexbuf+2, len=0; p[0] && p[1]; p += 2)
+ ((unsigned char*)hexbuf)[2+len++] = xtoi_2 (p);
+ if (len > 127)
+ {
+ err = gpg_error (GPG_ERR_TOO_LARGE);
+ xfree (hexbuf);
+ goto leave;
+ }
+ hexbuf[0] = 0x04; /* Tag for an Octet string. */
+ hexbuf[1] = len;
+ err = ksba_certreq_add_extension (cr, oidstr_subjectKeyIdentifier, 0,
+ hexbuf, 2+len);
+ xfree (hexbuf);
+ if (err)
+ {
+ log_error ("error setting the subject-key-id: %s\n",
+ gpg_strerror (err));
+ goto leave;
+ }
+ }
+
+ /* Insert additional extensions. */
+ for (seq=0; (string = get_parameter_value (para, pEXTENSION, seq)); seq++)
+ {
+ char *hexbuf;
+ char *oidstr;
+ int crit = 0;
+
+ s = strpbrk (string, " \t:");
+ if (!s)
+ {
+ err = gpg_error (GPG_ERR_INTERNAL);
+ goto leave;
+ }
+
+ oidstr = xtrymalloc (s - string + 1);
+ if (!oidstr)
+ {
+ err = gpg_error_from_syserror ();
+ goto leave;
+ }
+ memcpy (oidstr, string, (s-string));
+ oidstr[(s-string)] = 0;
+
+ s++;
+ while (spacep (s))
+ s++;
+ if (!*s)
+ {
+ err = gpg_error (GPG_ERR_INTERNAL);
+ xfree (oidstr);
+ goto leave;
+ }
+
+ if (strchr ("cC", *s))
+ crit = 1;
+ s++;
+ while (spacep (s))
+ s++;
+ if (*s == ':')
+ s++;
+ while (spacep (s))
+ s++;
+
+ hexbuf = xtrystrdup (s);
+ if (!hexbuf)
+ {
+ err = gpg_error_from_syserror ();
+ xfree (oidstr);
+ goto leave;
+ }
+ for (p=hexbuf, len=0; p[0] && p[1]; p += 2)
+ ((unsigned char*)hexbuf)[len++] = xtoi_2 (p);
+ err = ksba_certreq_add_extension (cr, oidstr, crit,
+ hexbuf, len);
+ xfree (oidstr);
+ xfree (hexbuf);
+ }
}
else
sigkey = public;
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index dc9f2e032..7164f4274 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -2004,6 +2004,8 @@ gpgsm_parse_validation_model (const char *model)
return 0;
else if ( !ascii_strcasecmp (model, "chain") )
return 1;
+ else if ( !ascii_strcasecmp (model, "steed") )
+ return 2;
else
return -1;
}
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 31cd95150..6c68af746 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -195,7 +195,9 @@ struct server_control_s
certificates up the chain (0 = none, 1 = only
signer) */
int use_ocsp; /* Set to true if OCSP should be used. */
- int validation_model; /* Set to 1 for the chain model. */
+ int validation_model; /* 0 := standard model (shell),
+ 1 := chain model,
+ 2 := STEED model. */
};
@@ -307,7 +309,7 @@ int gpgsm_create_cms_signature (ctrl_t ctrl,
/* Flags used with gpgsm_validate_chain. */
#define VALIDATE_FLAG_NO_DIRMNGR 1
#define VALIDATE_FLAG_CHAIN_MODEL 2
-
+#define VALIDATE_FLAG_STEED 4
int gpgsm_walk_cert_chain (ctrl_t ctrl,
ksba_cert_t start, ksba_cert_t *r_next);
@@ -326,6 +328,7 @@ int gpgsm_cert_use_verify_p (ksba_cert_t cert);
int gpgsm_cert_use_decrypt_p (ksba_cert_t cert);
int gpgsm_cert_use_cert_p (ksba_cert_t cert);
int gpgsm_cert_use_ocsp_p (ksba_cert_t cert);
+int gpgsm_cert_has_well_known_private_key (ksba_cert_t cert);
int gpgsm_certs_identical_p (ksba_cert_t cert_a, ksba_cert_t cert_b);
int gpgsm_add_cert_to_certlist (ctrl_t ctrl, ksba_cert_t cert,
certlist_t *listaddr, int is_encrypt_to);
diff --git a/sm/keylist.c b/sm/keylist.c
index e67c2d8d3..42c533a6d 100644
--- a/sm/keylist.c
+++ b/sm/keylist.c
@@ -1,6 +1,6 @@
/* keylist.c - Print certificates in various formats.
- * Copyright (C) 1998, 1999, 2000, 2001, 2003,
- * 2004, 2005, 2008, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2008, 2009,
+ * 2010, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -187,6 +187,7 @@ static struct
/* GnuPG extensions */
{ "1.3.6.1.4.1.11591.2.1.1", "pkaAddress" },
{ "1.3.6.1.4.1.11591.2.2.1", "standaloneCertificate" },
+ { "1.3.6.1.4.1.11591.2.2.2", "wellKnownPrivateKey" },
/* Extensions used by the Bundesnetzagentur. */
{ "1.3.6.1.4.1.8301.3.5", "validityModel" },
@@ -420,7 +421,12 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
&& *not_after && strcmp (current_time, not_after) > 0 )
*truststring = 'e';
else if (valerr)
- *truststring = 'i';
+ {
+ if (gpgsm_cert_has_well_known_private_key (cert))
+ *truststring = 'w'; /* Well, this is dummy CA. */
+ else
+ *truststring = 'i';
+ }
else if (ctrl->with_validation && !is_root)
*truststring = 'f';
}
@@ -432,12 +438,17 @@ list_cert_colon (ctrl_t ctrl, ksba_cert_t cert, unsigned int validity,
{
struct rootca_flags_s dummy_flags;
- rc = gpgsm_agent_istrusted (ctrl, cert, NULL, &dummy_flags);
- if (!rc)
- *truststring = 'u'; /* Yes, we trust this one (ultimately). */
- else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
- *truststring = 'n'; /* No, we do not trust this one. */
- /* (in case of an error we can't tell anything.) */
+ if (gpgsm_cert_has_well_known_private_key (cert))
+ *truststring = 'w'; /* Well, this is dummy CA. */
+ else
+ {
+ rc = gpgsm_agent_istrusted (ctrl, cert, NULL, &dummy_flags);
+ if (!rc)
+ *truststring = 'u'; /* Yes, we trust this one (ultimately). */
+ else if (gpg_err_code (rc) == GPG_ERR_NOT_TRUSTED)
+ *truststring = 'n'; /* No, we do not trust this one. */
+ /* (in case of an error we can't tell anything.) */
+ }
}
if (*truststring)
diff --git a/sm/server.c b/sm/server.c
index 19c4a1678..385eb538a 100644
--- a/sm/server.c
+++ b/sm/server.c
@@ -277,7 +277,7 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
else if (!strcmp (key, "validation-model"))
{
int i = gpgsm_parse_validation_model (value);
- if ( i >= 0 && i <= 1 )
+ if ( i >= 0 && i <= 2 )
ctrl->validation_model = i;
else
err = gpg_error (GPG_ERR_ASS_PARAMETER);
diff --git a/sm/verify.c b/sm/verify.c
index c77eb5744..1173f66d1 100644
--- a/sm/verify.c
+++ b/sm/verify.c
@@ -624,6 +624,8 @@ gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, estream_t out_fp)
}
gpgsm_status (ctrl, STATUS_TRUST_FULLY,
+ (verifyflags & VALIDATE_FLAG_STEED)?
+ "0 steed":
(verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
"0 chain": "0 shell");
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2142d33d6..307d82952 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -41,6 +41,8 @@ EXTRA_DIST = runtest inittests $(testscripts) ChangeLog-2011 \
text-1.txt text-2.txt text-3.txt \
text-1.osig.pem text-1.dsig.pem text-1.osig-bad.pem \
text-2.osig.pem text-2.osig-bad.pem \
+ samplekeys/steed-self-signing-nonthority.pem \
+ samplekeys/68A638998DFABAC510EA645CE34F9686B2EDF7EA.key \
samplekeys/32100C27173EF6E9C4E9A25D3D69F86D37A4F939.key \
samplekeys/cert_g10code_pete1.pem \
samplekeys/cert_g10code_test1.pem \
diff --git a/tests/samplekeys/68A638998DFABAC510EA645CE34F9686B2EDF7EA.key b/tests/samplekeys/68A638998DFABAC510EA645CE34F9686B2EDF7EA.key
new file mode 100644
index 000000000..8236349a0
--- /dev/null
+++ b/tests/samplekeys/68A638998DFABAC510EA645CE34F9686B2EDF7EA.key
@@ -0,0 +1,10 @@
+(private-key
+ (rsa
+ (n #0093687D92A7BCD1E6FC11263B50657A8FA4B9CEE3F90E23384D62778CA1B6CBE0F60B20354A5F74899EB3C8DDF3081D32475C71869BB0C5DAF0051A2F44596E7406F1DCC7B29D88735E49341F09F4DFCAB5A08B76614C37220CF7E2CDB8A38E79644F3A250FFAE5D0BBA6917C67523D2812FDE8D3BEA9947F6A55402B1600C12F#)
+ (e #010001#)
+ (d #11BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE905D3988DFC39FEF462A0655AC906CBC12F6D322795D3988DFC39FEF462A0655AC906CBC12F6D322795D3988DFC39FEF462A0655AC906CBC12F6D322795D3983C1#)
+ (p "\x00�BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBA�")
+ (q "\x00�BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB�")
+ (u #00B28879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C221372887A30#)
+ )
+ )
diff --git a/tests/samplekeys/README b/tests/samplekeys/README
index a71f7987e..65255cb61 100644
--- a/tests/samplekeys/README
+++ b/tests/samplekeys/README
@@ -1,6 +1,6 @@
This is a collection of keys we use with the regression tests.
-opensc-tests.p12 PKCS#12 key and certificates taken from OpenSC.
+opensc-tests.p12 PKCS#12 key and certificates taken from OpenSC.
Passphrase is "password"
ov-user.p12 Private tests keys from www.openvalidation.org.
@@ -17,5 +17,8 @@ gte.pem GTE CyberTrust Global Root
cert-with-117-akas.pem A certificate with 117 subjectAltNames.
+steed-self-signing-nonthority.pem
+ The STEED Self-Signing Nonthority.
+68A638998DFABAC510EA645CE34F9686B2EDF7EA.key
+ The private Key of The STEED Self-Signing Nonthority.
-
diff --git a/tests/samplekeys/steed-self-signing-nonthority.pem b/tests/samplekeys/steed-self-signing-nonthority.pem
new file mode 100644
index 000000000..c6a9c54e8
--- /dev/null
+++ b/tests/samplekeys/steed-self-signing-nonthority.pem
@@ -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
diff --git a/tools/ChangeLog-2011 b/tools/ChangeLog-2011
index db771c82d..6821a8782 100644
--- a/tools/ChangeLog-2011
+++ b/tools/ChangeLog-2011
@@ -5,10 +5,6 @@
commit log, and generate a top-level ChangeLog file from logs at
"make dist". See doc/HACKING for details.
-2011-10-13 Marcus Brinkmann <[email protected]>
-
- * Makefile.am: Port to NPth.
-
2011-08-26 Werner Koch <[email protected]>
* gpgconf-comp.c (gc_component): Mark for translation. Suggested
diff --git a/tools/gpg-connect-agent.c b/tools/gpg-connect-agent.c
index 8de67bbf0..117f3380c 100644
--- a/tools/gpg-connect-agent.c
+++ b/tools/gpg-connect-agent.c
@@ -67,25 +67,25 @@ enum cmd_and_opt_values
/* The list of commands and options. */
static ARGPARSE_OPTS opts[] = {
ARGPARSE_group (301, N_("@\nOptions:\n ")),
-
+
ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
ARGPARSE_s_n (oQuiet, "quiet", N_("quiet")),
ARGPARSE_s_n (oHex, "hex", N_("print data out hex encoded")),
ARGPARSE_s_n (oDecode,"decode", N_("decode received data lines")),
- ARGPARSE_s_s (oRawSocket, "raw-socket",
+ ARGPARSE_s_s (oRawSocket, "raw-socket",
N_("|NAME|connect to Assuan socket NAME")),
- ARGPARSE_s_s (oTcpSocket, "tcp-socket",
+ ARGPARSE_s_s (oTcpSocket, "tcp-socket",
N_("|ADDR|connect to Assuan server at ADDR")),
- ARGPARSE_s_n (oExec, "exec",
+ ARGPARSE_s_n (oExec, "exec",
N_("run the Assuan server given on the command line")),
ARGPARSE_s_n (oNoExtConnect, "no-ext-connect",
N_("do not use extended connect mode")),
- ARGPARSE_s_s (oRun, "run",
+ ARGPARSE_s_s (oRun, "run",
N_("|FILE|run commands from FILE on startup")),
- ARGPARSE_s_n (oSubst, "subst", N_("run /subst on startup")),
+ ARGPARSE_s_n (oSubst, "subst", N_("run /subst on startup")),
ARGPARSE_s_n (oNoVerbose, "no-verbose", "@"),
- ARGPARSE_s_s (oHomedir, "homedir", "@" ),
+ ARGPARSE_s_s (oHomedir, "homedir", "@" ),
ARGPARSE_s_s (oAgentProgram, "agent-program", "@"),
ARGPARSE_end ()
@@ -216,7 +216,7 @@ gnu_getcwd (void)
#ifdef HAVE_W32CE_SYSTEM
strcpy (buffer, "/");
return buffer;
-#else
+#else
if (getcwd (buffer, size) == buffer)
return buffer;
xfree (buffer);
@@ -246,22 +246,22 @@ unescape_string (const char *string)
{
switch (*s)
{
- case 'b':
- case 't':
- case 'v':
- case 'n':
- case 'f':
- case 'r':
- case '"':
- case '\'':
+ case 'b':
+ case 't':
+ case 'v':
+ case 'n':
+ case 'f':
+ case 'r':
+ case '"':
+ case '\'':
case '\\': n++; break;
- case 'x':
+ case 'x':
if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
n++;
break;
default:
- if (s[1] && s[2]
+ if (s[1] && s[2]
&& octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
n++;
break;
@@ -272,7 +272,7 @@ unescape_string (const char *string)
esc = 1;
else
n++;
- }
+ }
buffer = xmalloc (n+1);
d = (unsigned char*)buffer;
@@ -291,7 +291,7 @@ unescape_string (const char *string)
case '"': *d++ = '\"'; break;
case '\'': *d++ = '\''; break;
case '\\': *d++ = '\\'; break;
- case 'x':
+ case 'x':
if (s[1] && s[2] && hexdigitp (s+1) && hexdigitp (s+2))
{
s++;
@@ -301,7 +301,7 @@ unescape_string (const char *string)
break;
default:
- if (s[1] && s[2]
+ if (s[1] && s[2]
&& octdigitp (s) && octdigitp (s+1) && octdigitp (s+2))
{
*d++ = (atoi_1 (s)*64) + (atoi_1 (s+1)*8) + atoi_1 (s+2);
@@ -315,7 +315,7 @@ unescape_string (const char *string)
esc = 1;
else
*d++ = *s;
- }
+ }
*d = 0;
return buffer;
}
@@ -334,7 +334,7 @@ unpercent_string (const char *string, int with_plus)
for (s=(const unsigned char *)string; *s; s++)
{
if (*s == '%' && s[1] && s[2])
- {
+ {
s++;
n++;
s++;
@@ -350,7 +350,7 @@ unpercent_string (const char *string, int with_plus)
for (s=(const unsigned char *)string; *s; s++)
{
if (*s == '%' && s[1] && s[2])
- {
+ {
s++;
*p++ = xtoi_2 (s);
s++;
@@ -387,7 +387,7 @@ set_var (const char *name, const char *value)
xfree (var->value);
var->value = value? xstrdup (value) : NULL;
return var->value;
-}
+}
static void
@@ -455,12 +455,12 @@ arithmetic_op (int operator, const char *operands)
case '+': result += value; break;
case '-': result -= value; break;
case '*': result *= value; break;
- case '/':
+ case '/':
if (!value)
return NULL;
result /= value;
break;
- case '%':
+ case '%':
if (!value)
return NULL;
result %= value;
@@ -480,10 +480,10 @@ arithmetic_op (int operator, const char *operands)
/* Extended version of get_var. This returns a malloced string and
- understand the function syntax: "func args".
+ understand the function syntax: "func args".
Defined functions are
-
+
get - Return a value described by the next argument:
cwd - The current working directory.
homedir - The gnupg homedir.
@@ -525,7 +525,7 @@ arithmetic_op (int operator, const char *operands)
Example: get_var_ext ("get sysconfdir") -> "/etc/gnupg"
-
+
*/
static char *
get_var_ext (const char *name)
@@ -630,7 +630,7 @@ get_var_ext (const char *name)
{
s++;
intvalue = (int)strtol (s, NULL, 0);
- result = xasprintf ("%s <%s>",
+ result = xasprintf ("%s <%s>",
gpg_strerror (intvalue), gpg_strsource (intvalue));
}
else if ( (s - name) == 1 && strchr ("+-*/%!|&", *name))
@@ -642,7 +642,7 @@ get_var_ext (const char *name)
log_error ("unknown variable function `%.*s'\n", (int)(s-name), name);
result = NULL;
}
-
+
xfree (free_me);
recursion_count--;
return result;
@@ -667,7 +667,7 @@ substitute_line (char *buffer)
p = strchr (line, '$');
if (!p)
return result; /* No more variables. */
-
+
if (p[1] == '$') /* Escaped dollar sign. */
{
memmove (p, p+1, strlen (p+1)+1);
@@ -751,7 +751,7 @@ static char *
substitute_line_copy (const char *buffer)
{
char *result, *p;
-
+
p = xstrdup (buffer?buffer:"");
result = substitute_line (p);
if (!result)
@@ -777,7 +777,7 @@ assign_variable (char *line, int syslet)
p++;
if (!*p)
- set_var (name, NULL); /* Remove variable. */
+ set_var (name, NULL); /* Remove variable. */
else if (syslet)
{
free_me = opt.enable_varsubst? substitute_line_copy (p) : NULL;
@@ -791,7 +791,7 @@ assign_variable (char *line, int syslet)
xfree (tmp);
xfree (free_me);
}
- else
+ else
{
tmp = opt.enable_varsubst? substitute_line_copy (p) : NULL;
if (tmp)
@@ -857,11 +857,11 @@ show_definq (void)
for (d=definq_list; d; d = d->next)
if (d->name)
- printf ("%-20s %c %s\n",
+ printf ("%-20s %c %s\n",
d->name, d->is_var? 'v' : d->is_prog? 'p':'f', d->file);
for (d=definq_list; d; d = d->next)
if (!d->name)
- printf ("%-20s %c %s\n", "*",
+ printf ("%-20s %c %s\n", "*",
d->is_var? 'v': d->is_prog? 'p':'f', d->file);
}
@@ -871,14 +871,14 @@ static void
clear_definq (void)
{
while (definq_list)
- {
+ {
definq_t tmp = definq_list->next;
xfree (definq_list->name);
xfree (definq_list);
definq_list = tmp;
}
definq_list_tail = &definq_list;
-}
+}
static void
@@ -1005,7 +1005,7 @@ do_open (char *line)
HANDLE prochandle, handle, newhandle;
handle = (void*)_get_osfhandle (fd);
-
+
prochandle = OpenProcess (PROCESS_DUP_HANDLE, FALSE, server_pid);
if (!prochandle)
{
@@ -1030,7 +1030,7 @@ do_open (char *line)
log_info ("file `%s' opened in \"%s\" mode, fd=%d (libc=%d)\n",
name, mode, (int)open_fd_table[fd].handle, fd);
set_int_var (varname, (int)open_fd_table[fd].handle);
-#else
+#else
if (opt.verbose)
log_info ("file `%s' opened in \"%s\" mode, fd=%d\n",
name, mode, fd);
@@ -1117,14 +1117,14 @@ do_serverpid (assuan_context_t ctx)
int rc;
membuf_t mb;
char *buffer;
-
+
init_membuf (&mb, 100);
rc = assuan_transact (ctx, "GETINFO pid", getinfo_pid_cb, &mb,
NULL, NULL, NULL, NULL);
put_membuf (&mb, "", 1);
buffer = get_membuf (&mb, NULL);
if (rc || !buffer)
- log_error ("command \"%s\" failed: %s\n",
+ log_error ("command \"%s\" failed: %s\n",
"GETINFO pid", gpg_strerror (rc));
else
{
@@ -1136,6 +1136,22 @@ do_serverpid (assuan_context_t ctx)
}
+/* Return true if the command is either "HELP" or "SCD HELP". */
+static int
+help_cmd_p (const char *line)
+{
+ if (!ascii_strncasecmp (line, "SCD", 3)
+ && (spacep (line+3) || !line[3]))
+ {
+ for (line += 3; spacep (line); line++)
+ ;
+ }
+
+ return (!ascii_strncasecmp (line, "HELP", 4)
+ && (spacep (line+4) || !line[4]));
+}
+
+
/* gpg-connect-agent's entry point. */
int
main (int argc, char **argv)
@@ -1156,7 +1172,7 @@ main (int argc, char **argv)
loopline_t head;
loopline_t *tail;
loopline_t current;
- unsigned int nestlevel;
+ unsigned int nestlevel;
int oneshot;
char *condition;
} loopstack[20];
@@ -1197,7 +1213,7 @@ main (int argc, char **argv)
case oExec: opt.exec = 1; break;
case oNoExtConnect: opt.connect_flags &= ~(1); break;
case oRun: opt_run = pargs.r.ret_str; break;
- case oSubst:
+ case oSubst:
opt.enable_varsubst = 1;
opt.trim_leading_spaces = 1;
break;
@@ -1339,7 +1355,7 @@ main (int argc, char **argv)
log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
}
-
+
for (loopidx=0; loopidx < DIM (loopstack); loopidx++)
loopstack[loopidx].collecting = 0;
loopidx = -1;
@@ -1396,7 +1412,7 @@ main (int argc, char **argv)
linesize = 0;
keep_line = 1;
}
- n = read_line (script_fp? script_fp:stdin,
+ n = read_line (script_fp? script_fp:stdin,
&line, &linesize, &maxlength);
}
if (n < 0)
@@ -1422,7 +1438,7 @@ main (int argc, char **argv)
log_info ("end of script\n");
continue;
}
- break;
+ break;
}
if (!maxlength)
{
@@ -1433,11 +1449,11 @@ main (int argc, char **argv)
log_info (_("line shortened due to embedded Nul character\n"));
if (line[n-1] == '\n')
line[n-1] = 0;
-
+
if (opt.trim_leading_spaces)
{
const char *s = line;
-
+
while (spacep (s))
s++;
if (s != line)
@@ -1463,7 +1479,7 @@ main (int argc, char **argv)
loopstack[loopidx+1].nestlevel--;
else if (!strncmp (line, "/while", 6) && (!line[6]||spacep(line+6)))
loopstack[loopidx+1].nestlevel++;
-
+
if (loopstack[loopidx+1].nestlevel)
continue;
/* We reached the corresponding /end. */
@@ -1546,7 +1562,7 @@ main (int argc, char **argv)
{
current_datasink = fopen (fname, "wb");
if (!current_datasink)
- log_error ("can't open `%s': %s\n",
+ log_error ("can't open `%s': %s\n",
fname, strerror (errno));
}
xfree (tmpline);
@@ -1783,7 +1799,7 @@ main (int argc, char **argv)
"/cleardef Delete all definitions.\n"
"/sendfd FILE MODE Open FILE and pass descriptor to server.\n"
"/recvfd Receive FD from server and print.\n"
-"/open VAR FILE MODE Open FILE and assign the file descriptor to VAR.\n"
+"/open VAR FILE MODE Open FILE and assign the file descriptor to VAR.\n"
"/close FD Close file with descriptor FD.\n"
"/showopen Show descriptors of all open files.\n"
"/serverpid Retrieve the pid of the server.\n"
@@ -1799,7 +1815,7 @@ main (int argc, char **argv)
}
else
log_error (_("unknown command `%s'\n"), cmd );
-
+
continue;
}
@@ -1822,9 +1838,7 @@ main (int argc, char **argv)
if (*line == '#' || !*line)
continue; /* Don't expect a response for a comment line. */
- rc = read_and_print_response (ctx, (!ascii_strncasecmp (line, "HELP", 4)
- && (spacep (line+4) || !line[4])),
- &cmderr);
+ rc = read_and_print_response (ctx, help_cmd_p (line), &cmderr);
if (rc)
log_info (_("receiving line failed: %s\n"), gpg_strerror (rc) );
if ((rc || cmderr) && script_fp)
@@ -1833,7 +1847,7 @@ main (int argc, char **argv)
fclose (script_fp);
script_fp = NULL;
}
-
+
/* FIXME: If the last command was BYE or the server died for
some other reason, we won't notice until we get the next
@@ -1844,8 +1858,8 @@ main (int argc, char **argv)
if (opt.verbose)
log_info ("closing connection to agent\n");
-
- return 0;
+
+ return 0;
}
@@ -1911,7 +1925,7 @@ handle_inquire (assuan_context_t ctx, char *line)
log_error ("error executing `%s': %s\n",
d->file, strerror (errno));
else if (opt.verbose)
- log_error ("handling inquiry `%s' by running `%s'\n",
+ log_error ("handling inquiry `%s' by running `%s'\n",
name, d->file);
}
else
@@ -1974,7 +1988,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
*r_goterr = 0;
for (;;)
{
- do
+ do
{
rc = assuan_read_line (ctx, &line, &linelen);
if (rc)
@@ -1985,7 +1999,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
fwrite (line, linelen, 1, stdout);
putchar ('\n');
}
- }
+ }
while (*line == '#' || !linelen);
if (linelen >= 1
@@ -1999,7 +2013,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
for (j=2, s=(unsigned char*)line+2; j < linelen; j++, s++ )
{
if (*s == '%' && j+2 < linelen)
- {
+ {
s++; j++;
c = xtoi_2 ( s );
s++; j++;
@@ -2054,7 +2068,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
need_d = 0;
}
if (*s == '%' && j+2 < linelen)
- {
+ {
s++; j++;
c = xtoi_2 ( s );
s++; j++;
@@ -2073,7 +2087,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
putchar ('\n');
}
}
- else
+ else
{
if (need_lf)
{
@@ -2083,7 +2097,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
}
if (linelen >= 1
- && line[0] == 'S'
+ && line[0] == 'S'
&& (line[1] == '\0' || line[1] == ' '))
{
if (!current_datasink || current_datasink != stdout)
@@ -2091,7 +2105,7 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
fwrite (line, linelen, 1, stdout);
putchar ('\n');
}
- }
+ }
else if (linelen >= 2
&& line[0] == 'O' && line[1] == 'K'
&& (line[2] == '\0' || line[2] == ' '))
@@ -2121,11 +2135,11 @@ read_and_print_response (assuan_context_t ctx, int withhash, int *r_goterr)
}
*r_goterr = 1;
return 0;
- }
+ }
else if (linelen >= 7
&& line[0] == 'I' && line[1] == 'N' && line[2] == 'Q'
&& line[3] == 'U' && line[4] == 'I' && line[5] == 'R'
- && line[6] == 'E'
+ && line[6] == 'E'
&& (line[7] == '\0' || line[7] == ' '))
{
if (!current_datasink || current_datasink != stdout)