Preparing an interim release

This commit is contained in:
Werner Koch 2005-11-28 11:52:25 +00:00
parent 000a38ccf2
commit 6a13cf2c3d
32 changed files with 785 additions and 171 deletions

View File

@ -1,3 +1,19 @@
2005-11-28 Werner Koch <wk@g10code.com>
* configure.ac: Append the revision to the version string.
2005-11-13 Werner Koch <wk@g10code.com>
* am/cmacros.am (-DGNUPG_SYSCONFDIR): Define it.
2005-11-11 Werner Koch <wk@g10code.com>
* configure.ac (NEED_KSBA_VERSION: Require 0.9.13.
2005-09-12 Werner Koch <wk@g10code.com>
Released 1.9.19.
2005-08-01 Werner Koch <wk@g10code.com>
Released 1.9.18.

7
NEWS
View File

@ -1,3 +1,10 @@
Noteworthy changes in version 1.9.20
-------------------------------------------------
* [scdaemon] Support for keypads of some readers. Tested only with
SPR532. New option --disable-keypad.
Noteworthy changes in version 1.9.19 (2005-09-12)
-------------------------------------------------

1
TODO
View File

@ -26,7 +26,6 @@ might want to have an agent context for each service request
* sm/gpgsm.c
** Support --output for all commands
** mark all unimplemented commands and options.
** Print a hint when MD2 is the cause for a problem.
** Implement --default-key
** support the anyPolicy semantic
** Check that we are really following the verification procedures in rfc3280.

View File

@ -1,3 +1,20 @@
2005-11-24 Werner Koch <wk@g10code.com>
* minip12.c (p12_parse): Fixed for case that the key object comes
prior to the certificate.
2005-10-19 Werner Koch <wk@g10code.com>
* divert-scd.c (getpin_cb): Hack to use it for a keypad message.
* call-scd.c (inq_needpin): Reworked to support the new KEYPADINFO.
* query.c (start_pinentry): Keep track of the owner.
(popup_message_thread, agent_popup_message_start)
(agent_popup_message_stop, agent_reset_query): New.
* command.c (start_command_handler): Make sure a popup window gets
closed.
2005-10-08 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (gpg_protect_tool_LDADD): Add ../gl/libgnu.a.

View File

@ -133,7 +133,7 @@ struct server_control_s
int have_keygrip;
int use_auth_call; /* Hack to send the PKAUTH command instead of the
PKSIGN command tro scdaemon. */
PKSIGN command to the scdaemon. */
};
typedef struct server_control_s *CTRL;
typedef struct server_control_s *ctrl_t;
@ -200,6 +200,7 @@ int agent_key_available (const unsigned char *grip);
/*-- query.c --*/
void initialize_module_query (void);
void agent_query_dump_state (void);
void agent_reset_query (ctrl_t ctrl);
int agent_askpin (ctrl_t ctrl,
const char *desc_text, const char *prompt_text,
const char *inital_errtext,
@ -209,6 +210,10 @@ int agent_get_passphrase (ctrl_t ctrl, char **retpass,
const char *errtext);
int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok,
const char *cancel);
int agent_popup_message_start (ctrl_t ctrl, const char *desc,
const char *ok_btn, const char *cancel_btn);
void agent_popup_message_stop (ctrl_t ctrl);
/*-- cache.c --*/
void agent_flush_cache (void);

View File

@ -633,26 +633,43 @@ inq_needpin (void *opaque, const char *line)
size_t pinlen;
int rc;
if (!(!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7])))
if (!strncmp (line, "NEEDPIN", 7) && (line[7] == ' ' || !line[7]))
{
line += 7;
while (*line == ' ')
line++;
pinlen = 90;
pin = gcry_malloc_secure (pinlen);
if (!pin)
return ASSUAN_Out_Of_Core;
rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen);
if (rc)
rc = ASSUAN_Canceled;
if (!rc)
rc = assuan_send_data (parm->ctx, pin, pinlen);
xfree (pin);
}
else if (!strncmp (line, "KEYPADINFO", 10) && (line[10] == ' ' || !line[10]))
{
size_t code;
char *endp;
code = strtoul (line+10, &endp, 10);
line = endp;
while (*line == ' ')
line++;
rc = parm->getpin_cb (parm->getpin_cb_arg, line, NULL, code);
if (rc)
rc = ASSUAN_Canceled;
}
else
{
log_error ("unsupported inquiry `%s'\n", line);
return ASSUAN_Inquire_Unknown;
rc = ASSUAN_Inquire_Unknown;
}
line += 7;
while (*line == ' ')
line++;
pinlen = 90;
pin = gcry_malloc_secure (pinlen);
if (!pin)
return ASSUAN_Out_Of_Core;
rc = parm->getpin_cb (parm->getpin_cb_arg, line, pin, pinlen);
if (rc)
rc = ASSUAN_Canceled;
if (!rc)
rc = assuan_send_data (parm->ctx, pin, pinlen);
xfree (pin);
return rc;
}

View File

@ -316,11 +316,11 @@ cmd_sigkey (ASSUAN_CONTEXT ctx, char *line)
this command is not used a default text will be used. Note, that
this description implictly selects the label used for the entry
box; if the string contains the string PIN (which in general will
not be translated), "PIN" is used, other wiese the translation of
not be translated), "PIN" is used, otherwise the translation of
'passphrase" is used. The description string should not contain
blanks unless they are percent or '+' escaped.
The descrition is only valid for the next PKSIGN or PKDECRYPT
The description is only valid for the next PKSIGN or PKDECRYPT
operation.
*/
static int
@ -399,7 +399,7 @@ cmd_sethash (ASSUAN_CONTEXT ctx, char *line)
/* PKSIGN <options>
Perform the actual sign operation. Neither input nor output are
sensitive to eavesdropping */
sensitive to eavesdropping. */
static int
cmd_pksign (ASSUAN_CONTEXT ctx, char *line)
{
@ -1085,6 +1085,9 @@ start_command_handler (int listen_fd, int fd)
/* Reset the SCD if needed. */
agent_reset_scd (&ctrl);
/* Reset the pinentry (in case of popup messages). */
agent_reset_query (&ctrl);
assuan_deinit_server (ctx);
if (ctrl.display)
free (ctrl.display);

View File

@ -204,7 +204,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
const char *again_text = NULL;
const char *prompt = "PIN";
if (maxbuf < 2)
if (buf && maxbuf < 2)
return gpg_error (GPG_ERR_INV_VALUE);
/* Parse the flags. */
@ -223,6 +223,23 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
else if (info && *info == '|')
log_debug ("pin_cb called without proper PIN info hack\n");
/* If BUF has been passed as NULL, we are in keypad mode: The
callback opens the popup and immediatley returns. */
if (!buf)
{
if (maxbuf == 0) /* Close the pinentry. */
{
agent_popup_message_stop (ctrl);
rc = 0;
}
else if (maxbuf == 1) /* Open the pinentry. */
{
rc = agent_popup_message_start (ctrl, info, NULL, NULL);
}
else
rc = gpg_error (GPG_ERR_INV_VALUE);
return rc;
}
/* FIXME: keep PI and TRIES in OPAQUE. Frankly this is a whole
mess because we should call the card's verify function from the

View File

@ -511,7 +511,7 @@ parse_bag_encrypted_data (const unsigned char *buffer, size_t length,
goto bailout;
}
/* Loop over all certificates inside the bab. */
/* Loop over all certificates inside the bag. */
while (n)
{
int isbag = 0;
@ -860,6 +860,7 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
size_t n = length;
const char *where;
int bagseqlength, len;
gcry_mpi_t *result = NULL;
where = "pfx";
if (parse_tag (&p, &n, &ti))
@ -936,10 +937,17 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
else if (ti.tag == TAG_OBJECT_ID && ti.length == DIM(oid_data)
&& !memcmp (p, oid_data, DIM(oid_data)))
{
p += DIM(oid_data);
n -= DIM(oid_data);
len -= DIM(oid_data);
return parse_bag_data (p, n, (p-buffer), pw);
if (result)
log_info ("already got an data object, skipping next one\n");
else
{
p += DIM(oid_data);
n -= DIM(oid_data);
len -= DIM(oid_data);
result = parse_bag_data (p, n, (p-buffer), pw);
if (!result)
goto bailout;
}
}
else
log_info ( "unknown bag type - skipped\n");
@ -950,9 +958,10 @@ p12_parse (const unsigned char *buffer, size_t length, const char *pw,
n -= len;
}
return NULL;
return result;
bailout:
log_error ("error at \"%s\", offset %u\n", where, (p - buffer));
/* fixme: need to release RESULT. */
return NULL;
}

View File

@ -27,9 +27,10 @@
#include <assert.h>
#include <unistd.h>
#include <sys/stat.h>
#ifdef USE_GNU_PTH
# include <pth.h>
#ifndef HAVE_W32_SYSTEM
#include <sys/wait.h>
#endif
#include <pth.h>
#include "agent.h"
#include "i18n.h"
@ -48,14 +49,30 @@
time. */
#define LOCK_TIMEOUT (1*60)
/* The assuan context of the current pinentry. */
static assuan_context_t entry_ctx;
static assuan_context_t entry_ctx = NULL;
#ifdef USE_GNU_PTH
/* The control variable of the connection owning the current pinentry.
This is only valid if ENTRY_CTX is not NULL. Note, that we care
only about the value of the pointer and that it should never be
dereferenced. */
static ctrl_t entry_owner;
/* A mutex used to serialize access to the pinentry. */
static pth_mutex_t entry_lock;
#endif
/* data to be passed to our callbacks */
struct entry_parm_s {
/* The thread ID of the popup working thread. */
static pth_t popup_tid;
/* A flag used in communication between the popup working thread and
its stop function. */
static int popup_finished;
/* Data to be passed to our callbacks, */
struct entry_parm_s
{
int lines;
size_t size;
unsigned char *buffer;
@ -67,17 +84,17 @@ struct entry_parm_s {
/* This function must be called once to initialize this module. This
has to be done before a second thread is spawned. We can't do the
static initialization because Pth emulation code might not be able
to do a static init; in particualr, it is not possible for W32. */
to do a static init; in particular, it is not possible for W32. */
void
initialize_module_query (void)
{
#ifdef USE_GNU_PTH
static int initialized;
if (!initialized)
if (pth_mutex_init (&entry_lock))
initialized = 1;
#endif /*USE_GNU_PTH*/
{
if (pth_mutex_init (&entry_lock))
initialized = 1;
}
}
@ -102,8 +119,19 @@ agent_query_dump_state (void)
log_info ("agent_query_dump_state: entry_lock=");
dump_mutex_state (&entry_lock);
log_printf ("\n");
log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld\n",
entry_ctx, (long)assuan_get_pid (entry_ctx));
log_info ("agent_query_dump_state: entry_ctx=%p pid=%ld popup_tid=%p\n",
entry_ctx, (long)assuan_get_pid (entry_ctx), popup_tid);
}
/* Called to make sure that a popup window owned by the current
connection gets closed. */
void
agent_reset_query (ctrl_t ctrl)
{
if (entry_ctx && popup_tid && entry_owner == ctrl)
{
agent_popup_message_stop (ctrl);
}
}
@ -117,14 +145,12 @@ unlock_pinentry (int rc)
assuan_context_t ctx = entry_ctx;
entry_ctx = NULL;
#ifdef USE_GNU_PTH
if (!pth_mutex_release (&entry_lock))
{
log_error ("failed to release the entry lock\n");
if (!rc)
rc = gpg_error (GPG_ERR_INTERNAL);
}
#endif
assuan_disconnect (ctx);
return rc;
}
@ -145,7 +171,7 @@ atfork_cb (void *opaque, int where)
pinentry - we will serialize _all_ pinentry calls.
*/
static int
start_pinentry (CTRL ctrl)
start_pinentry (ctrl_t ctrl)
{
int rc;
const char *pgmname;
@ -153,13 +179,10 @@ start_pinentry (CTRL ctrl)
const char *argv[5];
int no_close_list[3];
int i;
pth_event_t evt;
#ifdef USE_GNU_PTH
{
pth_event_t evt;
evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
if (!pth_mutex_acquire (&entry_lock, 0, evt))
evt = pth_event (PTH_EVENT_TIME, pth_timeout (LOCK_TIMEOUT, 0));
if (!pth_mutex_acquire (&entry_lock, 0, evt))
{
if (pth_event_occurred (evt))
rc = gpg_error (GPG_ERR_TIMEOUT);
@ -170,9 +193,9 @@ start_pinentry (CTRL ctrl)
gpg_strerror (rc));
return rc;
}
pth_event_free (evt, PTH_FREE_THIS);
}
#endif
pth_event_free (evt, PTH_FREE_THIS);
entry_owner = ctrl;
if (entry_ctx)
return 0;
@ -436,7 +459,7 @@ agent_askpin (ctrl_t ctrl,
passphrase is returned in RETPASS as an hex encoded string to be
freed by the caller */
int
agent_get_passphrase (CTRL ctrl,
agent_get_passphrase (ctrl_t ctrl,
char **retpass, const char *desc, const char *prompt,
const char *errtext)
{
@ -517,11 +540,11 @@ agent_get_passphrase (CTRL ctrl,
/* Pop up the PIN-entry, display the text and the prompt and ask the
user to confirm this. We return 0 for success, ie. the used
user to confirm this. We return 0 for success, ie. the user
confirmed it, GPG_ERR_NOT_CONFIRMED for what the text says or an
other error. */
int
agent_get_confirmation (CTRL ctrl,
agent_get_confirmation (ctrl_t ctrl,
const char *desc, const char *ok, const char *cancel)
{
int rc;
@ -562,4 +585,119 @@ agent_get_confirmation (CTRL ctrl,
}
/* The thread running the popup message. */
static void *
popup_message_thread (void *arg)
{
assuan_transact (entry_ctx, "CONFIRM", NULL, NULL, NULL, NULL, NULL, NULL);
popup_finished = 1;
return NULL;
}
/* Pop up a message window similar to the confirm one but keep it open
until agent_popup_message_stop has been called. It is crucial for
the caller to make sure that the stop function gets called as soon
as the message is not anymore required becuase the message is
system modal and all other attempts to use the pinentry will fail
(after a timeout). */
int
agent_popup_message_start (ctrl_t ctrl, const char *desc,
const char *ok_btn, const char *cancel_btn)
{
int rc;
char line[ASSUAN_LINELENGTH];
pth_attr_t tattr;
rc = start_pinentry (ctrl);
if (rc)
return rc;
if (desc)
snprintf (line, DIM(line)-1, "SETDESC %s", desc);
else
snprintf (line, DIM(line)-1, "RESET");
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
if (ok_btn)
{
snprintf (line, DIM(line)-1, "SETOK %s", ok_btn);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
if (cancel_btn)
{
snprintf (line, DIM(line)-1, "SETCANCEL %s", cancel_btn);
line[DIM(line)-1] = 0;
rc = assuan_transact (entry_ctx, line, NULL,NULL,NULL,NULL,NULL,NULL);
if (rc)
return unlock_pinentry (map_assuan_err (rc));
}
tattr = pth_attr_new();
pth_attr_set (tattr, PTH_ATTR_JOINABLE, 1);
pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 256*1024);
pth_attr_set (tattr, PTH_ATTR_NAME, "popup-message");
popup_finished = 0;
popup_tid = pth_spawn (tattr, popup_message_thread, NULL);
if (!popup_tid)
{
rc = gpg_error_from_errno (errno);
log_error ("error spawning popup message handler: %s\n",
strerror (errno) );
pth_attr_destroy (tattr);
return unlock_pinentry (rc);
}
pth_attr_destroy (tattr);
return 0;
}
/* Close a popup window. */
void
agent_popup_message_stop (ctrl_t ctrl)
{
int rc;
pid_t pid;
if (!popup_tid || !entry_ctx)
{
log_debug ("agent_popup_message_stop called with no active popup\n");
return;
}
pid = assuan_get_pid (entry_ctx);
if (pid == (pid_t)(-1))
; /* No pid available can't send a kill. */
else if (popup_finished)
; /* Already finished and ready for joining. */
else if (pid && ((rc=waitpid (pid, NULL, WNOHANG))==-1 || (rc == pid)) )
{ /* The daemon already died. No need to send a kill. However
because we already waited for the process, we need to tell
assuan that it should not wait again (done by
unlock_pinentry). */
if (rc == pid)
assuan_set_flag (entry_ctx, ASSUAN_NO_WAITPID, 1);
}
else
kill (pid, SIGINT);
/* Now wait for the thread to terminate. */
rc = pth_join (popup_tid, NULL);
if (!rc)
log_debug ("agent_popup_message_stop: pth_join failed: %s\n",
strerror (errno));
popup_tid = NULL;
entry_owner = NULL;
/* Now we can close the connection. */
unlock_pinentry (0);
}

View File

@ -173,7 +173,8 @@ test_agent_protect (void)
for (i = 0; i < DIM (specs); i++)
{
ret = agent_protect (specs[i].key, specs[i].passphrase,
ret = agent_protect ((const unsigned char*)specs[i].key,
specs[i].passphrase,
&specs[i].result, &specs[i].resultlen);
if (gpg_err_code (ret) != specs[i].ret_expected)
{

View File

@ -25,7 +25,8 @@ if ! HAVE_DOSISH_SYSTEM
AM_CPPFLAGS += -DGNUPG_BINDIR="\"$(bindir)\"" \
-DGNUPG_LIBEXECDIR="\"$(libexecdir)\"" \
-DGNUPG_LIBDIR="\"$(libdir)/@PACKAGE@\"" \
-DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\""
-DGNUPG_DATADIR="\"$(datadir)/@PACKAGE@\"" \
-DGNUPG_SYSCONFDIR="\"$(sysconfdir)/@PACKAGE@\""
endif
if GNUPG_AGENT_PGM

View File

@ -22,9 +22,12 @@
AC_PREREQ(2.52)
min_automake_version="1.9.3"
# Version number: Remember to change it immediately *after* a release.
# Add a "-cvs" prefix for non-released code.
AC_INIT(gnupg, 1.9.19, gnupg-devel@gnupg.org)
# Remember to change the version number immediately *after* a release.
# Uncomment the my_iscvs macro for non-released code.
m4_define(my_version, [1.9.20])
m4_define(my_iscvs, yes)
AC_INIT([gnupg], my_version[]m4_ifdef([my_iscvs], [-cvs[]m4_translit(
[$Revision$],[Ra-z $:])]), [gnupg-devel@gnupg.org])
# Set development_version to yes if the minor number is odd or you
# feel that the default check for a development version is not
# sufficient.
@ -36,7 +39,7 @@ NEED_LIBGCRYPT_VERSION=1.1.94
NEED_LIBASSUAN_VERSION=0.6.10
NEED_KSBA_VERSION=0.9.12
NEED_KSBA_VERSION=0.9.13
PACKAGE=$PACKAGE_NAME

View File

@ -61,7 +61,7 @@ X.509 specific are noted like [X.509: xxx]
u32 offset to the n-th key's keyID (a keyID is always 8 byte)
or 0 if not known which is the case only for X509.
u16 special key flags
bit 0 =
bit 0 = qualified signature (not yet implemented}
u16 reserved
u16 size of serialnumber(may be zero)
n u16 (see above) bytes of serial number

View File

@ -17,6 +17,7 @@ kbx/kbxutil.c
scd/scdaemon.c
scd/app-openpgp.c
scd/app-nks.c
sm/base64.c
sm/call-agent.c

View File

@ -10,8 +10,8 @@ msgid ""
msgstr ""
"Project-Id-Version: gnupg2 1.9.18\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"POT-Creation-Date: 2005-11-23 13:00+0100\n"
"PO-Revision-Date: 2005-11-23 13:02+0100\n"
"POT-Creation-Date: 2005-11-28 12:14+0100\n"
"PO-Revision-Date: 2005-11-28 12:16+0100\n"
"Last-Translator: Werner Koch <wk@gnupg.org>\n"
"Language-Team: de\n"
"MIME-Version: 1.0\n"
@ -766,6 +766,10 @@ msgstr ""
msgid "can't access %s - invalid OpenPGP card?\n"
msgstr "Zugriff auf %s nicht möglich - ungültige OpenPGP Karte?\n"
#: scd/app-nks.c:344
msgid "the NullPIN has not yet been changed\n"
msgstr "Die Nullpin wurde noch nicht geändert\n"
#: sm/base64.c:317
#, c-format
msgid "invalid radix64 character %02x skipped\n"
@ -1369,7 +1373,7 @@ msgstr "Signieren mit `%s' nicht möglich: %s\n"
#: sm/gpgsm.c:1475
msgid "this command has not yet been implemented\n"
msgstr "Diee Kommando wurde noch nicht implementiert\n"
msgstr "Dieses Kommando wurde noch nicht implementiert\n"
#: sm/gpgsm.c:1705 sm/gpgsm.c:1742 sm/qualified.c:73
#, c-format
@ -1548,10 +1552,10 @@ msgid ""
msgstr ""
"Sie sind dabei, eine Signatur mit dem Zertifikat:\n"
"\"%s\"\n"
"zu erzeugen. Dies wird einen qualifizierte Signatur erzeugen, \n"
"die gesetzlich einer handgeschriebene gleichgestellt ist.\n"
"zu erzeugen. Dies wird eine qualifizierte Signatur erzeugen, \n"
"die gesetzlich einer handgeschriebenen gleichgestellt ist.\n"
"\n"
"%s%sSind Sie wirklich sicher, da Sie dies möchten?"
"%s%sSind Sie wirklich sicher, daß Sie dies möchten?"
#: sm/qualified.c:224
msgid ""

View File

@ -1,8 +1,63 @@
2005-11-23 Werner Koch <wk@g10code.com>
* app-nks.c (verify_pin): Give a special error message for a Nullpin.
2005-10-29 Werner Koch <wk@g10code.com>
* ccid-driver.c (send_escape_cmd): New args RESULT, RESULTLEN and
RESULTMAX. Changed all callers.
(ccid_transceive_escape): New.
2005-10-27 Werner Koch <wk@g10code.com>
* apdu.c [__CYGWIN__]: Make cygwin environment similar to _WIN32.
Suggested by John P. Clizbe.
* scdaemon.c [__CYGWIN__]: Set default PC/SC driver to winscard.dll.
2005-10-19 Werner Koch <wk@g10code.com>
* ccid-driver.h (CCID_DRIVER_ERR_NO_KEYPAD): New.
* apdu.h (SW_HOST_NO_KEYPAD): New.
* iso7816.h (struct iso7816_pininfo_s): New.
* iso7816.c (map_sw): Support new code.
(iso7816_check_keypad): New.
(iso7816_verify_kp, iso7816_change_reference_data_kp)
(iso7816_reset_retry_counter_kp): New. Extended versions of the
original functions.
* apdu.c (host_sw_string): Support new code.
(reader_table_s): New field CHECK_KEYPAD.
(new_reader_slot, open_ct_reader, open_pcsc_reader)
(open_ccid_reader, open_rapdu_reader): Initialize it.
(check_ccid_keypad): New.
(apdu_check_keypad): New.
(apdu_send_le): Factored all code out to ...
(send_le): .. new. Takes an additional arg; changed all callers
of the orginal function to use this one with a NULL for the new
arg.
(apdu_send_simple_kp): New.
(ct_send_apdu, pcsc_send_apdu, my_rapdu_send_apdu)
(send_apdu_ccid): New arg PININFO.
(send_apdu_ccid): Use the new arg.
* scdaemon.c: New option --disable-keypad.
2005-10-08 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (scdaemon_LDADD): Add ../gl/libgnu.a after
../common/libcommon.a.
2005-09-20 Werner Koch <wk@g10code.com>
* app-dinsig.c (verify_pin): Try ISO 9564 BCD encoding.
* iso7816.c (iso7816_select_application): Add arg FLAGS. Changed
all callers to pass 0.
* app-openpgp.c (app_select_openpgp): But this one requires a
special flag.
* app-p15.c (app_select_p15): Don't use select application for the
BELPIC.
2005-09-09 Werner Koch <wk@g10code.com>
* pcsc-wrapper.c (main): Removed bogus free.

View File

@ -66,10 +66,10 @@
#include "ccid-driver.h"
/* To to conflicting use of threading libraries we usually can't link
/* Due to conflicting use of threading libraries we usually can't link
against libpcsclite. Instead we use a wrapper program. */
#ifdef USE_GNU_PTH
#ifndef HAVE_W32_SYSTEM
#if !defined(HAVE_W32_SYSTEM) && !defined(__CYGWIN__)
#define NEED_PCSC_WRAPPER 1
#endif
#endif
@ -78,7 +78,7 @@
#define MAX_READER 4 /* Number of readers we support concurrently. */
#ifdef _WIN32
#if defined(_WIN32) || defined(__CYGWIN__)
#define DLSTDCALL __stdcall
#else
#define DLSTDCALL
@ -90,6 +90,14 @@
#define MAX_OPEN_FDS 20
#endif
/* Helper to pass patrameters related to keypad based operations. */
struct pininfo_s
{
int mode;
int minlen;
int maxlen;
int padlen;
};
/* A structure to collect information pertaining to one reader
slot. */
@ -103,7 +111,8 @@ struct reader_table_s {
int (*reset_reader)(int);
int (*get_status_reader)(int, unsigned int *);
int (*send_apdu_reader)(int,unsigned char *,size_t,
unsigned char *, size_t *);
unsigned char *, size_t *, struct pininfo_s *);
int (*check_keypad)(int, int, int, int, int, int);
void (*dump_status_reader)(int);
struct {
@ -320,6 +329,7 @@ new_reader_slot (void)
reader_table[reader].reset_reader = NULL;
reader_table[reader].get_status_reader = NULL;
reader_table[reader].send_apdu_reader = NULL;
reader_table[reader].check_keypad = NULL;
reader_table[reader].dump_status_reader = NULL;
reader_table[reader].used = 1;
@ -372,6 +382,7 @@ host_sw_string (long err)
case SW_HOST_GENERAL_ERROR: return "general error";
case SW_HOST_NO_READER: return "no reader";
case SW_HOST_ABORTED: return "aborted";
case SW_HOST_NO_KEYPAD: return "no keypad";
default: return "unknown host status error";
}
}
@ -533,7 +544,7 @@ ct_get_status (int slot, unsigned int *status)
set to BUFLEN. Returns: CT API error code. */
static int
ct_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
unsigned char *buffer, size_t *buflen)
unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo)
{
int rc;
unsigned char dad[1], sad[1];
@ -596,6 +607,7 @@ open_ct_reader (int port)
reader_table[reader].reset_reader = reset_ct_reader;
reader_table[reader].get_status_reader = ct_get_status;
reader_table[reader].send_apdu_reader = ct_send_apdu;
reader_table[reader].check_keypad = NULL;
reader_table[reader].dump_status_reader = ct_dump_reader_status;
dump_reader_status (reader);
@ -1082,7 +1094,8 @@ pcsc_get_status (int slot, unsigned int *status)
set to BUFLEN. Returns: CT API error code. */
static int
pcsc_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
unsigned char *buffer, size_t *buflen)
unsigned char *buffer, size_t *buflen,
struct pininfo_s *pininfo)
{
#ifdef NEED_PCSC_WRAPPER
long err;
@ -1479,6 +1492,7 @@ open_pcsc_reader (const char *portstr)
reader_table[slot].reset_reader = reset_pcsc_reader;
reader_table[slot].get_status_reader = pcsc_get_status;
reader_table[slot].send_apdu_reader = pcsc_send_apdu;
reader_table[slot].check_keypad = NULL;
reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
/* Read the status so that IS_T0 will be set. */
@ -1625,6 +1639,7 @@ open_pcsc_reader (const char *portstr)
reader_table[slot].reset_reader = reset_pcsc_reader;
reader_table[slot].get_status_reader = pcsc_get_status;
reader_table[slot].send_apdu_reader = pcsc_send_apdu;
reader_table[slot].check_keypad = NULL;
reader_table[slot].dump_status_reader = dump_pcsc_reader_status;
/* log_debug ("state from pcsc_status: 0x%lx\n", card_state); */
@ -1713,7 +1728,8 @@ get_status_ccid (int slot, unsigned int *status)
set to BUFLEN. Returns: Internal CCID driver error code. */
static int
send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
unsigned char *buffer, size_t *buflen)
unsigned char *buffer, size_t *buflen,
struct pininfo_s *pininfo)
{
long err;
size_t maxbuflen;
@ -1727,9 +1743,18 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
log_printhex (" APDU_data:", apdu, apdulen);
maxbuflen = *buflen;
err = ccid_transceive (reader_table[slot].ccid.handle,
apdu, apdulen,
buffer, maxbuflen, buflen);
if (pininfo)
err = ccid_transceive_secure (reader_table[slot].ccid.handle,
apdu, apdulen,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen,
buffer, maxbuflen, buflen);
else
err = ccid_transceive (reader_table[slot].ccid.handle,
apdu, apdulen,
buffer, maxbuflen, buflen);
if (err)
log_error ("ccid_transceive failed: (0x%lx)\n",
err);
@ -1737,6 +1762,24 @@ send_apdu_ccid (int slot, unsigned char *apdu, size_t apdulen,
return err;
}
/* Check whether the CCID reader supports the ISO command code COMMAND
on the keypad. Return 0 on success. For a description of the pin
parameters, see ccid-driver.c */
static int
check_ccid_keypad (int slot, int command, int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen)
{
unsigned char apdu[] = { 0, 0, 0, 0x81 };
apdu[1] = command;
return ccid_transceive_secure (reader_table[slot].ccid.handle,
apdu, sizeof apdu,
pin_mode, pinlen_min, pinlen_max, pin_padlen,
NULL, 0, NULL);
}
/* Open the reader and try to read an ATR. */
static int
open_ccid_reader (const char *portstr)
@ -1776,6 +1819,7 @@ open_ccid_reader (const char *portstr)
reader_table[slot].reset_reader = reset_ccid_reader;
reader_table[slot].get_status_reader = get_status_ccid;
reader_table[slot].send_apdu_reader = send_apdu_ccid;
reader_table[slot].check_keypad = check_ccid_keypad;
reader_table[slot].dump_status_reader = dump_ccid_reader_status;
dump_reader_status (slot);
@ -1932,7 +1976,8 @@ my_rapdu_get_status (int slot, unsigned int *status)
set to BUFLEN. Returns: APDU error code. */
static int
my_rapdu_send_apdu (int slot, unsigned char *apdu, size_t apdulen,
unsigned char *buffer, size_t *buflen)
unsigned char *buffer, size_t *buflen,
struct pininfo_s *pininfo)
{
int err;
reader_table_t slotp;
@ -2063,6 +2108,7 @@ open_rapdu_reader (int portno,
reader_table[slot].reset_reader = reset_rapdu_reader;
reader_table[slot].get_status_reader = my_rapdu_get_status;
reader_table[slot].send_apdu_reader = my_rapdu_send_apdu;
reader_table[slot].check_keypad = NULL;
reader_table[slot].dump_status_reader = NULL;
dump_reader_status (slot);
@ -2198,28 +2244,28 @@ apdu_open_reader (const char *portstr)
pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
pcsc_release_context = dlsym (handle, "SCardReleaseContext");
pcsc_list_readers = dlsym (handle, "SCardListReaders");
#ifdef _WIN32
#if defined(_WIN32) || defined(__CYGWIN__)
if (!pcsc_list_readers)
pcsc_list_readers = dlsym (handle, "SCardListReadersA");
#endif
pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
#ifdef _WIN32
#if defined(_WIN32) || defined(__CYGWIN__)
if (!pcsc_get_status_change)
pcsc_get_status_change = dlsym (handle, "SCardGetStatusChangeA");
#endif
pcsc_connect = dlsym (handle, "SCardConnect");
#ifdef _WIN32
#if defined(_WIN32) || defined(__CYGWIN__)
if (!pcsc_connect)
pcsc_connect = dlsym (handle, "SCardConnectA");
#endif
pcsc_reconnect = dlsym (handle, "SCardReconnect");
#ifdef _WIN32
#if defined(_WIN32) || defined(__CYGWIN__)
if (!pcsc_reconnect)
pcsc_reconnect = dlsym (handle, "SCardReconnectA");
#endif
pcsc_disconnect = dlsym (handle, "SCardDisconnect");
pcsc_status = dlsym (handle, "SCardStatus");
#ifdef _WIN32
#if defined(_WIN32) || defined(__CYGWIN__)
if (!pcsc_status)
pcsc_status = dlsym (handle, "SCardStatusA");
#endif
@ -2492,11 +2538,30 @@ apdu_get_status (int slot, int hang,
}
/* Check whether the reader supports the ISO command code COMMAND on
the keypad. Return 0 on success. For a description of the pin
parameters, see ccid-driver.c */
int
apdu_check_keypad (int slot, int command, int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen)
{
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
if (reader_table[slot].check_keypad)
return reader_table[slot].check_keypad (slot, command,
pin_mode, pinlen_min, pinlen_max,
pin_padlen);
else
return SW_HOST_NOT_SUPPORTED;
}
/* Dispatcher for the actual send_apdu function. Note, that this
function should be called in locked state. */
static int
send_apdu (int slot, unsigned char *apdu, size_t apdulen,
unsigned char *buffer, size_t *buflen)
unsigned char *buffer, size_t *buflen, struct pininfo_s *pininfo)
{
if (slot < 0 || slot >= MAX_READER || !reader_table[slot].used )
return SW_HOST_NO_DRIVER;
@ -2504,24 +2569,20 @@ send_apdu (int slot, unsigned char *apdu, size_t apdulen,
if (reader_table[slot].send_apdu_reader)
return reader_table[slot].send_apdu_reader (slot,
apdu, apdulen,
buffer, buflen);
buffer, buflen, pininfo);
else
return SW_HOST_NOT_SUPPORTED;
}
/* Send an APDU to the card in SLOT. The APDU is created from all
given parameters: CLASS, INS, P0, P1, LC, DATA, LE. A value of -1
for LC won't sent this field and the data field; in this case DATA
must also be passed as NULL. The return value is the status word
or -1 for an invalid SLOT or other non card related error. If
RETBUF is not NULL, it will receive an allocated buffer with the
returned data. The length of that data will be put into
*RETBUFLEN. The caller is reponsible for releasing the buffer even
in case of errors. */
int
apdu_send_le(int slot, int class, int ins, int p0, int p1,
int lc, const char *data, int le,
unsigned char **retbuf, size_t *retbuflen)
/* Core APDU trabceiver function. Parameters are described at
apdu_send_le with the exception of PININFO which indicates keypad
related operations if not NULL. */
static int
send_le (int slot, int class, int ins, int p0, int p1,
int lc, const char *data, int le,
unsigned char **retbuf, size_t *retbuflen,
struct pininfo_s *pininfo)
{
#define RESULTLEN 256
unsigned char result[RESULTLEN+10]; /* 10 extra in case of bugs in
@ -2570,7 +2631,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
/* As safeguard don't pass any garbage from the stack to the driver. */
memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
resultlen = RESULTLEN;
rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, pininfo);
if (rc || resultlen < 2)
{
log_error ("apdu_send_simple(%d) failed: %s\n",
@ -2638,7 +2699,7 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
apdu[apdulen++] = len;
memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
resultlen = RESULTLEN;
rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
if (rc || resultlen < 2)
{
log_error ("apdu_send_simple(%d) for get response failed: %s\n",
@ -2703,6 +2764,27 @@ apdu_send_le(int slot, int class, int ins, int p0, int p1,
#undef RESULTLEN
}
/* Send an APDU to the card in SLOT. The APDU is created from all
given parameters: CLASS, INS, P0, P1, LC, DATA, LE. A value of -1
for LC won't sent this field and the data field; in this case DATA
must also be passed as NULL. The return value is the status word
or -1 for an invalid SLOT or other non card related error. If
RETBUF is not NULL, it will receive an allocated buffer with the
returned data. The length of that data will be put into
*RETBUFLEN. The caller is reponsible for releasing the buffer even
in case of errors. */
int
apdu_send_le(int slot, int class, int ins, int p0, int p1,
int lc, const char *data, int le,
unsigned char **retbuf, size_t *retbuflen)
{
return send_le (slot, class, ins, p0, p1,
lc, data, le,
retbuf, retbuflen,
NULL);
}
/* Send an APDU to the card in SLOT. The APDU is created from all
given parameters: CLASS, INS, P0, P1, LC, DATA. A value of -1 for
LC won't sent this field and the data field; in this case DATA must
@ -2716,8 +2798,8 @@ int
apdu_send (int slot, int class, int ins, int p0, int p1,
int lc, const char *data, unsigned char **retbuf, size_t *retbuflen)
{
return apdu_send_le (slot, class, ins, p0, p1, lc, data, 256,
retbuf, retbuflen);
return send_le (slot, class, ins, p0, p1, lc, data, 256,
retbuf, retbuflen, NULL);
}
/* Send an APDU to the card in SLOT. The APDU is created from all
@ -2730,7 +2812,25 @@ int
apdu_send_simple (int slot, int class, int ins, int p0, int p1,
int lc, const char *data)
{
return apdu_send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL);
return send_le (slot, class, ins, p0, p1, lc, data, -1, NULL, NULL, NULL);
}
/* Same as apdu_send_simple but uses the keypad of the reader. */
int
apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen)
{
struct pininfo_s pininfo;
pininfo.mode = pin_mode;
pininfo.minlen = pinlen_min;
pininfo.maxlen = pinlen_max;
pininfo.padlen = pin_padlen;
return send_le (slot, class, ins, p0, p1, lc, data, -1,
NULL, NULL, &pininfo);
}
@ -2771,7 +2871,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
class = apdulen? *apdu : 0;
resultlen = RESULTLEN;
rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
if (rc || resultlen < 2)
{
log_error ("apdu_send_direct(%d) failed: %s\n",
@ -2825,7 +2925,7 @@ apdu_send_direct (int slot, const unsigned char *apdudata, size_t apdudatalen,
apdu[apdulen++] = len;
memset (apdu+apdulen, 0, sizeof (apdu) - apdulen);
resultlen = RESULTLEN;
rc = send_apdu (slot, apdu, apdulen, result, &resultlen);
rc = send_apdu (slot, apdu, apdulen, result, &resultlen, NULL);
if (rc || resultlen < 2)
{
log_error ("apdu_send_direct(%d) for get response failed: %s\n",

View File

@ -63,7 +63,8 @@ enum {
SW_HOST_CARD_IO_ERROR = 0x1000a,
SW_HOST_GENERAL_ERROR = 0x1000b,
SW_HOST_NO_READER = 0x1000c,
SW_HOST_ABORTED = 0x1000d
SW_HOST_ABORTED = 0x1000d,
SW_HOST_NO_KEYPAD = 0x1000e
};
@ -96,8 +97,14 @@ int apdu_activate (int slot);
int apdu_reset (int slot);
int apdu_get_status (int slot, int hang,
unsigned int *status, unsigned int *changed);
int apdu_check_keypad (int slot, int command, int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen);
int apdu_send_simple (int slot, int class, int ins, int p0, int p1,
int lc, const char *data);
int apdu_send_simple_kp (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen);
int apdu_send (int slot, int class, int ins, int p0, int p1,
int lc, const char *data,
unsigned char **retbuf, size_t *retbuflen);

View File

@ -1,5 +1,5 @@
/* app-dinsig.c - The DINSIG (DIN V 66291-1) card application.
* Copyright (C) 2002, 2004 Free Software Foundation, Inc.
* Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@ -280,10 +280,11 @@ verify_pin (app_t app,
{
if (!app->did_chv1 || app->force_chv1 )
{
const char *s;
char *pinvalue;
int rc;
rc = pincb (pincb_arg, "PIN", &pinvalue);
rc = pincb (pincb_arg, "PIN", &pinvalue);
if (rc)
{
log_info ("PIN callback returned error: %s\n", gpg_strerror (rc));
@ -291,8 +292,16 @@ verify_pin (app_t app,
}
/* We require the PIN to be at least 6 and at max 8 bytes.
According to the specs, this should all be ASCII but we don't
check this. */
According to the specs, this should all be ASCII. */
for (s=pinvalue; digitp (s); s++)
;
if (*s)
{
log_error ("Non-numeric digits found in PIN\n");
xfree (pinvalue);
return gpg_error (GPG_ERR_BAD_PIN);
}
if (strlen (pinvalue) < 6)
{
log_error ("PIN is too short; minimum length is 6\n");
@ -307,6 +316,28 @@ verify_pin (app_t app,
}
rc = iso7816_verify (app->slot, 0x81, pinvalue, strlen (pinvalue));
if (gpg_err_code (rc) == GPG_ERR_INV_VALUE)
{
/* We assume that ISO 9564-1 encoding is used and we failed
because the first nibble we passed was 3 and not 2. DIN
says something about looking up such an encoding in the
SSD but I was not able to find any tag relevant to
this. */
char paddedpin[8];
int i, ndigits;
for (ndigits=0, s=pinvalue; *s; ndigits++, s++)
;
i = 0;
paddedpin[i++] = 0x20 | (ndigits & 0x0f);
for (s=pinvalue; i < sizeof paddedpin && *s && s[1]; s = s+2 )
paddedpin[i++] = (((*s - '0') << 4) | ((s[1] - '0') & 0x0f));
if (i < sizeof paddedpin && *s)
paddedpin[i++] = (((*s - '0') << 4) | 0x0f);
while (i < sizeof paddedpin)
paddedpin[i++] = 0xff;
rc = iso7816_verify (app->slot, 0x81, paddedpin, sizeof paddedpin);
}
if (rc)
{
log_error ("verify PIN failed\n");
@ -404,7 +435,7 @@ app_select_dinsig (APP app)
int slot = app->slot;
int rc;
rc = iso7816_select_application (slot, aid, sizeof aid);
rc = iso7816_select_application (slot, aid, sizeof aid, 0);
if (!rc)
{
app->apptype = "DINSIG";

View File

@ -27,7 +27,7 @@
#include <time.h>
#include "scdaemon.h"
#include "i18n.h"
#include "iso7816.h"
#include "app-common.h"
#include "tlv.h"
@ -320,7 +320,7 @@ verify_pin (app_t app,
return rc;
}
/* The follwoing limits are due to TCOS but also defined in the
/* The following limits are due to TCOS but also defined in the
NKS specs. */
if (strlen (pinvalue) < 6)
{
@ -340,7 +340,10 @@ verify_pin (app_t app,
rc = iso7816_verify (app->slot, 0, pinvalue, strlen (pinvalue));
if (rc)
{
log_error ("verify PIN failed\n");
if ( gpg_error (rc) == GPG_ERR_USE_CONDITIONS )
log_error (_("the NullPIN has not yet been changed\n"));
else
log_error ("verify PIN failed\n");
xfree (pinvalue);
return rc;
}
@ -492,7 +495,7 @@ app_select_nks (APP app)
int slot = app->slot;
int rc;
rc = iso7816_select_application (slot, aid, sizeof aid);
rc = iso7816_select_application (slot, aid, sizeof aid, 0);
if (!rc)
{
app->apptype = "NKS";

View File

@ -1284,6 +1284,11 @@ verify_chv2 (app_t app,
if (!app->did_chv2)
{
char *pinvalue;
iso7816_pininfo_t pininfo;
memset (&pininfo, 0, sizeof pininfo);
pininfo.mode = 1;
pininfo.minlen = 6;
rc = pincb (pincb_arg, "PIN", &pinvalue);
if (rc)
@ -2455,7 +2460,9 @@ app_select_openpgp (app_t app)
size_t buflen;
void *relptr;
rc = iso7816_select_application (slot, aid, sizeof aid);
/* Note that the card can't cope with P2=0xCO, thus we need to pass a
special flag value. */
rc = iso7816_select_application (slot, aid, sizeof aid, 0x0001);
if (!rc)
{
unsigned int manufacturer;

View File

@ -3268,18 +3268,15 @@ app_select_p15 (app_t app)
int direct = 0;
int is_belpic = 0;
rc = iso7816_select_application (slot, pkcs15_aid, sizeof pkcs15_aid);
if (rc)
{
rc = iso7816_select_application (slot, pkcs15be_aid,sizeof pkcs15be_aid);
if (!rc)
is_belpic = 1;
}
rc = iso7816_select_application (slot, pkcs15_aid, sizeof pkcs15_aid, 0);
if (rc)
{ /* Not found: Try to locate it from 2F00. We use direct path
selection here because it seems that the Belgian eID card
does only allow for that. Many other cards supports this
selection method too. */
selection method too. Note, that we don't use
select_application above for the Belgian card - the call
works but it seems that it did not switch to the correct DF.
Using the 2f02 just works. */
unsigned short path[1] = { 0x2f00 };
rc = iso7816_select_path (app->slot, path, 1, NULL, NULL);

View File

@ -1240,7 +1240,9 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
if (CCID_COMMAND_FAILED (buffer))
print_command_failed (buffer);
/* Check whether a card is at all available. */
/* Check whether a card is at all available. Note: If you add new
error codes here, check whether they need to be ignored in
send_escape_cmd. */
switch ((buffer[7] & 0x03))
{
case 0: /* no error */ break;
@ -1253,16 +1255,23 @@ bulk_in (ccid_driver_t handle, unsigned char *buffer, size_t length,
/* Note that this function won't return the error codes NO_CARD or
CARD_INACTIVE */
CARD_INACTIVE. IF RESULT is not NULL, the result from the
operation will get returned in RESULT and its length in RESULTLEN.
If the response is larger than RESULTMAX, an error is returned and
the required buffer length returned in RESULTLEN. */
static int
send_escape_cmd (ccid_driver_t handle,
const unsigned char *data, size_t datalen)
const unsigned char *data, size_t datalen,
unsigned char *result, size_t resultmax, size_t *resultlen)
{
int i, rc;
unsigned char msg[100];
size_t msglen;
unsigned char seqno;
if (resultlen)
*resultlen = 0;
if (datalen > sizeof msg - 10)
return CCID_DRIVER_ERR_INV_VALUE; /* Escape data too large. */
@ -1285,11 +1294,42 @@ send_escape_cmd (ccid_driver_t handle,
return rc;
rc = bulk_in (handle, msg, sizeof msg, &msglen, RDR_to_PC_Escape,
seqno, 5000, 0);
if (result)
switch (rc)
{
/* We need to ignore certain errorcode here. */
case 0:
case CCID_DRIVER_ERR_CARD_INACTIVE:
case CCID_DRIVER_ERR_NO_CARD:
{
if (msglen > resultmax)
rc = CCID_DRIVER_ERR_INV_VALUE; /* Response too large. */
else
{
memcpy (result, msg, msglen);
*resultlen = msglen;
}
rc = 0;
}
break;
default:
break;
}
return rc;
}
int
ccid_transceive_escape (ccid_driver_t handle,
const unsigned char *data, size_t datalen,
unsigned char *resp, size_t maxresplen, size_t *nresp)
{
return send_escape_cmd (handle, data, datalen, resp, maxresplen, nresp);
}
/* experimental */
int
ccid_poll (ccid_driver_t handle)
@ -1445,7 +1485,8 @@ ccid_get_atr (ccid_driver_t handle,
{
tried_iso = 1;
/* Try switching to ISO mode. */
if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2))
if (!send_escape_cmd (handle, (const unsigned char*)"\xF1\x01", 2,
NULL, 0, NULL))
goto again;
}
else if (CCID_COMMAND_FAILED (msg))
@ -1957,14 +1998,16 @@ ccid_transceive (ccid_driver_t handle,
}
/* Send the CCID Secure command to the reader. APDU_BUF should contain the APDU template. PIN_MODE defines now the pin gets formatted:
/* Send the CCID Secure command to the reader. APDU_BUF should
contain the APDU template. PIN_MODE defines how the pin gets
formatted:
1 := The PIN is ASCII encoded and of variable length. The
length of the PIN entered will be put into Lc by the reader.
The APDU should me made up of 4 bytes without Lc.
PINLEN_MIN and PINLEN_MAX define the limits for the pin length. 0
may be used t enable usbale defaults. PIN_PADLEN should be 0
may be used t enable reasonable defaults. PIN_PADLEN should be 0.
When called with RESP and NRESP set to NULL, the function will
merely check whether the reader supports the secure command for the
@ -1996,7 +2039,7 @@ ccid_transceive_secure (ccid_driver_t handle,
else if (apdu_buflen >= 4 && apdu_buf[1] == 0x24 && (handle->has_pinpad & 2))
return CCID_DRIVER_ERR_NOT_SUPPORTED; /* Not yet by our code. */
else
return CCID_DRIVER_ERR_NOT_SUPPORTED;
return CCID_DRIVER_ERR_NO_KEYPAD;
if (pin_mode != 1)
return CCID_DRIVER_ERR_NOT_SUPPORTED;
@ -2027,7 +2070,8 @@ ccid_transceive_secure (ccid_driver_t handle,
if (handle->id_vendor == VENDOR_SCM)
{
DEBUGOUT ("sending escape sequence to switch to a case 1 APDU\n");
rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3);
rc = send_escape_cmd (handle, (const unsigned char*)"\x80\x02\x00", 3,
NULL, 0, NULL);
if (rc)
return rc;
}
@ -2044,7 +2088,7 @@ ccid_transceive_secure (ccid_driver_t handle,
if (handle->id_vendor == VENDOR_SCM)
{
/* For the SPR532 the next 2 bytes need to be zero. We do this
for all SCM product. Kudos to to Martin Paljak for this
for all SCM product. Kudos to Martin Paljak for this
hint. */
msg[13] = msg[14] = 0;
}

View File

@ -58,7 +58,7 @@
#ifndef CCID_DRIVER_H
#define CCID_DRIVER_H
/* The CID driver returns the same error codes as the statsu words
/* The CID driver returns the same error codes as the status words
used by GnuPG's apdu.h. For ease of maintenance they should always
match. */
#define CCID_DRIVER_ERR_OUT_OF_CORE 0x10001
@ -74,6 +74,7 @@
#define CCID_DRIVER_ERR_GENERAL_ERROR 0x1000b
#define CCID_DRIVER_ERR_NO_READER 0x1000c
#define CCID_DRIVER_ERR_ABORTED 0x1000d
#define CCID_DRIVER_ERR_NO_KEYPAD 0x1000e
struct ccid_driver_s;
typedef struct ccid_driver_s *ccid_driver_t;
@ -94,6 +95,10 @@ int ccid_transceive_secure (ccid_driver_t handle,
int pin_mode,
int pinlen_min, int pinlen_max, int pin_padlen,
unsigned char *resp, size_t maxresplen, size_t *nresp);
int ccid_transceive_escape (ccid_driver_t handle,
const unsigned char *data, size_t datalen,
unsigned char *resp, size_t maxresplen,
size_t *nresp);

View File

@ -47,9 +47,9 @@
#define CMD_SELECT_FILE 0xA4
#define CMD_VERIFY 0x20
#define CMD_CHANGE_REFERENCE_DATA 0x24
#define CMD_RESET_RETRY_COUNTER 0x2C
#define CMD_VERIFY ISO7816_VERIFY
#define CMD_CHANGE_REFERENCE_DATA ISO7816_CHANGE_REFERENCE_DATA
#define CMD_RESET_RETRY_COUNTER ISO7816_RESET_RETRY_COUNTER
#define CMD_GET_DATA 0xCA
#define CMD_PUT_DATA 0xDA
#define CMD_MSE 0x22
@ -95,6 +95,7 @@ map_sw (int sw)
case SW_HOST_GENERAL_ERROR: ec = GPG_ERR_GENERAL; break;
case SW_HOST_NO_READER: ec = GPG_ERR_ENODEV; break;
case SW_HOST_ABORTED: ec = GPG_ERR_CANCELED; break;
case SW_HOST_NO_KEYPAD: ec = GPG_ERR_NOT_SUPPORTED; break;
default:
if ((sw & 0x010000))
@ -124,12 +125,15 @@ iso7816_map_sw (int sw)
requested application ID. The function can't be used to enumerate
AIDs and won't return the AID on success. The return value is 0
for okay or a GPG error code. Note that ISO error codes are
internally mapped. */
internally mapped. Bit 0 of FLAGS should be set if the card does
not understand P2=0xC0. */
gpg_error_t
iso7816_select_application (int slot, const char *aid, size_t aidlen)
iso7816_select_application (int slot, const char *aid, size_t aidlen,
unsigned int flags)
{
int sw;
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4, 0, aidlen, aid);
sw = apdu_send_simple (slot, 0x00, CMD_SELECT_FILE, 4,
(flags&1)? 0 :0x0c, aidlen, aid);
return map_sw (sw);
}
@ -221,27 +225,59 @@ iso7816_list_directory (int slot, int list_dirs,
}
/* Check whether the reader supports the ISO command code COMMAND on
the keypad. Returns 0 on success. */
gpg_error_t
iso7816_check_keypad (int slot, int command, iso7816_pininfo_t *pininfo)
{
int sw;
sw = apdu_check_keypad (slot, command,
pininfo->mode, pininfo->minlen, pininfo->maxlen,
pininfo->padlen);
return map_sw (sw);
}
/* Perform a VERIFY command on SLOT using the card holder verification
vector CHVNO with a CHV of lenght CHVLEN. With PININFO non-NULL
the keypad of the reader will be used. Returns 0 on success. */
gpg_error_t
iso7816_verify_kp (int slot, int chvno, const char *chv, size_t chvlen,
iso7816_pininfo_t *pininfo)
{
int sw;
if (pininfo && pininfo->mode)
sw = apdu_send_simple_kp (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
return map_sw (sw);
}
/* Perform a VERIFY command on SLOT using the card holder verification
vector CHVNO with a CHV of lenght CHVLEN. Returns 0 on success. */
gpg_error_t
iso7816_verify (int slot, int chvno, const char *chv, size_t chvlen)
{
int sw;
sw = apdu_send_simple (slot, 0x00, CMD_VERIFY, 0, chvno, chvlen, chv);
return map_sw (sw);
return iso7816_verify_kp (slot, chvno, chv, chvlen, NULL);
}
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
0), a "change reference data" is done, otherwise an "exchange
reference data". The new reference data is expected in NEWCHV of
length NEWCHVLEN. */
length NEWCHVLEN. With PININFO non-NULL the keypad of the reader
will be used. */
gpg_error_t
iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen)
iso7816_change_reference_data_kp (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen,
iso7816_pininfo_t *pininfo)
{
int sw;
char *buf;
@ -258,28 +294,69 @@ iso7816_change_reference_data (int slot, int chvno,
memcpy (buf, oldchv, oldchvlen);
memcpy (buf+oldchvlen, newchv, newchvlen);
sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
if (pininfo && pininfo->mode)
sw = apdu_send_simple_kp (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0x00, CMD_CHANGE_REFERENCE_DATA,
oldchvlen? 0 : 1, chvno, oldchvlen+newchvlen, buf);
xfree (buf);
return map_sw (sw);
}
/* Perform a CHANGE_REFERENCE_DATA command on SLOT for the card holder
verification vector CHVNO. If the OLDCHV is NULL (and OLDCHVLEN
0), a "change reference data" is done, otherwise an "exchange
reference data". The new reference data is expected in NEWCHV of
length NEWCHVLEN. */
gpg_error_t
iso7816_reset_retry_counter (int slot, int chvno,
const char *newchv, size_t newchvlen)
iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen)
{
return iso7816_change_reference_data_kp (slot, chvno, oldchv, oldchvlen,
newchv, newchvlen, NULL);
}
gpg_error_t
iso7816_reset_retry_counter_kp (int slot, int chvno,
const char *newchv, size_t newchvlen,
iso7816_pininfo_t *pininfo)
{
int sw;
if (!newchv || !newchvlen )
return gpg_error (GPG_ERR_INV_VALUE);
sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv);
if (pininfo && pininfo->mode)
sw = apdu_send_simple_kp (slot, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv,
pininfo->mode,
pininfo->minlen,
pininfo->maxlen,
pininfo->padlen);
else
sw = apdu_send_simple (slot, 0x00, CMD_RESET_RETRY_COUNTER,
2, chvno, newchvlen, newchv);
return map_sw (sw);
}
gpg_error_t
iso7816_reset_retry_counter (int slot, int chvno,
const char *newchv, size_t newchvlen)
{
return iso7816_reset_retry_counter_kp (slot, chvno, newchv, newchvlen, NULL);
}
/* Perform a GET DATA command requesting TAG and storing the result in
a newly allocated buffer at the address passed by RESULT. Return
the length of this data at the address of RESULTLEN. */

View File

@ -28,10 +28,30 @@
#include "cardglue.h"
#endif
/* Command codes used by iso7816_check_keypad. */
#define ISO7816_VERIFY 0x20
#define ISO7816_CHANGE_REFERENCE_DATA 0x24
#define ISO7816_RESET_RETRY_COUNTER 0x2C
/* Information to be passed to keypad equipped readers. See
ccid-driver.c for details. */
struct iso7816_pininfo_s
{
int mode; /* A mode of 0 means: Do not use the keypad. */
int minlen;
int maxlen;
int padlen;
int padchar;
};
typedef struct iso7816_pininfo_s iso7816_pininfo_t;
gpg_error_t iso7816_map_sw (int sw);
gpg_error_t iso7816_select_application (int slot,
const char *aid, size_t aidlen);
const char *aid, size_t aidlen,
unsigned int flags);
gpg_error_t iso7816_select_file (int slot, int tag, int is_dir,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_select_path (int slot,
@ -39,13 +59,26 @@ gpg_error_t iso7816_select_path (int slot,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_list_directory (int slot, int list_dirs,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_check_keypad (int slot, int command,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_verify (int slot,
int chvno, const char *chv, size_t chvlen);
gpg_error_t iso7816_verify_kp (int slot,
int chvno, const char *chv, size_t chvlen,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_change_reference_data (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen);
gpg_error_t iso7816_change_reference_data_kp (int slot, int chvno,
const char *oldchv, size_t oldchvlen,
const char *newchv, size_t newchvlen,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_reset_retry_counter (int slot, int chvno,
const char *newchv, size_t newchvlen);
gpg_error_t iso7816_reset_retry_counter_kp (int slot, int chvno,
const char *newchv,
size_t newchvlen,
iso7816_pininfo_t *pininfo);
gpg_error_t iso7816_get_data (int slot, int tag,
unsigned char **result, size_t *resultlen);
gpg_error_t iso7816_put_data (int slot, int tag,

View File

@ -84,6 +84,7 @@ enum cmd_and_opt_values
opcscDriver,
oDisableCCID,
oDisableOpenSC,
oDisableKeypad,
oAllowAdmin,
oDenyAdmin,
oDisableApplication,
@ -126,6 +127,7 @@ static ARGPARSE_OPTS opts[] = {
"@"
#endif
/* end --disable-ccid */},
{ oDisableKeypad, "disable-keypad", 0, N_("do not use a reader's keypad")},
{ oAllowAdmin, "allow-admin", 0, N_("allow the use of admin card commands")},
{ oDenyAdmin, "deny-admin", 0, "@" },
{ oDisableApplication, "disable-application", 2, "@"},
@ -135,7 +137,7 @@ static ARGPARSE_OPTS opts[] = {
/* The card dirver we use by default for PC/SC. */
#ifdef HAVE_W32_SYSTEM
#if defined(HAVE_W32_SYSTEM) || defined(__CYGWIN__)
#define DEFAULT_PCSC_DRIVER "winscard.dll"
#else
#define DEFAULT_PCSC_DRIVER "libpcsclite.so"
@ -489,6 +491,8 @@ main (int argc, char **argv )
case oDisableCCID: opt.disable_ccid = 1; break;
case oDisableOpenSC: break;
case oDisableKeypad: opt.disable_keypad = 1; break;
case oAllowAdmin: opt.allow_admin = 1; break;
case oDenyAdmin: opt.allow_admin = 0; break;

View File

@ -39,21 +39,22 @@
#define MAX_DIGEST_LEN 24
/* A large struct name "opt" to keep global flags */
/* A large struct name "opt" to keep global flags. */
struct {
unsigned int debug; /* debug flags (DBG_foo_VALUE) */
int verbose; /* verbosity level */
int quiet; /* be as quiet as possible */
int dry_run; /* don't change any persistent data */
int batch; /* batch mode */
const char *homedir; /* configuration directory name */
unsigned int debug; /* Debug flags (DBG_foo_VALUE). */
int verbose; /* Verbosity level. */
int quiet; /* Be as quiet as possible. */
int dry_run; /* Don't change any persistent data. */
int batch; /* Batch mode. */
const char *homedir; /* Configuration directory name. */
const char *ctapi_driver; /* Library to access the ctAPI. */
const char *pcsc_driver; /* Library to access the PC/SC system. */
const char *reader_port; /* NULL or reder port to use. */
int disable_ccid; /* Disable the use of the internal CCID driver. */
int disable_keypad; /* Do not use a keypad. */
int allow_admin; /* Allow the use of admin commands for certain
cards. */
strlist_t disabled_applications; /* card applications we do not
strlist_t disabled_applications; /* Card applications we do not
want to use. */
} opt;

View File

@ -1,3 +1,11 @@
2005-10-19 Werner Koch <wk@g10code.com>
* gpgconf-comp.c (gc_options_scdaemon): New option --disable-keypad.
2005-09-22 Werner Koch <wk@g10code.com>
* rfc822parse.c (parse_field): Tread Content-Disposition special.
2005-10-08 Marcus Brinkmann <marcus@g10code.de>
* Makefile.am (watchgnupg_LDADD): New variable.

View File

@ -528,7 +528,9 @@ static gc_option_t gc_options_scdaemon[] =
{ "disable-ccid", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
"gnupg", "do not use the internal CCID driver",
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
{ "disable-keypad", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
"gnupg", "do not use a reader's keypad",
GC_ARG_TYPE_NONE, GC_BACKEND_SCDAEMON },
{ "Debug",
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
@ -2447,7 +2449,8 @@ gc_component_change_options (int component, FILE *in)
{
#ifdef HAVE_W32_SYSTEM
/* FIXME: Won't work becuase W32 doesn't silently
overwrite. */
overwrite. Fix it by creating a backup copy and
deliting the orginal file first. */
err = rename (src_pathname[i], dest_pathname[i]);
#else /*!HAVE_W32_SYSTEM*/
/* This is a bit safer than rename() because we

View File

@ -766,6 +766,7 @@ parse_field (HDR_LINE hdr)
} tspecial_header[] = {
{ "Content-Type", 12},
{ "Content-Transfer-Encoding", 25},
{ "Content-Disposition", 19},
{ NULL, 0}
};
const char *delimiters;