Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: GnuPG: devel

[PATCH] Added user defined pinentry prompts for SCD.

 

 

GnuPG devel RSS feed   Index | Next | Previous | View Threaded


bjk at luxsci

Jan 10, 2012, 7:19 PM

Post #1 of 4 (155 views)
Permalink
[PATCH] Added 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 | 12 +++++-
scd/app-common.h | 9 ++++
scd/app-openpgp.c | 108 ++++++++++++++++++++++++++++++++++++++++++++++------
scd/app.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
scd/command.c | 68 ++++++++++++++++++++++++++++++++-
5 files changed, 274 insertions(+), 15 deletions(-)

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..d89c5dc 100644
--- a/scd/app-common.h
+++ b/scd/app-common.h
@@ -34,6 +34,11 @@
#define APP_CHANGE_FLAG_RESET 1
#define APP_CHANGE_FLAG_NULLPIN 2

+/* For user defined pinentry prompts. */
+enum {
+ PIN_PROMPT,
+ PIN_ADMIN_PROMPT,
+};

struct app_local_s; /* Defined by all app-*.c. */

@@ -119,6 +124,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 +198,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 +208,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..a840c98 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_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|",
+ -1, 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|",
+ -1, 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|", -1, 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,39 @@ 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_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 +3933,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..0e722c6 100644
--- a/scd/app.c
+++ b/scd/app.c
@@ -923,6 +923,98 @@ app_genkey (app_t app, ctrl_t ctrl, const char *keynostr, unsigned int flags,
}


+/* Replaces special escapes in a user defined pinentry prompt with the
+ * argument value where 'which' is one of:
+ *
+ * PIN_PROMPT: |S| - signature count (unsigned long)
+ * PIN_ADMIN_PROMPT: |A| - remaining attempts (int)
+ *
+ * The escapes in the prompt are replaced with the values. A prompt is set
+ * with the OPTION command and reset to the default when it's value is -.
+ */
+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_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;
+ }
+
+ va_end(ap);
+
+ if (!token)
+ 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
wrapper. */
diff --git a/scd/command.c b/scd/command.c
index 88f8ec2..6e6d89b 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 defined 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_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,20 @@ option_handler (assuan_context_t ctx, const char *key, const char *value)
ctrl->server_local->event_signal = i;
#endif
}
+ else if (!strcmp (key, "pin-prompt"))
+ {
+ if (ctrl->app_ctx)
+ return app_set_pin_prompt(ctrl->app_ctx, PIN_PROMPT, value);
+ else
+ return set_pinentry_prompt(ctrl->server_local, PIN_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 +577,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_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 +2161,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;

--
1.7.7.3


_______________________________________________
Gnupg-devel mailing list
Gnupg-devel [at] gnupg
http://lists.gnupg.org/mailman/listinfo/gnupg-devel


wk at gnupg

Jan 11, 2012, 4:07 AM

Post #2 of 4 (142 views)
Permalink
Re: [PATCH] Added user defined pinentry prompts for SCD. [In reply to]

On Wed, 11 Jan 2012 04:19, bjk [at] luxsci said:
> 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.

Would you mind to describe a use case for this feature?


Shalom-Salam,

Werner

--
Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz.


_______________________________________________
Gnupg-devel mailing list
Gnupg-devel [at] gnupg
http://lists.gnupg.org/mailman/listinfo/gnupg-devel


bjk at luxsci

Jan 11, 2012, 3:25 PM

Post #3 of 4 (142 views)
Permalink
Re: [PATCH] Added user defined pinentry prompts for SCD. [In reply to]

On Wed, Jan 11, 2012 at 01:07:29PM +0100, Werner Koch wrote:
> On Wed, 11 Jan 2012 04:19, bjk [at] luxsci said:
> > 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.
>
> Would you mind to describe a use case for this feature?

To inform the user where the pinentry came from or what the pinentry is
for. For example, my server program has clients the connect to it and
these clients can set a client name that the server can use to keep
track of in log files. Using this new option, the server program can set
the pinentry prompt to inform the user of what client needs the
pinentry rather than only prompting for a PIN.

I noticed a discussion in the ML of setting the pinentry title but this
patch modifies the pinentry description strings. A title patch would be
good to have, too.

I posted the patch here so folks can review it and maybe suggest a
better way of going about it. It does need other application support
(only app-openpgp has been modified to make use of it). Maybe it would
be better to make a pin-prompt branch?

Have a good one,

--
Ben Kibbey
[XMPP: bjk AT jabber DOT org] - [IRC: (bjk) FreeNode/OFTC]

_______________________________________________
Gnupg-devel mailing list
Gnupg-devel [at] gnupg
http://lists.gnupg.org/mailman/listinfo/gnupg-devel


wk at gnupg

Jan 12, 2012, 1:23 AM

Post #4 of 4 (142 views)
Permalink
Re: [PATCH] Added user defined pinentry prompts for SCD. [In reply to]

On Thu, 12 Jan 2012 00:25, bjk [at] luxsci said:

> I posted the patch here so folks can review it and maybe suggest a
> better way of going about it. It does need other application support

I am fine with the patch after some indentaion changes.

> (only app-openpgp has been modified to make use of it). Maybe it would
> be better to make a pin-prompt branch?

Yes, please do that.


Salam-Shalom,

Werner

--
Die Gedanken sind frei. Ausnahmen regelt ein Bundesgesetz.


_______________________________________________
Gnupg-devel mailing list
Gnupg-devel [at] gnupg
http://lists.gnupg.org/mailman/listinfo/gnupg-devel

GnuPG devel RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.