mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-21 10:09:57 +01:00
Merge branch 'master' into npth
Conflicts: ChangeLog-2011 Makefile.am agent/ChangeLog-2011 agent/gpg-agent.c dirmngr/ChangeLog-2011 dirmngr/dirmngr.c doc/HACKING g13/g13.c po/de.po scd/ChangeLog-2011 scd/apdu.c scd/command.c scd/scdaemon.c scripts/gitlog-to-changelog tools/ChangeLog-2011
This commit is contained in:
commit
0868997e18
@ -14,21 +14,6 @@
|
||||
accept --with-libgpg-error-prefix as well as --with-gpg-error-prefix
|
||||
* m4/gpg-error.m4: Update from git master.
|
||||
|
||||
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
|
||||
|
||||
* configure.ac: Fix npth version check.
|
||||
* m4/npth.m4: Fix version check.
|
||||
|
||||
2011-09-26 Marcus Brinkmann <marcus@g10code.com>
|
||||
|
||||
* configure.ac: Don't check for PTH but for NPTH.
|
||||
(AH_BOTTOM): Remove PTH_SYSCALL_SOFT.
|
||||
(have_pth): Rename to ...
|
||||
(have_npth): ... this.
|
||||
(USE_GNU_NPTH): Rename to ...
|
||||
(USE_GNU_PTH): ... this.
|
||||
* m4/gnupg-npth.m4: New file.
|
||||
|
||||
2011-09-23 Werner Koch <wk@g10code.com>
|
||||
|
||||
* configure.ac: Remove check for gcry_kdf_derive.
|
||||
|
@ -116,6 +116,7 @@ gen-ChangeLog:
|
||||
if test -d $(top_srcdir)/.git; then \
|
||||
(cd $(top_srcdir) && \
|
||||
./scripts/gitlog-to-changelog \
|
||||
--append-dot --tear-off \
|
||||
--amend=scripts/git-log-fix \
|
||||
--since=$(gen_start_date) ) > $(distdir)/cl-t; \
|
||||
cat $(top_srcdir)/scripts/git-log-footer >> $(distdir)/cl-t; \
|
||||
|
19
NEWS
19
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)
|
||||
-----------------------------------------------------
|
||||
|
@ -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)
|
||||
|
@ -12,17 +12,6 @@
|
||||
(ssh_handler_request_identities): Do not call card_key_available
|
||||
if the scdaemon is disabled.
|
||||
|
||||
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
|
||||
|
||||
* gpg-agent.c (start_connection_thread)
|
||||
(start_connection_thread_ssh): Cast npth_self result to unsigned
|
||||
long for safety.
|
||||
|
||||
* cache.c (new_data): Fix error check.
|
||||
|
||||
* cache.c, call-pinentry.c, call-scd.c, findkey.c, gpg-agent.c,
|
||||
trustlist.c: Port to NPth.
|
||||
|
||||
2011-09-12 Ben Kibbey <bjk@luxsci.net>
|
||||
|
||||
* genkey.c (agent_ask_new_passphrase): Allow for an empty passphrase
|
||||
|
@ -73,17 +73,20 @@ struct
|
||||
/* True if we handle sigusr2. */
|
||||
int sigusr2_enabled;
|
||||
|
||||
/* Environment setting gathered at program start or changed using the
|
||||
/* Environment settings gathered at program start or changed using the
|
||||
Assuan command UPDATESTARTUPTTY. */
|
||||
session_env_t startup_env;
|
||||
char *startup_lc_ctype;
|
||||
char *startup_lc_messages;
|
||||
|
||||
const char *pinentry_program; /* Filename of the program to start as
|
||||
pinentry. */
|
||||
const char *scdaemon_program; /* Filename of the program to handle
|
||||
smartcard tasks. */
|
||||
/* Filename of the program to start as pinentry. */
|
||||
const char *pinentry_program;
|
||||
|
||||
/* Filename of the program to handle smartcard tasks. */
|
||||
const char *scdaemon_program;
|
||||
|
||||
int disable_scdaemon; /* Never use the SCdaemon. */
|
||||
|
||||
int no_grab; /* Don't let the pinentry grab the keyboard */
|
||||
|
||||
/* The name of the file pinentry shall tocuh before exiting. If
|
||||
@ -98,31 +101,51 @@ struct
|
||||
|
||||
/* Flag disallowing bypassing of the warning. */
|
||||
int enforce_passphrase_constraints;
|
||||
|
||||
/* The require minmum length of a passphrase. */
|
||||
unsigned int min_passphrase_len;
|
||||
|
||||
/* The minimum number of non-alpha characters in a passphrase. */
|
||||
unsigned int min_passphrase_nonalpha;
|
||||
|
||||
/* File name with a patternfile or NULL if not enabled. */
|
||||
const char *check_passphrase_pattern;
|
||||
|
||||
/* If not 0 the user is asked to change his passphrase after these
|
||||
number of days. */
|
||||
unsigned int max_passphrase_days;
|
||||
|
||||
/* If set, a passphrase history will be written and checked at each
|
||||
passphrase change. */
|
||||
int enable_passhrase_history;
|
||||
|
||||
int running_detached; /* We are running detached from the tty. */
|
||||
|
||||
/* If this global option is true, the passphrase cache is ignored
|
||||
for signing operations. */
|
||||
int ignore_cache_for_signing;
|
||||
|
||||
/* If this global option is true, the user is allowed to
|
||||
interactively mark certificate in trustlist.txt as trusted. */
|
||||
int allow_mark_trusted;
|
||||
|
||||
/* If this global option is true, the Assuan command
|
||||
PRESET_PASSPHRASE is allowed. */
|
||||
int allow_preset_passphrase;
|
||||
|
||||
/* If this global option is true, the Assuan option
|
||||
pinentry-mode=loopback is allowed. */
|
||||
int allow_loopback_pinentry;
|
||||
|
||||
int keep_tty; /* Don't switch the TTY (for pinentry) on request */
|
||||
int keep_display; /* Don't switch the DISPLAY (for pinentry) on request */
|
||||
int ssh_support; /* Enable ssh-agent emulation. */
|
||||
|
||||
/* This global option enables the ssh-agent subsystem. */
|
||||
int ssh_support;
|
||||
} opt;
|
||||
|
||||
|
||||
/* Bit values for the --debug option. */
|
||||
#define DBG_COMMAND_VALUE 1 /* debug commands i/o */
|
||||
#define DBG_MPI_VALUE 2 /* debug mpi details */
|
||||
#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
|
||||
@ -130,8 +153,9 @@ struct
|
||||
#define DBG_CACHE_VALUE 64 /* debug the caching */
|
||||
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
|
||||
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
|
||||
#define DBG_ASSUAN_VALUE 1024
|
||||
#define DBG_ASSUAN_VALUE 1024 /* Enable Assuan debugging. */
|
||||
|
||||
/* Test macros for the debug option. */
|
||||
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
|
||||
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
|
||||
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
|
||||
@ -139,14 +163,18 @@ struct
|
||||
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
|
||||
#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
|
||||
|
||||
/* Forward reference for local definitions in command.c. */
|
||||
struct server_local_s;
|
||||
|
||||
/* Forward reference for local definitions in call-scd.c. */
|
||||
struct scd_local_s;
|
||||
|
||||
/* Collection of data per session (aka connection). */
|
||||
struct server_control_s
|
||||
{
|
||||
/* Private data used to fire up the connection thread. We use this
|
||||
structure do avoid an extra allocation for just a few bytes. */
|
||||
structure do avoid an extra allocation for only a few bytes while
|
||||
spawning a new connection thread. */
|
||||
struct {
|
||||
gnupg_fd_t fd;
|
||||
} thread_startup;
|
||||
@ -157,6 +185,7 @@ struct server_control_s
|
||||
/* Private data of the SCdaemon (call-scd.c). */
|
||||
struct scd_local_s *scd_local;
|
||||
|
||||
/* Environment settings for the connection. */
|
||||
session_env_t session_env;
|
||||
char *lc_ctype;
|
||||
char *lc_messages;
|
||||
@ -177,37 +206,47 @@ struct server_control_s
|
||||
unsigned char keygrip[20];
|
||||
int have_keygrip;
|
||||
|
||||
int use_auth_call; /* Hack to send the PKAUTH command instead of the
|
||||
PKSIGN command to the scdaemon. */
|
||||
int in_passwd; /* Hack to inhibit enforced passphrase change
|
||||
during an explicit passwd command. */
|
||||
/* A flag to enable a hack to send the PKAUTH command instead of the
|
||||
PKSIGN command to the scdaemon. */
|
||||
int use_auth_call;
|
||||
|
||||
unsigned long s2k_count; /* Other than the calibrated count. */
|
||||
/* A flag to inhibit enforced passphrase change during an explicit
|
||||
passwd command. */
|
||||
int in_passwd;
|
||||
|
||||
/* The current S2K which might be different from the calibrated
|
||||
count. */
|
||||
unsigned long s2k_count;
|
||||
};
|
||||
|
||||
|
||||
/* Information pertaining to pinentry requests. */
|
||||
struct pin_entry_info_s
|
||||
{
|
||||
int min_digits; /* min. number of digits required or 0 for freeform entry */
|
||||
int max_digits; /* max. number of allowed digits allowed*/
|
||||
int max_tries;
|
||||
int failed_tries;
|
||||
int max_tries; /* max. number of allowed tries. */
|
||||
int failed_tries; /* Number of tries so far failed. */
|
||||
int with_qualitybar; /* Set if the quality bar should be displayed. */
|
||||
int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
|
||||
void *check_cb_arg; /* optional argument which might be of use in the CB */
|
||||
const char *cb_errtext; /* used by the cb to display a specific error */
|
||||
size_t max_length; /* allocated length of the buffer */
|
||||
char pin[1];
|
||||
size_t max_length; /* Allocated length of the buffer PIN. */
|
||||
char pin[1]; /* The buffer to hold the PIN or passphrase.
|
||||
It's actual allocated length is given by
|
||||
MAX_LENGTH (above). */
|
||||
};
|
||||
|
||||
|
||||
/* Types of the private keys. */
|
||||
enum
|
||||
{
|
||||
PRIVATE_KEY_UNKNOWN = 0,
|
||||
PRIVATE_KEY_CLEAR = 1,
|
||||
PRIVATE_KEY_PROTECTED = 2,
|
||||
PRIVATE_KEY_SHADOWED = 3,
|
||||
PROTECTED_SHARED_SECRET = 4
|
||||
PRIVATE_KEY_UNKNOWN = 0, /* Type of key is not known. */
|
||||
PRIVATE_KEY_CLEAR = 1, /* The key is not protected. */
|
||||
PRIVATE_KEY_PROTECTED = 2, /* The key is protected. */
|
||||
PRIVATE_KEY_SHADOWED = 3, /* The key is a stub for a smartcard
|
||||
based key. */
|
||||
PROTECTED_SHARED_SECRET = 4 /* RFU. */
|
||||
};
|
||||
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
107
agent/command.c
107
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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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))
|
||||
{
|
||||
|
140
common/estream.c
140
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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -15,21 +15,6 @@
|
||||
* certcache.c (classify_pattern): Remove unused variable and make
|
||||
explicit substring search work.
|
||||
|
||||
2011-11-24 Werner Koch <wk@g10code.com>
|
||||
|
||||
* ks-engine-http.c (ks_http_help): Do not print help for hkp.
|
||||
* ks-engine-hkp.c (ks_hkp_help): Print help only for hkp.
|
||||
(send_request): Remove test code.
|
||||
(map_host): Use xtrymalloc.
|
||||
|
||||
* certcache.c (classify_pattern): Remove unused variable and make
|
||||
explicit substring search work.
|
||||
|
||||
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
|
||||
|
||||
* Makefile.am, certcache.c, crlfetch.c, dirmngr.c, ldap-wrapper.c:
|
||||
Port to NPth.
|
||||
|
||||
2011-06-01 Marcus Brinkmann <mb@g10code.com>
|
||||
|
||||
* Makefile.am (dirmngr_ldap_CFLAGS): Add $(LIBGCRYPT_CFLAGS),
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
13
doc/HACKING
13
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.
|
||||
|
||||
|
||||
|
||||
|
@ -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-----
|
||||
|
44
doc/faq.org
44
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
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
|
||||
|
32
po/de.po
32
po/de.po
@ -9,7 +9,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: gnupg-2.1.0\n"
|
||||
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
|
||||
"PO-Revision-Date: 2011-11-24 14:15+0100\n"
|
||||
"PO-Revision-Date: 2011-12-20 15:52+0100\n"
|
||||
"Last-Translator: Werner Koch <wk@gnupg.org>\n"
|
||||
"Language-Team: German <de@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
@ -111,9 +111,9 @@ msgstr "Fehler beim Holen der Karten-Seriennummer: %s\n"
|
||||
msgid "detected card with S/N: %s\n"
|
||||
msgstr "Erkannte Karte hat die Seriennummer: %s\n"
|
||||
|
||||
#, fuzzy, c-format
|
||||
#, c-format
|
||||
msgid "no authentication key for ssh on card: %s\n"
|
||||
msgstr "Fehler beim Holen der Authentisierungsschlüssel-ID der Karte: %s\n"
|
||||
msgstr "Auf der Karte ist kein Authentisierungsschlüssel für SSH: %s\n"
|
||||
|
||||
#, c-format
|
||||
msgid "no suitable card key found: %s\n"
|
||||
@ -5434,17 +5434,11 @@ msgstr "|AN|Neue Admin-PIN"
|
||||
msgid "|N|New PIN"
|
||||
msgstr "|N|Neue PIN"
|
||||
|
||||
#, fuzzy
|
||||
msgid "||Please enter the Reset Code for the card and New PIN"
|
||||
msgstr "Bitte geben Sie den Rückstellcode für diese Karte ein"
|
||||
|
||||
#, fuzzy
|
||||
msgid "||Please enter the Admin PIN and New Admin PIN"
|
||||
msgstr "|A|Bitte die Admin-PIN eingeben."
|
||||
msgstr "|A|Bitte die Admin-PIN sowie die neue Admin-PIN eingeben."
|
||||
|
||||
#, fuzzy
|
||||
msgid "||Please enter the PIN and New PIN"
|
||||
msgstr "||Bitte die PIN eingeben"
|
||||
msgstr "||Bitte die PIN sowie die neue PIN eingeben"
|
||||
|
||||
msgid "error reading application data\n"
|
||||
msgstr "Fehler beim Lesen der Anwendungsdaten\n"
|
||||
@ -5880,6 +5874,18 @@ msgstr ""
|
||||
msgid "line %d: invalid hash algorithm given\n"
|
||||
msgstr "Zeile %d: Ungültiges Hashverfahren\n"
|
||||
|
||||
#, c-format
|
||||
msgid "line %d: invalid authority-key-id\n"
|
||||
msgstr "Zeile %d: Ungültige Authentisierungsschlüssel-ID\n"
|
||||
|
||||
#, c-format
|
||||
msgid "line %d: invalid subject-key-id\n"
|
||||
msgstr "Zeile %d: ungültige \"Subject-Key-Id\"\n"
|
||||
|
||||
#, c-format
|
||||
msgid "line %d: invalid extension syntax\n"
|
||||
msgstr "Zeile %d: Ungültiger Syntax der Extension\n"
|
||||
|
||||
#, c-format
|
||||
msgid "line %d: error reading key `%s' from card: %s\n"
|
||||
msgstr "Zeile %d: Fehler beim Lesen des Schlüssels `%s' von der Karte: %s\n"
|
||||
@ -7925,6 +7931,10 @@ msgstr ""
|
||||
"Syntax: gpg-check-pattern [optionen] Musterdatei\n"
|
||||
"Die von stdin gelesene Passphrase gegen die Musterdatei prüfen\n"
|
||||
|
||||
#, fuzzy
|
||||
#~ msgid "||Please enter the Reset Code for the card and New PIN"
|
||||
#~ msgstr "Bitte geben Sie den Rückstellcode für diese Karte ein"
|
||||
|
||||
#~ msgid " - probably dead - removing lock"
|
||||
#~ msgstr " - existiert wahrscheinlich nicht mehr - entferne Sperre"
|
||||
|
||||
|
@ -87,10 +87,6 @@
|
||||
(handle_control): New.
|
||||
(main): Handle the case 6 of handle_control.
|
||||
|
||||
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
|
||||
|
||||
* Makefile.am, apdu.c, app.c, command.c, scdaemon.c: Port to Npth.
|
||||
|
||||
2011-08-10 Werner Koch <wk@g10code.com>
|
||||
|
||||
* command.c (cmd_killscd): Use the new assuan force close flag
|
||||
|
@ -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 \
|
||||
|
252
scd/apdu.c
252
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -143,7 +143,8 @@ size_t app_help_read_length_of_cert (int slot, int fid, size_t *r_certoff);
|
||||
/*-- app.c --*/
|
||||
void app_dump_state (void);
|
||||
void application_notify_card_reset (int slot);
|
||||
gpg_error_t check_application_conflict (ctrl_t ctrl, const char *name);
|
||||
gpg_error_t check_application_conflict (ctrl_t ctrl, int slot,
|
||||
const char *name);
|
||||
gpg_error_t select_application (ctrl_t ctrl, int slot, const char *name,
|
||||
app_t *r_app);
|
||||
char *get_supported_applications (void);
|
||||
|
102
scd/app.c
102
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;
|
||||
|
||||
if (p && n <= resultlen)
|
||||
{
|
||||
/* The GDO file is pretty short, thus we simply reuse it for
|
||||
storing the serial number. */
|
||||
memmove (result, p, n);
|
||||
app->serialno = result;
|
||||
app->serialnolen = n;
|
||||
err = app_munge_serialno (app);
|
||||
if (err)
|
||||
goto leave;
|
||||
p = find_tlv_unchecked (result, resultlen, 0x5A, &n);
|
||||
if (p)
|
||||
resultlen -= (p-result);
|
||||
if (p && n > resultlen && n == 0x0d && resultlen+1 == n)
|
||||
{
|
||||
/* The object it does not fit into the buffer. This is an
|
||||
invalid encoding (or the buffer is too short. However, I
|
||||
have some test cards with such an invalid encoding and
|
||||
therefore I use this ugly workaround to return something
|
||||
I can further experiment with. */
|
||||
log_info ("enabling BMI testcard workaround\n");
|
||||
n--;
|
||||
}
|
||||
|
||||
if (p && n <= resultlen)
|
||||
{
|
||||
/* The GDO file is pretty short, thus we simply reuse it for
|
||||
storing the serial number. */
|
||||
memmove (result, p, n);
|
||||
app->serialno = result;
|
||||
app->serialnolen = n;
|
||||
err = app_munge_serialno (app);
|
||||
if (err)
|
||||
goto leave;
|
||||
}
|
||||
else
|
||||
xfree (result);
|
||||
result = NULL;
|
||||
}
|
||||
else
|
||||
xfree (result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
/* For certain error codes, there is no need to try more. */
|
||||
@ -357,7 +365,15 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
|
||||
goto leave;
|
||||
|
||||
/* Figure out the application to use. */
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
if (want_undefined)
|
||||
{
|
||||
/* We switch to the "undefined" application only if explicitly
|
||||
requested. */
|
||||
app->apptype = "UNDEFINED";
|
||||
err = 0;
|
||||
}
|
||||
else
|
||||
err = gpg_error (GPG_ERR_NOT_FOUND);
|
||||
|
||||
if (err && is_app_allowed ("openpgp")
|
||||
&& (!name || !strcmp (name, "openpgp")))
|
||||
@ -366,11 +382,11 @@ select_application (ctrl_t ctrl, int slot, const char *name, app_t *r_app)
|
||||
err = app_select_nks (app);
|
||||
if (err && is_app_allowed ("p15") && (!name || !strcmp (name, "p15")))
|
||||
err = app_select_p15 (app);
|
||||
if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
|
||||
err = app_select_dinsig (app);
|
||||
if (err && is_app_allowed ("geldkarte")
|
||||
&& (!name || !strcmp (name, "geldkarte")))
|
||||
err = app_select_geldkarte (app);
|
||||
if (err && is_app_allowed ("dinsig") && (!name || !strcmp (name, "dinsig")))
|
||||
err = app_select_dinsig (app);
|
||||
if (err && name)
|
||||
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
|
||||
|
||||
@ -404,8 +420,10 @@ get_supported_applications (void)
|
||||
"openpgp",
|
||||
"nks",
|
||||
"p15",
|
||||
"dinsig",
|
||||
"geldkarte",
|
||||
"dinsig",
|
||||
/* Note: "undefined" is not listed here because it needs special
|
||||
treatment by the client. */
|
||||
NULL
|
||||
};
|
||||
int idx;
|
||||
|
252
scd/atr.c
252
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)
|
||||
es_putc ('\0', fp); /* We want a string. */
|
||||
if (es_fclose_snatch (fp, (void**)&result, NULL))
|
||||
{
|
||||
have_ta = !!(*atr & 0x10);
|
||||
have_tb = !!(*atr & 0x20);
|
||||
have_tc = !!(*atr & 0x40);
|
||||
have_td = !!(*atr & 0x80);
|
||||
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
|
||||
goto leave; /* ATR shorter than indicated by format character. */
|
||||
atrlen--;
|
||||
atr++;
|
||||
log_error ("oops: es_fclose_snatch failed: %s\n", strerror (errno));
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
have_ta = have_tb = have_tc = have_td = 0;
|
||||
|
||||
if (have_ta + have_tb + have_tc >= atrlen)
|
||||
goto leave;
|
||||
atrlen -= have_ta + have_tb + have_tc;
|
||||
atr += have_ta + have_tb + have_tc;
|
||||
|
||||
if (have_td)
|
||||
{
|
||||
have_ta = !!(*atr & 0x10);
|
||||
have_tb = !!(*atr & 0x20);
|
||||
have_tc = !!(*atr & 0x40);
|
||||
have_td = !!(*atr & 0x80);
|
||||
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
|
||||
goto leave; /* ATR shorter than indicated by format character. */
|
||||
atrlen--;
|
||||
atr++;
|
||||
}
|
||||
else
|
||||
have_ta = have_tb = have_tc = have_td = 0;
|
||||
|
||||
for (idx = 3; have_ta || have_tb || have_tc || have_td; idx++)
|
||||
{
|
||||
if (have_ta + have_tb + have_tc >= atrlen)
|
||||
goto leave;
|
||||
atrlen -= have_ta + have_tb + have_tc;
|
||||
atr += have_ta + have_tb + have_tc;
|
||||
|
||||
if (have_td)
|
||||
{
|
||||
have_ta = !!(*atr & 0x10);
|
||||
have_tb = !!(*atr & 0x20);
|
||||
have_tc = !!(*atr & 0x40);
|
||||
have_td = !!(*atr & 0x80);
|
||||
if (have_ta + have_tb + have_tc + have_td + n_historical >= atrlen)
|
||||
goto leave; /* ATR shorter than indicated by format character. */
|
||||
atrlen--;
|
||||
atr++;
|
||||
}
|
||||
else
|
||||
have_ta = have_tb = have_tc = have_td = 0;
|
||||
}
|
||||
|
||||
if (n_historical >= atrlen)
|
||||
goto leave; /* ATR shorter than required for historical bytes. */
|
||||
|
||||
if (n_historical)
|
||||
{
|
||||
for (idx=0; n_historical && atrlen; n_historical--, atrlen--, atr++)
|
||||
historical[idx] = *atr;
|
||||
}
|
||||
|
||||
if (!atrlen || *atr != chksum)
|
||||
goto leave;
|
||||
|
||||
/* Don't care about garbage at the end of the ATR. */
|
||||
|
||||
result = n_historical;
|
||||
|
||||
leave:
|
||||
xfree (atrbuffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
292
scd/command.c
292
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))
|
||||
{
|
||||
slot_table[slot].valid = 0;
|
||||
}
|
||||
application_notify_card_reset (slot);
|
||||
switch (apdu_reset (slot))
|
||||
{
|
||||
case 0:
|
||||
break;
|
||||
case SW_HOST_NO_CARD:
|
||||
case SW_HOST_CARD_INACTIVE:
|
||||
break;
|
||||
default:
|
||||
apdu_close_reader (slot);
|
||||
vreader_table[vrdr].slot = slot = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* If we hold a lock, unlock now. */
|
||||
@ -327,25 +360,24 @@ do_reset (ctrl_t ctrl, int send_reset)
|
||||
/* Reset the card removed flag for the current reader. We need to
|
||||
take the lock here so that the ticker thread won't concurrently
|
||||
try to update the file. Calling update_reader_status_file is
|
||||
required to get hold of the new status of the card in the slot
|
||||
required to get hold of the new status of the card in the vreader
|
||||
table. */
|
||||
err = npth_mutex_lock (&status_file_update_lock);
|
||||
if (err)
|
||||
{
|
||||
log_error ("failed to acquire status_fle_update lock: %s\n",
|
||||
strerror (err));
|
||||
ctrl->reader_slot = -1;
|
||||
log_error ("failed to acquire status_file_update lock\n");
|
||||
ctrl->server_local->vreader_idx = -1;
|
||||
return;
|
||||
}
|
||||
update_reader_status_file (0); /* Update slot status table. */
|
||||
update_card_removed (slot, 0); /* Clear card_removed flag. */
|
||||
update_card_removed (vrdr, 0); /* Clear card_removed flag. */
|
||||
err = npth_mutex_unlock (&status_file_update_lock);
|
||||
if (err)
|
||||
log_error ("failed to release status_file_update lock: %s\n",
|
||||
strerror (err));
|
||||
|
||||
/* Do this last, so that the update_card_removed above does its job. */
|
||||
ctrl->reader_slot = -1;
|
||||
ctrl->server_local->vreader_idx = -1;
|
||||
}
|
||||
|
||||
|
||||
@ -385,35 +417,38 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
|
||||
}
|
||||
|
||||
|
||||
/* Return the slot of the current reader or open the reader if no
|
||||
other sessions are using a reader. Note, that we currently support
|
||||
/* Return the index of the current reader or open the reader if no
|
||||
other sessions are using that reader. If it is not possible to
|
||||
open the reader -1 is returned. Note, that we currently support
|
||||
only one reader but most of the code (except for this function)
|
||||
should be able to cope with several readers. */
|
||||
static int
|
||||
get_reader_slot (void)
|
||||
get_current_reader (void)
|
||||
{
|
||||
struct slot_status_s *ss;
|
||||
struct vreader_s *vr;
|
||||
|
||||
ss = &slot_table[0]; /* One reader for now. */
|
||||
/* We only support one reader for now. */
|
||||
vr = &vreader_table[0];
|
||||
|
||||
/* Initialize the item if needed. */
|
||||
if (!ss->valid)
|
||||
/* Initialize the vreader item if not yet done. */
|
||||
if (!vr->valid)
|
||||
{
|
||||
ss->slot = -1;
|
||||
ss->valid = 1;
|
||||
vr->slot = -1;
|
||||
vr->valid = 1;
|
||||
}
|
||||
|
||||
/* Try to open the reader. */
|
||||
if (ss->slot == -1)
|
||||
if (vr->slot == -1)
|
||||
{
|
||||
int no_service_flag;
|
||||
ss->slot = apdu_open_reader (opt.reader_port, &no_service_flag);
|
||||
|
||||
vr->slot = apdu_open_reader (opt.reader_port, &no_service_flag);
|
||||
|
||||
/* If we still don't have a slot, we have no readers.
|
||||
Invalidate for now until a reader is attached. */
|
||||
if(ss->slot == -1)
|
||||
if (vr->slot == -1)
|
||||
{
|
||||
ss->valid = 0;
|
||||
vr->valid = 0;
|
||||
}
|
||||
|
||||
if (no_service_flag)
|
||||
@ -423,18 +458,17 @@ get_reader_slot (void)
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the slot_table index. */
|
||||
return 0;
|
||||
/* Return the vreader index or -1. */
|
||||
return vr->valid ? 0 : -1;
|
||||
}
|
||||
|
||||
/* If the card has not yet been opened, do it. Note that this
|
||||
function returns an Assuan error, so don't map the error a second
|
||||
time. */
|
||||
|
||||
/* If the card has not yet been opened, do it. */
|
||||
static gpg_error_t
|
||||
open_card (ctrl_t ctrl, const char *apptype)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int slot;
|
||||
int vrdr;
|
||||
|
||||
if (reader_disabled)
|
||||
return gpg_error (GPG_ERR_NOT_OPERATIONAL);
|
||||
@ -462,21 +496,25 @@ open_card (ctrl_t ctrl, const char *apptype)
|
||||
need to check that the client didn't requested a specific
|
||||
application different from the one in use before we continue. */
|
||||
if (ctrl->app_ctx)
|
||||
return check_application_conflict (ctrl, apptype);
|
||||
{
|
||||
return check_application_conflict
|
||||
(ctrl, vreader_slot (ctrl->server_local->vreader_idx), apptype);
|
||||
}
|
||||
|
||||
/* Setup the slot and select the application. */
|
||||
if (ctrl->reader_slot != -1)
|
||||
slot = ctrl->reader_slot;
|
||||
/* Setup the vreader and select the application. */
|
||||
if (ctrl->server_local->vreader_idx != -1)
|
||||
vrdr = ctrl->server_local->vreader_idx;
|
||||
else
|
||||
slot = get_reader_slot ();
|
||||
ctrl->reader_slot = slot;
|
||||
if (slot == -1)
|
||||
vrdr = get_current_reader ();
|
||||
ctrl->server_local->vreader_idx = vrdr;
|
||||
if (vrdr == -1)
|
||||
err = gpg_error (reader_disabled? GPG_ERR_NOT_OPERATIONAL: GPG_ERR_CARD);
|
||||
else
|
||||
{
|
||||
/* Fixme: We should move the apdu_connect call to
|
||||
select_application. */
|
||||
int sw;
|
||||
int slot = vreader_slot (vrdr);
|
||||
|
||||
ctrl->server_local->disconnect_allowed = 0;
|
||||
sw = apdu_connect (slot);
|
||||
@ -484,6 +522,8 @@ open_card (ctrl_t ctrl, const char *apptype)
|
||||
{
|
||||
if (sw == SW_HOST_NO_CARD)
|
||||
err = gpg_error (GPG_ERR_CARD_NOT_PRESENT);
|
||||
else if (sw == SW_HOST_CARD_INACTIVE)
|
||||
err = gpg_error (GPG_ERR_CARD_RESET);
|
||||
else
|
||||
err = gpg_error (GPG_ERR_CARD);
|
||||
}
|
||||
@ -523,8 +563,10 @@ cmd_serialno (assuan_context_t ctx, char *line)
|
||||
char *serial_and_stamp;
|
||||
char *serial;
|
||||
time_t stamp;
|
||||
int retries = 0;
|
||||
|
||||
/* Clear the remove flag so that the open_card is able to reread it. */
|
||||
retry:
|
||||
if (!reader_disabled && ctrl->server_local->card_removed)
|
||||
{
|
||||
if ( IS_LOCKED (ctrl) )
|
||||
@ -533,7 +575,12 @@ cmd_serialno (assuan_context_t ctx, char *line)
|
||||
}
|
||||
|
||||
if ((rc = open_card (ctrl, *line? line:NULL)))
|
||||
return rc;
|
||||
{
|
||||
/* In case of an inactive card, retry once. */
|
||||
if (gpg_err_code (rc) == GPG_ERR_CARD_RESET && retries++ < 1)
|
||||
goto retry;
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = app_get_serial_and_stamp (ctrl->app_ctx, &serial, &stamp);
|
||||
if (rc)
|
||||
@ -1613,8 +1660,8 @@ static const char hlp_getinfo[] =
|
||||
"\n"
|
||||
"socket_name - Return the name of the socket.\n"
|
||||
"\n"
|
||||
"status - Return the status of the current slot (in the future, may\n"
|
||||
"also return the status of all slots). The status is a list of\n"
|
||||
"status - Return the status of the current reader (in the future, may\n"
|
||||
"also return the status of all readers). The status is a list of\n"
|
||||
"one-character flags. The following flags are currently defined:\n"
|
||||
" 'u' Usable card present. This is the normal state during operation.\n"
|
||||
" 'r' Card removed. A reset is necessary.\n"
|
||||
@ -1658,22 +1705,18 @@ cmd_getinfo (assuan_context_t ctx, char *line)
|
||||
else if (!strcmp (line, "status"))
|
||||
{
|
||||
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||
int slot = ctrl->reader_slot;
|
||||
int vrdr = ctrl->server_local->vreader_idx;
|
||||
char flag = 'r';
|
||||
|
||||
if (!ctrl->server_local->card_removed && slot != -1)
|
||||
if (!ctrl->server_local->card_removed && vrdr != -1)
|
||||
{
|
||||
struct slot_status_s *ss;
|
||||
struct vreader_s *vr;
|
||||
|
||||
if (!(slot >= 0 && slot < DIM(slot_table)))
|
||||
if (!(vrdr >= 0 && vrdr < DIM(vreader_table)))
|
||||
BUG ();
|
||||
|
||||
ss = &slot_table[slot];
|
||||
|
||||
if (!ss->valid)
|
||||
BUG ();
|
||||
|
||||
if (ss->any && (ss->status & 1))
|
||||
vr = &vreader_table[vrdr];
|
||||
if (vr->valid && vr->any && (vr->status & 1))
|
||||
flag = 'u';
|
||||
}
|
||||
rc = assuan_send_data (ctx, &flag, 1);
|
||||
@ -1759,7 +1802,7 @@ cmd_disconnect (assuan_context_t ctx, char *line)
|
||||
|
||||
|
||||
static const char hlp_apdu[] =
|
||||
"APDU [--atr] [--more] [--exlen[=N]] [hexstring]\n"
|
||||
"APDU [--[dump-]atr] [--more] [--exlen[=N]] [hexstring]\n"
|
||||
"\n"
|
||||
"Send an APDU to the current reader. This command bypasses the high\n"
|
||||
"level functions and sends the data directly to the card. HEXSTRING\n"
|
||||
@ -1788,8 +1831,12 @@ cmd_apdu (assuan_context_t ctx, char *line)
|
||||
int handle_more;
|
||||
const char *s;
|
||||
size_t exlen;
|
||||
int slot;
|
||||
|
||||
with_atr = has_option (line, "--atr");
|
||||
if (has_option (line, "--dump-atr"))
|
||||
with_atr = 2;
|
||||
else
|
||||
with_atr = has_option (line, "--atr");
|
||||
handle_more = has_option (line, "--more");
|
||||
|
||||
if ((s=has_option_name (line, "--exlen")))
|
||||
@ -1810,21 +1857,46 @@ cmd_apdu (assuan_context_t ctx, char *line)
|
||||
if ((rc = open_card (ctrl, NULL)))
|
||||
return rc;
|
||||
|
||||
slot = vreader_slot (ctrl->server_local->vreader_idx);
|
||||
|
||||
if (with_atr)
|
||||
{
|
||||
unsigned char *atr;
|
||||
size_t atrlen;
|
||||
char hexbuf[400];
|
||||
|
||||
atr = apdu_get_atr (ctrl->reader_slot, &atrlen);
|
||||
atr = apdu_get_atr (slot, &atrlen);
|
||||
if (!atr || atrlen > sizeof hexbuf - 2 )
|
||||
{
|
||||
rc = gpg_error (GPG_ERR_INV_CARD);
|
||||
goto leave;
|
||||
}
|
||||
bin2hex (atr, atrlen, hexbuf);
|
||||
if (with_atr == 2)
|
||||
{
|
||||
char *string, *p, *pend;
|
||||
|
||||
string = atr_dump (atr, atrlen);
|
||||
if (string)
|
||||
{
|
||||
for (rc=0, p=string; !rc && (pend = strchr (p, '\n')); p = pend+1)
|
||||
{
|
||||
rc = assuan_send_data (ctx, p, pend - p + 1);
|
||||
if (!rc)
|
||||
rc = assuan_send_data (ctx, NULL, 0);
|
||||
}
|
||||
if (!rc && *p)
|
||||
rc = assuan_send_data (ctx, p, strlen (p));
|
||||
es_free (string);
|
||||
if (rc)
|
||||
goto leave;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bin2hex (atr, atrlen, hexbuf);
|
||||
send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
|
||||
}
|
||||
xfree (atr);
|
||||
send_status_info (ctrl, "CARD-ATR", hexbuf, strlen (hexbuf), NULL, 0);
|
||||
}
|
||||
|
||||
apdu = hex_to_buffer (line, &apdulen);
|
||||
@ -1838,7 +1910,7 @@ cmd_apdu (assuan_context_t ctx, char *line)
|
||||
unsigned char *result = NULL;
|
||||
size_t resultlen;
|
||||
|
||||
rc = apdu_send_direct (ctrl->reader_slot, exlen,
|
||||
rc = apdu_send_direct (slot, exlen,
|
||||
apdu, apdulen, handle_more,
|
||||
&result, &resultlen);
|
||||
if (rc)
|
||||
@ -1869,15 +1941,8 @@ cmd_killscd (assuan_context_t ctx, char *line)
|
||||
(void)line;
|
||||
|
||||
ctrl->server_local->stopme = 1;
|
||||
#ifdef ASSUAN_FORCE_CLOSE
|
||||
assuan_set_flag (ctx, ASSUAN_FORCE_CLOSE, 1);
|
||||
return 0;
|
||||
#else
|
||||
/* Actually returning an EOF does not anymore work with modern
|
||||
Libassuan versions. However we keep that non working code until
|
||||
we make a Libassuan with the force close flag a requirement. */
|
||||
return gpg_error (GPG_ERR_EOF);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -1988,12 +2053,13 @@ scd_command_handler (ctrl_t ctrl, int fd)
|
||||
session_list = ctrl->server_local;
|
||||
ctrl->server_local->ctrl_backlink = ctrl;
|
||||
ctrl->server_local->assuan_ctx = ctx;
|
||||
ctrl->server_local->vreader_idx = -1;
|
||||
|
||||
/* We open the reader right at startup so that the ticker is able to
|
||||
update the status file. */
|
||||
if (ctrl->reader_slot == -1)
|
||||
if (ctrl->server_local->vreader_idx == -1)
|
||||
{
|
||||
ctrl->reader_slot = get_reader_slot ();
|
||||
ctrl->server_local->vreader_idx = get_current_reader ();
|
||||
}
|
||||
|
||||
/* Command processing loop. */
|
||||
@ -2195,32 +2261,33 @@ update_reader_status_file (int set_card_removed_flag)
|
||||
int idx;
|
||||
unsigned int status, changed;
|
||||
|
||||
/* Make sure that the reader has been opened. Like get_reader_slot,
|
||||
/* Make sure that a reader has been opened. Like get_current_reader,
|
||||
this part of the code assumes that there is only one reader. */
|
||||
if (!slot_table[0].valid)
|
||||
(void)get_reader_slot ();
|
||||
if (!vreader_table[0].valid)
|
||||
(void)get_current_reader ();
|
||||
|
||||
/* Note, that we only try to get the status, because it does not
|
||||
make sense to wait here for a operation to complete. If we are
|
||||
busy working with a card, delays in the status file update should
|
||||
be acceptable. */
|
||||
for (idx=0; idx < DIM(slot_table); idx++)
|
||||
for (idx=0; idx < DIM(vreader_table); idx++)
|
||||
{
|
||||
struct slot_status_s *ss = slot_table + idx;
|
||||
struct vreader_s *vr = vreader_table + idx;
|
||||
struct server_local_s *sl;
|
||||
int sw_apdu;
|
||||
|
||||
if (!ss->valid || ss->slot == -1)
|
||||
if (!vr->valid || vr->slot == -1)
|
||||
continue; /* Not valid or reader not yet open. */
|
||||
|
||||
sw_apdu = apdu_get_status (ss->slot, 0, &status, &changed);
|
||||
sw_apdu = apdu_get_status (vr->slot, 0, &status, &changed);
|
||||
if (sw_apdu == SW_HOST_NO_READER)
|
||||
{
|
||||
/* Most likely the _reader_ has been unplugged. */
|
||||
apdu_close_reader(ss->slot);
|
||||
ss->valid = 0;
|
||||
application_notify_card_reset (vr->slot);
|
||||
apdu_close_reader (vr->slot);
|
||||
vr->slot = -1;
|
||||
status = 0;
|
||||
changed = ss->changed;
|
||||
changed = vr->changed;
|
||||
}
|
||||
else if (sw_apdu)
|
||||
{
|
||||
@ -2228,21 +2295,21 @@ update_reader_status_file (int set_card_removed_flag)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ss->any || ss->status != status || ss->changed != changed )
|
||||
if (!vr->any || vr->status != status || vr->changed != changed )
|
||||
{
|
||||
char *fname;
|
||||
char templ[50];
|
||||
FILE *fp;
|
||||
|
||||
log_info ("updating slot %d status: 0x%04X->0x%04X (%u->%u)\n",
|
||||
ss->slot, ss->status, status, ss->changed, changed);
|
||||
ss->status = status;
|
||||
ss->changed = changed;
|
||||
log_info ("updating reader %d (%d) status: 0x%04X->0x%04X (%u->%u)\n",
|
||||
idx, vr->slot, vr->status, status, vr->changed, changed);
|
||||
vr->status = status;
|
||||
vr->changed = changed;
|
||||
|
||||
/* FIXME: Should this be IDX instead of ss->slot? This
|
||||
/* FIXME: Should this be IDX instead of vr->slot? This
|
||||
depends on how client sessions will associate the reader
|
||||
status with their session. */
|
||||
snprintf (templ, sizeof templ, "reader_%d.status", ss->slot);
|
||||
snprintf (templ, sizeof templ, "reader_%d.status", vr->slot);
|
||||
fname = make_filename (opt.homedir, templ, NULL );
|
||||
fp = fopen (fname, "w");
|
||||
if (fp)
|
||||
@ -2270,8 +2337,8 @@ update_reader_status_file (int set_card_removed_flag)
|
||||
envs[0] = envstr;
|
||||
envs[1] = NULL;
|
||||
|
||||
sprintf (numbuf1, "%d", ss->slot);
|
||||
sprintf (numbuf2, "0x%04X", ss->status);
|
||||
sprintf (numbuf1, "%d", vr->slot);
|
||||
sprintf (numbuf2, "0x%04X", vr->status);
|
||||
sprintf (numbuf3, "0x%04X", status);
|
||||
args[0] = "--reader-port";
|
||||
args[1] = numbuf1;
|
||||
@ -2299,10 +2366,10 @@ update_reader_status_file (int set_card_removed_flag)
|
||||
/* Set the card removed flag for all current sessions. We
|
||||
will set this on any card change because a reset or
|
||||
SERIALNO request must be done in any case. */
|
||||
if (ss->any && set_card_removed_flag)
|
||||
if (vr->any && set_card_removed_flag)
|
||||
update_card_removed (idx, 1);
|
||||
|
||||
ss->any = 1;
|
||||
vr->any = 1;
|
||||
|
||||
/* Send a signal to all clients who applied for it. */
|
||||
send_client_notifications ();
|
||||
@ -2318,8 +2385,9 @@ update_reader_status_file (int set_card_removed_flag)
|
||||
{
|
||||
/* FIXME: Use a real timeout. */
|
||||
/* At least one connection and all allow a disconnect. */
|
||||
log_info ("disconnecting card in slot %d\n", ss->slot);
|
||||
apdu_disconnect (ss->slot);
|
||||
log_info ("disconnecting card in reader %d (%d)\n",
|
||||
idx, vr->slot);
|
||||
apdu_disconnect (vr->slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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"));
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
242
sm/certreqgen.c
242
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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
29
sm/keylist.c
29
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)
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -0,0 +1,10 @@
|
||||
(private-key
|
||||
(rsa
|
||||
(n #0093687D92A7BCD1E6FC11263B50657A8FA4B9CEE3F90E23384D62778CA1B6CBE0F60B20354A5F74899EB3C8DDF3081D32475C71869BB0C5DAF0051A2F44596E7406F1DCC7B29D88735E49341F09F4DFCAB5A08B76614C37220CF7E2CDB8A38E79644F3A250FFAE5D0BBA6917C67523D2812FDE8D3BEA9947F6A55402B1600C12F#)
|
||||
(e #010001#)
|
||||
(d #11BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE926B54482C04EDE1C59E877B5F382114F8D1BAAE905D3988DFC39FEF462A0655AC906CBC12F6D322795D3988DFC39FEF462A0655AC906CBC12F6D322795D3988DFC39FEF462A0655AC906CBC12F6D322795D3983C1#)
|
||||
(p "\x00ÂBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBAÏ")
|
||||
(q "\x00ÂBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¡")
|
||||
(u #00B28879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C2213728879D8EEE03F5546A5BBAD0C221372887A30#)
|
||||
)
|
||||
)
|
@ -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.
|
||||
|
||||
|
||||
|
54
tests/samplekeys/steed-self-signing-nonthority.pem
Normal file
54
tests/samplekeys/steed-self-signing-nonthority.pem
Normal file
@ -0,0 +1,54 @@
|
||||
|
||||
ID: 0x72B0BD08
|
||||
S/N: 01
|
||||
Issuer: CN=The STEED Self-Signing Nonthority
|
||||
Subject: CN=The STEED Self-Signing Nonthority
|
||||
sha1_fpr: E6:99:39:A2:5F:5D:93:F2:06:71:5D:C9:FC:1A:25:DC:72:B0:BD:08
|
||||
md5_fpr: C9:83:C8:13:91:53:5A:C2:9A:BA:AF:0E:9C:AF:93:0E
|
||||
certid: BA9A5990A0E94A627D08D4D06FD15EC561FD15E8.01
|
||||
keygrip: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
|
||||
notBefore: 2011-11-11 00:00:00
|
||||
notAfter: 2106-02-06 00:00:00
|
||||
hashAlgo: 1.2.840.113549.1.1.5 (sha1WithRSAEncryption)
|
||||
keyType: 1024 bit RSA
|
||||
subjKeyId: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
|
||||
authKeyId: [none]
|
||||
keyUsage: certSign crlSign
|
||||
extKeyUsage: [none]
|
||||
policies: [none]
|
||||
chainLength: 1
|
||||
crlDP: [none]
|
||||
authInfo: [none]
|
||||
subjInfo: [none]
|
||||
extn: 1.3.6.1.4.1.11591.2.2.2 (wellKnownPrivateKey) [3 octets]
|
||||
|
||||
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIICKDCCAZGgAwIBAgIBATANBgkqhkiG9w0BAQUFADAsMSowKAYDVQQDEyFUaGUg
|
||||
U1RFRUQgU2VsZi1TaWduaW5nIE5vbnRob3JpdHkwIBcNMTExMTExMDAwMDAwWhgP
|
||||
MjEwNjAyMDYwMDAwMDBaMCwxKjAoBgNVBAMTIVRoZSBTVEVFRCBTZWxmLVNpZ25p
|
||||
bmcgTm9udGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAk2h9kqe8
|
||||
0eb8ESY7UGV6j6S5zuP5DiM4TWJ3jKG2y+D2CyA1Sl90iZ6zyN3zCB0yR1xxhpuw
|
||||
xdrwBRovRFludAbx3MeynYhzXkk0Hwn038q1oIt2YUw3Igz34s24o455ZE86JQ/6
|
||||
5dC7ppF8Z1I9KBL96NO+qZR/alVAKxYAwS8CAwEAAaNYMFYwEgYDVR0TAQH/BAgw
|
||||
BgEB/wIBATARBgorBgEEAdpHAgICBAMBAf8wHQYDVR0OBBYEFGimOJmN+rrFEOpk
|
||||
XONPloay7ffqMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOBgQB3JwUn
|
||||
AbOdGv5ErojNSSP+yGZIy5av4wnkzK840Uj3jY6A5cuHroZGOD60hqLV2Hy0npox
|
||||
zte4phWEKWmZiXd8SCmd3MFNgZSieiixye0qxSmuqYft2j6NhEXD5xc/iTTjFT42
|
||||
SjGPLKAICuMBuGPnoozOEVlgqwaDqKOUph5sqw==
|
||||
-----END CERTIFICATE-----
|
||||
|
||||
Created using these parameters:
|
||||
|
||||
Key-Type: RSA
|
||||
Key-Length: 1024
|
||||
Key-Grip: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
|
||||
Key-Usage: cert
|
||||
Serial: 1
|
||||
Name-DN: CN=The STEED Self-Signing Nonthority
|
||||
Not-Before: 2011-11-11
|
||||
Not-After: 2106-02-06
|
||||
Subject-Key-Id: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
|
||||
Extension: 2.5.29.19 c 30060101ff020101
|
||||
Extension: 1.3.6.1.4.1.11591.2.2.2 n 0101ff
|
||||
Signing-Key: 68A638998DFABAC510EA645CE34F9686B2EDF7EA
|
@ -5,10 +5,6 @@
|
||||
commit log, and generate a top-level ChangeLog file from logs at
|
||||
"make dist". See doc/HACKING for details.
|
||||
|
||||
2011-10-13 Marcus Brinkmann <marcus@g10code.com>
|
||||
|
||||
* Makefile.am: Port to NPth.
|
||||
|
||||
2011-08-26 Werner Koch <wk@g10code.com>
|
||||
|
||||
* gpgconf-comp.c (gc_component): Mark for translation. Suggested
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user