[git] GnuPG - branch, scd-pin-prompt, created. gnupg-2.1.0beta3-17-g633ea85
by Ben Kibbey
cvs at cvs.gnupg.org
Fri Jan 13 02:45:02 CET 2012
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "The GNU Privacy Guard".
The branch, scd-pin-prompt has been created
at 633ea8531e4c12164f481d093936f3a9054d8ad9 (commit)
- Log -----------------------------------------------------------------
commit 633ea8531e4c12164f481d093936f3a9054d8ad9
Author: Ben Kibbey <bjk at luxsci.net>
Date: Tue Jan 10 22:10:36 2012 -0500
Add user defined pinentry prompts for SCD.
This adds scdaemon "OPTION pin-prompt" and "OPTION pin-admin-prompt"
along with special escapes to replace in the prompt string to inform the
user of a signature count and admin PIN attempts remaining.
It also adds another "standard" pinentry escape "|I|" to ignore the
default pinentry prompt from gpg-agent and use the supplied 'info'
parameter unmodified (cannot be used with other pinentry flags).
* agent/divert-scd.c (getpin_cb): Add |I| pinentry flag to ignore the
default prompt and use the 'info' parameter as the entire prompt.
* scd/app-common.h (PIN_PROMPT_NONE, PIN_SIGN_PROMPT, PIN_ADMIN_PROMPT):
New enumeration.
(set_pin_prompt): New application callback to set a user-defined
pinentry prompt.
* scd/app-openpgp.c (verify_a_chv): Expand a user-defined pinentry
prompt.
(build_enter_admin_pin_prompt): Ditto.
(do_change_pin): Ditto.
(do_set_pin_prompt): New.
* scd/app.c (expand_pin_prompt): New.
(app_set_pin_prompt): Ditto.
* scd/command.c (set_pinentry_prompt): New.
(option_handler): Add option 'pin-prompt' and 'pin-admin-prompt'.
(open_card): Set the user-defined pinentry prompts after selecting an
application.
diff --git a/NEWS b/NEWS
index 7d1ae47..f261363 100644
--- a/NEWS
+++ b/NEWS
@@ -4,6 +4,8 @@ Noteworthy changes in version 2.1.0beta4 (unreleased)
* GPG now accepts a space separated fingerprint as a user ID. This
allows to copy and paste the fingerprint from the key listing.
+ * New option for SCDAEMON to set a user defined pinentry prompt.
+
Noteworthy changes in version 2.1.0beta3 (2011-12-20)
-----------------------------------------------------
diff --git a/agent/divert-scd.c b/agent/divert-scd.c
index f176a6b..a2de217 100644
--- a/agent/divert-scd.c
+++ b/agent/divert-scd.c
@@ -166,6 +166,8 @@ encode_md_for_card (const unsigned char *digest, size_t digestlen, int algo,
'A' = The PIN is an Admin PIN, SO-PIN or alike.
'P' = The PIN is a PUK (Personal Unblocking Key).
'R' = The PIN is a Reset Code.
+ 'I' = Ignore using the default prompt and use 'info' as the entire
+ prompt. Cannot be used with other flags.
Example:
@@ -185,6 +187,7 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
int newpin = 0;
int resetcode = 0;
int is_puk = 0;
+ int ignore = 0;
const char *again_text = NULL;
const char *prompt = "PIN";
@@ -212,6 +215,8 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
prompt = _("Reset Code");
resetcode = 1;
}
+ else if (*s == 'I')
+ ignore = 1;
}
info = ends+1;
any_flags = 1;
@@ -219,6 +224,9 @@ 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 (ignore)
+ any_flags = 0;
+
/* If BUF has been passed as NULL, we are in keypad mode: The
callback opens the popup and immediatley returns. */
if (!buf)
@@ -305,8 +313,8 @@ getpin_cb (void *opaque, const char *info, char *buf, size_t maxbuf)
}
else
{
- char *desc;
- if ( asprintf (&desc,
+ char *desc = NULL;
+ if (!ignore && asprintf (&desc,
_("Please enter the PIN%s%s%s to unlock the card"),
info? " (`":"",
info? info:"",
diff --git a/scd/app-common.h b/scd/app-common.h
index e3d23c2..d954932 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -34,6 +34,12 @@
#define APP_CHANGE_FLAG_RESET 1
#define APP_CHANGE_FLAG_NULLPIN 2
+/* For user defined pinentry prompts. */
+enum {
+ PIN_PROMPT_NONE = -1,
+ PIN_SIGN_PROMPT,
+ PIN_ADMIN_PROMPT,
+};
struct app_local_s; /* Defined by all app-*.c. */
@@ -119,6 +125,7 @@ struct app_ctx_s {
gpg_error_t (*check_pin) (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
+ gpg_error_t (*set_pin_prompt)(app_t app, int which, const char *prompt);
} fnc;
};
@@ -192,6 +199,7 @@ gpg_error_t app_genkey (app_t app, ctrl_t ctrl,
time_t createtime,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
+gpg_error_t app_set_pin_prompt (app_t app, int which, const char *prompt);
gpg_error_t app_get_challenge (app_t app, size_t nbytes,
unsigned char *buffer);
gpg_error_t app_change_pin (app_t app, ctrl_t ctrl,
@@ -201,6 +209,8 @@ gpg_error_t app_change_pin (app_t app, ctrl_t ctrl,
gpg_error_t app_check_pin (app_t app, const char *keyidstr,
gpg_error_t (*pincb)(void*, const char *, char **),
void *pincb_arg);
+char *expand_pin_prompt(const char *prompt, const char *prepend, int which,
+ ...);
/*-- app-openpgp.c --*/
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index e3a4484..ea3e52e 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -198,6 +198,8 @@ struct app_local_s {
rsa_key_format_t format;
} keyattr[3];
+ char *pin_prompt; /* As set with set_pin_prompt() or a default. */
+ char *pin_admin_prompt;
};
@@ -242,6 +244,8 @@ do_deinit (app_t app)
xfree (app->app_local->pk[i].key);
app->app_local->pk[i].read_done = 0;
}
+ xfree (app->app_local->pin_prompt);
+ xfree (app->app_local->pin_admin_prompt);
xfree (app->app_local);
app->app_local = NULL;
}
@@ -1520,19 +1524,41 @@ verify_a_chv (app_t app,
if (chvno == 1)
{
+ if (app->app_local->pin_prompt)
+ {
+ prompt_buffer = expand_pin_prompt (app->app_local->pin_prompt, "|I|",
+ PIN_SIGN_PROMPT, sigcount);
+ if (!prompt_buffer)
+ return gpg_error_from_syserror ();
+ }
+ else
+ {
#define PROMPTSTRING _("||Please enter the PIN%%0A[sigs done: %lu]")
- size_t promptsize = strlen (PROMPTSTRING) + 50;
+ size_t promptsize;
- prompt_buffer = xtrymalloc (promptsize);
- if (!prompt_buffer)
- return gpg_error_from_syserror ();
- snprintf (prompt_buffer, promptsize-1, PROMPTSTRING, sigcount);
- prompt = prompt_buffer;
+ promptsize = strlen (PROMPTSTRING) + 50;
+ prompt_buffer = xtrymalloc (promptsize);
+ if (!prompt_buffer)
+ return gpg_error_from_syserror ();
+ snprintf (prompt_buffer, promptsize-1, PROMPTSTRING, sigcount);
#undef PROMPTSTRING
+ }
+
+ prompt = prompt_buffer;
}
else
- prompt = _("||Please enter the PIN");
-
+ {
+ if (app->app_local->pin_prompt)
+ {
+ prompt_buffer = expand_pin_prompt (app->app_local->pin_prompt, "|I|",
+ PIN_PROMPT_NONE, NULL);
+ if (!prompt_buffer)
+ return gpg_error_from_syserror ();
+ prompt = prompt_buffer;
+ }
+ else
+ prompt = _("||Please enter the PIN");
+ }
if (!opt.disable_keypad
&& !iso7816_check_keypad (app->slot, ISO7816_VERIFY, &pininfo) )
@@ -1673,11 +1699,21 @@ build_enter_admin_pin_prompt (app_t app, char **r_prompt)
{
/* TRANSLATORS: Do not translate the "|A|" prefix but keep it at
the start of the string. Use %%0A to force a linefeed. */
- prompt = xtryasprintf (_("|A|Please enter the Admin PIN%%0A"
- "[remaining attempts: %d]"), remaining);
+ if (app->app_local->pin_admin_prompt)
+ prompt = expand_pin_prompt (app->app_local->pin_admin_prompt, "|I|",
+ PIN_ADMIN_PROMPT, remaining);
+ else
+ prompt = xtryasprintf (_("|A|Please enter the Admin PIN%%0A"
+ "[remaining attempts: %d]"), remaining);
}
else
- prompt = xtrystrdup (_("|A|Please enter the Admin PIN"));
+ {
+ if (app->app_local->pin_admin_prompt)
+ prompt = expand_pin_prompt (app->app_local->pin_admin_prompt, "|I|",
+ PIN_PROMPT_NONE, NULL);
+ else
+ prompt = xtrystrdup (_("|A|Please enter the Admin PIN"));
+ }
if (!prompt)
return gpg_error_from_syserror ();
@@ -1999,7 +2035,21 @@ do_change_pin (app_t app, ctrl_t ctrl, const char *chvnostr,
prompt = promptbuf;
}
else
- prompt = _("||Please enter the PIN");
+ {
+ if (app->app_local->pin_prompt)
+ {
+ promptbuf = expand_pin_prompt (app->app_local->pin_prompt,
+ "|I|", PIN_PROMPT_NONE, NULL);
+ if (!promptbuf)
+ {
+ rc = gpg_error_from_syserror ();
+ goto leave;
+ }
+ prompt = promptbuf;
+ }
+ else
+ prompt = _("||Please enter the PIN");
+ }
rc = pincb (pincb_arg, prompt, &oldpinvalue);
xfree (promptbuf);
promptbuf = NULL;
@@ -3707,6 +3757,40 @@ parse_algorithm_attribute (app_t app, int keyno)
xfree (relptr);
}
+gpg_error_t
+do_set_pin_prompt(app_t app, int which, const char *prompt)
+{
+ gpg_error_t rc = 0;
+ char **p = NULL;
+
+ switch (which)
+ {
+ case PIN_SIGN_PROMPT:
+ p = &app->app_local->pin_prompt;
+ break;
+ case PIN_ADMIN_PROMPT:
+ p = &app->app_local->pin_admin_prompt;
+ break;
+ default:
+ break;
+ }
+
+ if (p)
+ {
+ xfree (*p);
+ *p = NULL;
+
+ if (prompt && *prompt != '-' && *(prompt+1) != 0)
+ {
+ *p = xtrystrdup (prompt);
+ if (!*p)
+ rc = gpg_error_from_syserror ();
+ }
+ }
+
+ return rc;
+}
+
/* Select the OpenPGP application on the card in SLOT. This function
must be used before any other OpenPGP application functions. */
gpg_error_t
@@ -3850,6 +3934,7 @@ app_select_openpgp (app_t app)
app->fnc.decipher = do_decipher;
app->fnc.change_pin = do_change_pin;
app->fnc.check_pin = do_check_pin;
+ app->fnc.set_pin_prompt = do_set_pin_prompt;
}
leave:
diff --git a/scd/app.c b/scd/app.c
index 76dc8b4..e0b2fe6 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -922,6 +922,131 @@ app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
return err;
}
+/* For use with user-defined pinentry prompts that are set with the OPTION
+ * command. This function is called from an application before a pinentry is
+ * invoked. It replaces special escape strings in the user-defined 'prompt'
+ * with a single (for now) value set by the calling function. What data type
+ * the vararg value is depends on the 'which' parameter and is set in the
+ * calling function.
+ *
+ * The 'prepend' parameter are any pinentry flags to be prepended to the
+ * expanded prompt. These flags, if any, are not set by the user-defined
+ * prompt but the calling function. In most cases it will be NULL or "|I|".
+ *
+ * The following expandos are recognized:
+ *
+ * expando | which | description
+ * ----------------------------------------
+ * PIN_PROMPT_NONE NOP. The user-defined prompt is returned along
+ * with any 'prepend' parameter.
+ * |S| PIN_SIGN_PROMPT signature count (unsigned long)
+ * |A| PIN_ADMIN_PROMPT remaining attempts (int)
+ *
+ * The following example shows the default pinentry prompt when no
+ * user-defined prompt is set:
+ *
+ * "Please enter the PIN%%0A[sigs done: |S|]"
+ *
+ * Here, |S| is expanded to the number of signatures created so far.
+ */
+char *
+expand_pin_prompt(const char *prompt, const char *prepend, int which, ...)
+{
+ va_list ap;
+ size_t len, n;
+ char *buf;
+ unsigned long luval;
+ int intval;
+ char valuebuf[50] = {0};
+ char *p, *token = NULL, *tokenp;
+
+ if (!prompt)
+ return NULL;
+
+ len = strlen (prompt);
+ len += prepend ? strlen (prepend) : 0;
+ va_start (ap, which);
+
+ switch (which)
+ {
+ /* Signature count. */
+ case PIN_SIGN_PROMPT:
+ luval = va_arg (ap, unsigned long);
+ snprintf (valuebuf, sizeof (valuebuf), "%lu", luval);
+ token = "|S|";
+ break;
+ /* Pin tries remaining. */
+ case PIN_ADMIN_PROMPT:
+ intval = va_arg (ap, int);
+ snprintf (valuebuf, sizeof (valuebuf), "%i", intval);
+ token = "|A|";
+ break;
+ default:
+ break;
+ }
+
+ va_end (ap);
+
+ if (!token)
+ {
+ if (prepend)
+ {
+ len = strlen (prepend)+strlen (prompt)+1;
+ p = xtrymalloc (len);
+ if (!p)
+ return NULL;
+
+ snprintf (p, len, "%s%s", prepend, prompt);
+ return p;
+ }
+
+ return xtrystrdup (prompt);
+ }
+
+ len += strlen (valuebuf)+1;
+ buf = xtrymalloc (len);
+ if (!buf)
+ return NULL;
+
+ buf[0] = 0;
+ if (prepend)
+ strcpy (buf, prepend);
+
+ strcat (buf, prompt);
+
+ if (prepend)
+ p = buf+strlen (prepend);
+ else
+ p = buf;
+
+ tokenp = strstr (p, token);
+ if (!tokenp)
+ return buf;
+
+ p = tokenp+strlen (token);
+ len -= strlen (token)+1;
+ memmove(&buf[len-strlen (p)], p, strlen (p));
+
+ for (n = 0; valuebuf[n]; n++)
+ *tokenp++ = valuebuf[n];
+
+ buf[len] = 0;
+ return buf;
+}
+
+/* Set the prompt shown in the pinentry dialog. If not set then a default will
+ * be used. */
+gpg_error_t
+app_set_pin_prompt(app_t app, int which, const char *prompt)
+{
+ if (!app)
+ return gpg_error (GPG_ERR_INV_VALUE);
+
+ if (!app->fnc.set_pin_prompt)
+ return gpg_error (GPG_ERR_UNSUPPORTED_OPERATION);
+
+ return app->fnc.set_pin_prompt (app, which, prompt);
+}
/* Perform a GET CHALLENGE operation. This fucntion is special as it
directly accesses the card without any application specific
diff --git a/scd/command.c b/scd/command.c
index 88f8ec2..2704e57 100644
--- a/scd/command.c
+++ b/scd/command.c
@@ -139,6 +139,13 @@ struct server_local_s
this session. */
int stopme;
+ /* User-defined pinentry prompt strings. Needed both here and in the app
+ * since they may be set by the user before an app is selected with
+ * select_application(). They are copied to the app when
+ * select_application() succeeds and further modifications done in the app.
+ * */
+ char *pin_prompt;
+ char *pin_admin_prompt;
};
@@ -387,6 +394,39 @@ reset_notify (assuan_context_t ctx, char *line)
return 0;
}
+static gpg_error_t
+set_pinentry_prompt(struct server_local_s *srv, int which, const char *prompt)
+{
+ gpg_error_t rc = 0;
+ char **p = NULL;
+
+ switch (which)
+ {
+ case PIN_SIGN_PROMPT:
+ p = &srv->pin_prompt;
+ break;
+ case PIN_ADMIN_PROMPT:
+ p = &srv->pin_admin_prompt;
+ break;
+ default:
+ break;
+ }
+
+ if (p)
+ {
+ xfree (*p);
+ *p = NULL;
+
+ if (prompt && *prompt != '-' && *(prompt+1) != 0)
+ {
+ *p = xtrystrdup (prompt);
+ if (!*p)
+ rc = gpg_error_from_syserror ();
+ }
+ }
+
+ return rc;
+}
static gpg_error_t
option_handler (assuan_context_t ctx, const char *key, const char *value)
@@ -407,6 +447,22 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->server_local->event_signal = i;
#endif
}
+ /* A user-defined prompt to show in a pinentry overriding the default. See
+ * app.c:expand_pin_prompt() for details. */
+ else if (!strcmp (key, "pin-prompt"))
+ {
+ if (ctrl->app_ctx)
+ return app_set_pin_prompt (ctrl->app_ctx, PIN_SIGN_PROMPT, value);
+ else
+ return set_pinentry_prompt (ctrl->server_local, PIN_SIGN_PROMPT, value);
+ }
+ else if (!strcmp (key, "pin-admin-prompt"))
+ {
+ if (ctrl->app_ctx)
+ return app_set_pin_prompt (ctrl->app_ctx, PIN_ADMIN_PROMPT, value);
+ else
+ return set_pinentry_prompt (ctrl->server_local, PIN_ADMIN_PROMPT, value);
+ }
return 0;
}
@@ -523,7 +579,17 @@ open_card (ctrl_t ctrl, const char *apptype)
err = gpg_error (GPG_ERR_CARD);
}
else
- err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
+ {
+ err = select_application (ctrl, slot, apptype, &ctrl->app_ctx);
+ if (!err)
+ {
+ err = app_set_pin_prompt(ctrl->app_ctx, PIN_SIGN_PROMPT,
+ ctrl->server_local->pin_prompt);
+ if (!err)
+ err = app_set_pin_prompt(ctrl->app_ctx, PIN_ADMIN_PROMPT,
+ ctrl->server_local->pin_admin_prompt);
+ }
+ }
}
TEST_CARD_REMOVAL (ctrl, err);
@@ -2097,6 +2163,8 @@ scd_command_handler (ctrl_t ctrl, int fd)
sl->next_session = ctrl->server_local->next_session;
}
stopme = ctrl->server_local->stopme || reader_disabled;
+ xfree (ctrl->server_local->pin_prompt);
+ xfree (ctrl->server_local->pin_admin_prompt);
xfree (ctrl->server_local);
ctrl->server_local = NULL;
-----------------------------------------------------------------------
hooks/post-receive
--
The GNU Privacy Guard
http://git.gnupg.org
More information about the Gnupg-commits
mailing list