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