GNUPG-1-9-BRANCH gnupg (7 files)
cvs user wk
cvs at cvs.gnupg.org
Thu Feb 24 22:29:20 CET 2005
Date: Thursday, February 24, 2005 @ 22:40:48
Author: wk
Path: /cvs/gnupg/gnupg
Tag: GNUPG-1-9-BRANCH
Modified: agent/ChangeLog agent/agent.h agent/call-scd.c
agent/command-ssh.c scd/ChangeLog scd/app.c scd/command.c
* call-scd.c (unescape_status_string): New. Actual a copy of
../g10/call-agent.c
(card_getattr_cb, agent_card_getattr): New.
* command-ssh.c (card_key_available): New.
(ssh_handler_request_identities): First see whether a card key is
available.
* app.c (app_getattr): Return APPTYPE or SERIALNO type even if the
application does dot support the getattr call.
* app.c (select_application): Return an error code and the
application context in an new arg.
* command.c (open_card): Adjusted for that. Don't use the
fallback if no card is present. Return an error if the card has
been removed without a reset.
(do_reset, cmd_serialno): Clear that error flag.
(TEST_CARD_REMOVAL): New. Use it with all command handlers.
(scd_update_reader_status_file): Set the error flag on all changes.
---------------------+
agent/ChangeLog | 8 +
agent/agent.h | 1
agent/call-scd.c | 133 ++++++++++++++++++++++++++++--
agent/command-ssh.c | 218 +++++++++++++++++++++++++++++++++-----------------
scd/ChangeLog | 4
scd/app.c | 29 ++++++
scd/command.c | 24 +++--
7 files changed, 328 insertions(+), 89 deletions(-)
Index: gnupg/agent/ChangeLog
diff -u gnupg/agent/ChangeLog:1.59.2.69 gnupg/agent/ChangeLog:1.59.2.70
--- gnupg/agent/ChangeLog:1.59.2.69 Thu Feb 24 18:36:11 2005
+++ gnupg/agent/ChangeLog Thu Feb 24 22:40:48 2005
@@ -1,5 +1,13 @@
2005-02-24 Werner Koch <wk at g10code.com>
+ * call-scd.c (unescape_status_string): New. Actual a copy of
+ ../g10/call-agent.c
+ (card_getattr_cb, agent_card_getattr): New.
+
+ * command-ssh.c (card_key_available): New.
+ (ssh_handler_request_identities): First see whether a card key is
+ available.
+
* gpg-agent.c (handle_connections): Need to check for events if
select returns with -1.
Index: gnupg/agent/agent.h
diff -u gnupg/agent/agent.h:1.32.2.15 gnupg/agent/agent.h:1.32.2.16
--- gnupg/agent/agent.h:1.32.2.15 Wed Feb 23 22:06:32 2005
+++ gnupg/agent/agent.h Thu Feb 24 22:40:48 2005
@@ -259,6 +259,7 @@
int agent_card_readcert (ctrl_t ctrl,
const char *id, char **r_buf, size_t *r_buflen);
int agent_card_readkey (ctrl_t ctrl, const char *id, unsigned char **r_buf);
+gpg_error_t agent_card_getattr (ctrl_t ctrl, const char *name, char **result);
int agent_card_scd (ctrl_t ctrl, const char *cmdline,
int (*getpin_cb)(void *, const char *, char*, size_t),
void *getpin_cb_arg, void *assuan_context);
Index: gnupg/agent/call-scd.c
diff -u gnupg/agent/call-scd.c:1.13.2.9 gnupg/agent/call-scd.c:1.13.2.10
--- gnupg/agent/call-scd.c:1.13.2.9 Tue Feb 22 19:08:28 2005
+++ gnupg/agent/call-scd.c Thu Feb 24 22:40:48 2005
@@ -1,5 +1,5 @@
/* call-scd.c - fork of the scdaemon to do SC operations
- * Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+ * Copyright (C) 2001, 2002, 2005 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -66,7 +66,7 @@
static int active_connection_fd = -1;
static int active_connection = 0;
-/* callback parameter for learn card */
+/* Callback parameter for learn card */
struct learn_parm_s {
void (*kpinfo_cb)(void*, const char *);
void *kpinfo_cb_arg;
@@ -266,6 +266,41 @@
}
+
+/* Return a new malloced string by unescaping the string S. Escaping
+ is percent escaping and '+'/space mapping. A binary Nul will
+ silently be replaced by a 0xFF. Function returns NULL to indicate
+ an out of memory status. */
+static char *
+unescape_status_string (const unsigned char *s)
+{
+ char *buffer, *d;
+
+ buffer = d = xtrymalloc (strlen (s)+1);
+ if (!buffer)
+ return NULL;
+ while (*s)
+ {
+ if (*s == '%' && s[1] && s[2])
+ {
+ s++;
+ *d = xtoi_2 (s);
+ if (!*d)
+ *d = '\xff';
+ d++;
+ s += 2;
+ }
+ else if (*s == '+')
+ {
+ *d++ = ' ';
+ s++;
+ }
+ else
+ *d++ = *s++;
+ }
+ *d = 0;
+ return buffer;
+}
@@ -375,14 +410,6 @@
if (rc)
return rc;
- /* Hmm, do we really need this reset - scddaemon should do this or
- we can do this if we for some reason figure out that the
- operation might have failed due to a missing RESET. Hmmm, I feel
- this is really SCdaemon's duty */
-/* rc = assuan_transact (scd_ctx, "RESET", NULL, NULL, NULL, NULL, NULL, NULL); */
-/* if (rc) */
-/* return unlock_scd (map_assuan_err (rc)); */
-
rc = assuan_transact (scd_ctx, "SERIALNO",
NULL, NULL, NULL, NULL,
get_serialno_cb, &serialno);
@@ -395,6 +422,8 @@
return unlock_scd (0);
}
+
+
static AssuanError
membuf_data_cb (void *opaque, const void *buffer, size_t length)
@@ -644,6 +673,90 @@
}
+
+/* Type used with the card_getattr_cb. */
+struct card_getattr_parm_s {
+ const char *keyword; /* Keyword to look for. */
+ size_t keywordlen; /* strlen of KEYWORD. */
+ char *data; /* Malloced and unescaped data. */
+ int error; /* ERRNO value or 0 on success. */
+};
+
+/* Callback function for agent_card_getattr. */
+static assuan_error_t
+card_getattr_cb (void *opaque, const char *line)
+{
+ struct card_getattr_parm_s *parm = opaque;
+ const char *keyword = line;
+ int keywordlen;
+
+ if (parm->data)
+ return 0; /* We want only the first occurrence. */
+
+ for (keywordlen=0; *line && !spacep (line); line++, keywordlen++)
+ ;
+ while (spacep (line))
+ line++;
+
+ if (keywordlen == parm->keywordlen
+ && !memcmp (keyword, parm->keyword, keywordlen))
+ {
+ parm->data = unescape_status_string (line);
+ if (!parm->data)
+ parm->error = errno;
+ }
+
+ return 0;
+}
+
+
+/* Call the agent to retrieve a single line data object. On success
+ the object is malloced and stored at RESULT; it is guaranteed that
+ NULL is never stored in this case. On error an error code is
+ returned and NULL stored at RESULT. */
+gpg_error_t
+agent_card_getattr (ctrl_t ctrl, const char *name, char **result)
+{
+ int err;
+ struct card_getattr_parm_s parm;
+ char line[ASSUAN_LINELENGTH];
+
+ *result = NULL;
+
+ if (!*name)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ memset (&parm, 0, sizeof parm);
+ parm.keyword = name;
+ parm.keywordlen = strlen (name);
+
+ /* We assume that NAME does not need escaping. */
+ if (8 + strlen (name) > DIM(line)-1)
+ return gpg_error (GPG_ERR_TOO_LARGE);
+ stpcpy (stpcpy (line, "GETATTR "), name);
+
+ err = start_scd (ctrl);
+ if (err)
+ return err;
+
+ err = map_assuan_err (assuan_transact (scd_ctx, line,
+ NULL, NULL, NULL, NULL,
+ card_getattr_cb, &parm));
+ if (!err && parm.error)
+ err = gpg_error_from_errno (parm.error);
+
+ if (!err && !parm.data)
+ err = gpg_error (GPG_ERR_NO_DATA);
+
+ if (!err)
+ *result = parm.data;
+ else
+ xfree (parm.data);
+
+ return unlock_scd (err);
+}
+
+
static AssuanError
Index: gnupg/agent/command-ssh.c
diff -u gnupg/agent/command-ssh.c:1.1.4.11 gnupg/agent/command-ssh.c:1.1.4.12
--- gnupg/agent/command-ssh.c:1.1.4.11 Wed Feb 23 22:06:32 2005
+++ gnupg/agent/command-ssh.c Thu Feb 24 22:40:48 2005
@@ -1201,7 +1201,7 @@
return err;
}
-/* Extract the car from SEXP, and create a newly created C-string it,
+/* Extract the car from SEXP, and create a newly created C-string
which is to be stored in IDENTIFIER. */
static gpg_error_t
sexp_extract_identifier (gcry_sexp_t sexp, const char **identifier)
@@ -1404,6 +1404,7 @@
}
+/* Write the public key KEY_PUBLIC to STREAM in SSH key format. */
static gpg_error_t
ssh_send_key_public (estream_t stream, gcry_sexp_t key_public)
{
@@ -1516,7 +1517,78 @@
return err;
}
-
+
+/* Chec whether a smartcard is available and whether it has a usable
+ key. Store a copy of that key at R_PK and return 0. If no key is
+ available store NULL at R_PK and return an error code. */
+static gpg_error_t
+card_key_available (ctrl_t ctrl, gcry_sexp_t *r_pk)
+{
+ gpg_error_t err;
+ char *appname;
+ unsigned char *sbuf;
+ size_t sbuflen;
+ gcry_sexp_t pk;
+
+ *r_pk = NULL;
+
+ /* First see whether a card is available and whether the application
+ is supported. */
+ err = agent_card_getattr (ctrl, "APPTYPE", &appname);
+ if ( gpg_err_code (err) == GPG_ERR_CARD_REMOVED )
+ {
+ /* Ask for the serial number to reset the card. */
+ err = agent_card_serialno (ctrl, &appname);
+ if (err)
+ {
+ if (opt.verbose)
+ log_info (_("can't get serial number of card: %s\n"),
+ gpg_strerror (err));
+ return err;
+ }
+ log_info (_("detected card with S/N: %s\n"), appname);
+ xfree (appname);
+ err = agent_card_getattr (ctrl, "APPTYPE", &appname);
+ }
+ if (err)
+ {
+ log_error (_("error getting application type of card: %s\n"),
+ gpg_strerror (err));
+ return err;
+ }
+ if (strcmp (appname, "OPENPGP"))
+ {
+ log_info (_("card application `%s' is not supported\n"), appname);
+ xfree (appname);
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+ }
+ xfree (appname);
+ appname = NULL;
+
+ /* Read the public key. */
+ err = agent_card_readkey (ctrl, "OPENPGP.3", &sbuf);
+ if (err)
+ {
+ if (opt.verbose)
+ log_info (_("no suitable card key found: %s\n"), gpg_strerror (err));
+ return err;
+ }
+
+ sbuflen = gcry_sexp_canon_len (sbuf, 0, NULL, NULL);
+ err = gcry_sexp_sscan (&pk, NULL, sbuf, sbuflen);
+ xfree (sbuf);
+ if (err)
+ {
+ log_error ("failed to build S-Exp from received card key: %s\n",
+ gpg_strerror (err));
+ return err;
+ }
+
+ *r_pk = pk;
+ return 0;
+}
+
+
/*
Request handler.
@@ -1589,91 +1661,95 @@
goto out;
}
- /* Iterate over key files. */
- /* FIXME: make sure that buffer gets deallocated properly. */
+
+ /* First check whether a key is currently available in the card
+ reader - this should be allowed even without being listed in
+ sshcontrol.txt. */
+
+ if (!card_key_available (ctrl, &key_public))
+ {
+ err = ssh_send_key_public (key_blobs, key_public);
+ gcry_sexp_release (key_public);
+ key_public = NULL;
+ if (err)
+ goto out;
+
+ key_counter++;
+ }
+
+
+ /* Then look at all the registered an allowed keys. */
+
/* Fixme: We should better iterate over the control file and check
whether the key file is there. This is better in resepct to
performance if tehre are a lot of key sin our key storage. */
-
+ /* FIXME: make sure that buffer gets deallocated properly. */
err = open_control_file (&ctrl_fp, 0);
if (err)
goto out;
-#warning Really need to fix this fixme.
- /*
- FIXME: First check whether a key is currently available in the card reader - this should be allowed even without being listed in sshcontrol.txt.
- */
-
- while (1)
+ while ( (dir_entry = readdir (dir)) )
{
- dir_entry = readdir (dir);
- if (dir_entry)
- {
- if ((strlen (dir_entry->d_name) == 44)
- && (! strncmp (dir_entry->d_name + 40, ".key", 4)))
- {
- char hexgrip[41];
- int disabled;
-
- /* We do only want to return keys listed in our control
- file. */
- strncpy (hexgrip, dir_entry->d_name, 40);
- hexgrip[40] = 0;
- if ( strlen (hexgrip) != 40 )
- continue;
- if (search_control_file (ctrl_fp, hexgrip, &disabled)
- || disabled)
- continue;
-
- strncpy (key_path + key_directory_n + 1, dir_entry->d_name, 40);
-
- /* Read file content. */
- err = file_to_buffer (key_path, &buffer, &buffer_n);
- if (err)
- break;
+ if ((strlen (dir_entry->d_name) == 44)
+ && (! strncmp (dir_entry->d_name + 40, ".key", 4)))
+ {
+ char hexgrip[41];
+ int disabled;
+
+ /* We do only want to return keys listed in our control
+ file. */
+ strncpy (hexgrip, dir_entry->d_name, 40);
+ hexgrip[40] = 0;
+ if ( strlen (hexgrip) != 40 )
+ continue;
+ if (search_control_file (ctrl_fp, hexgrip, &disabled)
+ || disabled)
+ continue;
+
+ strncpy (key_path + key_directory_n + 1, dir_entry->d_name, 40);
+
+ /* Read file content. */
+ err = file_to_buffer (key_path, &buffer, &buffer_n);
+ if (err)
+ goto out;
- err = gcry_sexp_sscan (&key_secret, NULL, buffer, buffer_n);
- if (err)
- break;
-
- xfree (buffer);
- buffer = NULL;
-
- err = sexp_extract_identifier (key_secret, &key_type);
- if (err)
- break;
-
- err = ssh_key_type_lookup (NULL, key_type, &spec);
- if (err)
- break;
-
- xfree ((void *) key_type);
- key_type = NULL;
-
- err = key_secret_to_public (&key_public, spec, key_secret);
- if (err)
- break;
+ err = gcry_sexp_sscan (&key_secret, NULL, buffer, buffer_n);
+ if (err)
+ goto out;
+
+ xfree (buffer);
+ buffer = NULL;
+
+ err = sexp_extract_identifier (key_secret, &key_type);
+ if (err)
+ goto out;
+
+ err = ssh_key_type_lookup (NULL, key_type, &spec);
+ if (err)
+ goto out;
+
+ xfree ((void *) key_type);
+ key_type = NULL;
+
+ err = key_secret_to_public (&key_public, spec, key_secret);
+ if (err)
+ goto out;
- gcry_sexp_release (key_secret);
- key_secret = NULL;
+ gcry_sexp_release (key_secret);
+ key_secret = NULL;
- err = ssh_send_key_public (key_blobs, key_public);
- if (err)
- break;
+ err = ssh_send_key_public (key_blobs, key_public);
+ if (err)
+ goto out;
- gcry_sexp_release (key_public);
- key_public = NULL;
+ gcry_sexp_release (key_public);
+ key_public = NULL;
- key_counter++;
- }
- }
- else
- break;
+ key_counter++;
+ }
}
- if (err)
- goto out;
ret = es_fseek (key_blobs, 0, SEEK_SET);
if (ret)
Index: gnupg/scd/ChangeLog
diff -u gnupg/scd/ChangeLog:1.25.2.68 gnupg/scd/ChangeLog:1.25.2.69
--- gnupg/scd/ChangeLog:1.25.2.68 Thu Feb 24 18:36:11 2005
+++ gnupg/scd/ChangeLog Thu Feb 24 22:40:48 2005
@@ -1,5 +1,8 @@
2005-02-24 Werner Koch <wk at g10code.com>
+ * app.c (app_getattr): Return APPTYPE or SERIALNO type even if the
+ application does dot support the getattr call.
+
* app-openpgp.c (get_one_do): Never try to get a non cacheable
object from the cache.
(get_one_do): Add new arg to return an error code. Changed all
@@ -13,6 +16,7 @@
been removed without a reset.
(do_reset, cmd_serialno): Clear that error flag.
(TEST_CARD_REMOVAL): New. Use it with all command handlers.
+ (scd_update_reader_status_file): Set the error flag on all changes.
* scdaemon.c (ticker_thread): Termintate if a shutdown is pending.
Index: gnupg/scd/app.c
diff -u gnupg/scd/app.c:1.3.2.11 gnupg/scd/app.c:1.3.2.12
--- gnupg/scd/app.c:1.3.2.11 Thu Feb 24 18:36:11 2005
+++ gnupg/scd/app.c Thu Feb 24 22:40:48 2005
@@ -305,6 +305,35 @@
return gpg_error (GPG_ERR_INV_VALUE);
if (!app->initialized)
return gpg_error (GPG_ERR_CARD_NOT_INITIALIZED);
+
+ if (app->apptype && name && !strcmp (name, "APPTYPE"))
+ {
+ send_status_info (ctrl, "APPTYPE",
+ app->apptype, strlen (app->apptype), NULL, 0);
+ return 0;
+ }
+ if (name && !strcmp (name, "SERIALNO"))
+ {
+ char *serial_and_stamp;
+ char *serial;
+ time_t stamp;
+ int rc;
+
+ rc = app_get_serial_and_stamp (app, &serial, &stamp);
+ if (rc)
+ return rc;
+ rc = asprintf (&serial_and_stamp, "%s %lu",
+ serial, (unsigned long)stamp);
+ rc = (rc < 0)? gpg_error_from_errno (errno) : 0;
+ xfree (serial);
+ if (rc)
+ return rc;
+ send_status_info (ctrl, "SERIALNO",
+ serial_and_stamp, strlen (serial_and_stamp), NULL, 0);
+ free (serial_and_stamp);
+ return 0;
+ }
+
if (!app->fnc.getattr)
return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
return app->fnc.getattr (app, ctrl, name);
Index: gnupg/scd/command.c
diff -u gnupg/scd/command.c:1.19.2.17 gnupg/scd/command.c:1.19.2.18
--- gnupg/scd/command.c:1.19.2.17 Thu Feb 24 18:36:11 2005
+++ gnupg/scd/command.c Thu Feb 24 22:40:48 2005
@@ -239,7 +239,7 @@
operations are done on the same card unless he calls this function.
*/
static int
-cmd_serialno (ASSUAN_CONTEXT ctx, char *line)
+cmd_serialno (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc = 0;
@@ -248,7 +248,8 @@
time_t stamp;
/* Clear the remove flag so that the open_card is able to reread it. */
- ctrl->server_local->card_removed = 0;
+ if (ctrl->server_local->card_removed)
+ do_reset (ctrl, 0);
if ((rc = open_card (ctrl, *line? line:NULL)))
return rc;
@@ -1092,7 +1093,6 @@
-
/* Tell the assuan library about our commands */
static int
@@ -1299,10 +1299,6 @@
char templ[50];
FILE *fp;
- last[slot].any = 1;
- last[slot].status = status;
- last[slot].changed = changed;
-
log_info ("updating status of slot %d to 0x%04X\n", slot, status);
sprintf (templ, "reader_%d.status", slot);
@@ -1318,7 +1314,19 @@
}
xfree (fname);
- /* Send a signal to the primary client, if any. */
+ /* Set the card removed flag. We will set this on any
+ card change because a reset or SERIALNO request must be
+ done in any case. */
+ if (primary_connection && primary_connection->server_local
+ && last[slot].any )
+ primary_connection->server_local->card_removed = 1;
+
+ last[slot].any = 1;
+ last[slot].status = status;
+ last[slot].changed = changed;
+
+
+ /* Send a signal to the primary client, if any. */
if (primary_connection && primary_connection->server_local
&& primary_connection->server_local->assuan_ctx)
{
More information about the Gnupg-commits
mailing list