Support the SETQUALITYBAR command of recent pinentries.

This commit is contained in:
Werner Koch 2007-09-18 11:40:09 +00:00
parent 1151d4d6ae
commit a6b11ea482
5 changed files with 150 additions and 9 deletions

View File

@ -1,3 +1,14 @@
2007-09-18 Werner Koch <wk@g10code.com>
* agent.h (struct pin_entry_info_s): Add element WITH_QUALITYBAR.
* genkey.c (check_passphrase_constraints): New arg SILENT.
Changed all callers.
(agent_protect_and_store, agent_genkey): Enable qualitybar.
* call-pinentry.c (agent_askpin): Send that option.
(unescape_passphrase_string): New.
(inq_quality): New.
(estimate_passphrase_quality): New.
2007-09-14 Marcus Brinkmann <marcus@g10code.de>
* call-pinentry.c (agent_popup_message_stop): Implement kill for

View File

@ -169,6 +169,7 @@ struct pin_entry_info_s
int max_digits; /* max. number of allowed digits allowed*/
int max_tries;
int failed_tries;
int with_qualitybar; /* Set if the quality bar should be displayed. */
int (*check_cb)(struct pin_entry_info_s *); /* CB used to check the PIN */
void *check_cb_arg; /* optional argument which might be of use in the CB */
const char *cb_errtext; /* used by the cb to displaye a specific error */
@ -269,7 +270,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
membuf_t *outbuf);
/*-- genkey.c --*/
int check_passphrase_constraints (ctrl_t ctrl, const char *pw);
int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent);
int agent_genkey (ctrl_t ctrl,
const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);

View File

@ -413,6 +413,106 @@ all_digitsp( const char *s)
}
/* 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. PArsing stops at the end of the string or
a white space character. */
static char *
unescape_passphrase_string (const unsigned char *s)
{
char *buffer, *d;
buffer = d = xtrymalloc_secure (strlen ((const char*)s)+1);
if (!buffer)
return NULL;
while (*s && !spacep (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;
}
/* Estimate the quality of the passphrase PW and return a value in the
range 0..100. */
static int
estimate_passphrase_quality (const char *pw)
{
int goodlength = opt.min_passphrase_len + opt.min_passphrase_len/3;
int length;
const char *s;
if (goodlength < 1)
return 0;
for (length = 0, s = pw; *s; s++)
if (!spacep (s))
length ++;
if (length > goodlength)
return 100;
return ((length*10) / goodlength)*10;
}
/* Handle the QUALITY inquiry. */
static int
inq_quality (void *opaque, const char *line)
{
assuan_context_t ctx = opaque;
char *pin;
int rc;
int percent;
char numbuf[20];
if (!strncmp (line, "QUALITY", 7) && (line[7] == ' ' || !line[7]))
{
line += 7;
while (*line == ' ')
line++;
pin = unescape_passphrase_string (line);
if (!pin)
rc = gpg_error_from_syserror ();
else
{
percent = estimate_passphrase_quality (pin);
if (check_passphrase_constraints (NULL, pin, 1))
percent = -percent;
snprintf (numbuf, sizeof numbuf, "%d", percent);
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
xfree (pin);
}
}
else
{
log_error ("unsupported inquiry `%s' from pinentry\n", line);
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
}
return rc;
}
/* Call the Entry and ask for the PIN. We do check for a valid PIN
number here and repeat it as long as we have invalid formed
@ -463,6 +563,16 @@ agent_askpin (ctrl_t ctrl,
if (rc)
return unlock_pinentry (rc);
/* If a passphrase quality indicator has been requested and a
minimum passphrase length has not been disabled, send the command
to the pinentry. */
if (pininfo->with_qualitybar && opt.min_passphrase_len )
{
rc = assuan_transact (entry_ctx, "SETQUALITYBAR",
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
return unlock_pinentry (rc);
}
if (initial_errtext)
{
@ -497,7 +607,7 @@ agent_askpin (ctrl_t ctrl,
}
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm,
NULL, NULL, NULL, NULL);
inq_quality, entry_ctx, NULL, NULL);
/* Most pinentries out in the wild return the old Assuan error code
for canceled which gets translated to an assuan Cancel error and
not to the code for a user cancel. Fix this here. */

View File

@ -912,7 +912,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
}
while (!rc
&& opt_check
&& check_passphrase_constraints (ctrl, response));
&& check_passphrase_constraints (ctrl, response, 0));
if (!rc)
{

View File

@ -168,9 +168,10 @@ take_this_one_anyway (ctrl_t ctrl, const char *desc)
/* Check whether the passphrase PW is suitable. Returns 0 if the
passphrase is suitable and true if it is not and the user should be
asked to provide a different one. */
asked to provide a different one. If SILENT is set, no message are
displayed. */
int
check_passphrase_constraints (ctrl_t ctrl, const char *pw)
check_passphrase_constraints (ctrl_t ctrl, const char *pw, int silent)
{
gpg_error_t err;
unsigned int minlen = opt.min_passphrase_len;
@ -181,7 +182,12 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw)
if (utf8_charcount (pw) < minlen )
{
char *desc = xtryasprintf
char *desc;
if (silent)
return gpg_error (GPG_ERR_INV_PASSPHRASE);
desc = xtryasprintf
( ngettext ("Warning: You have entered a passphrase that%%0A"
"is obviously not secure. A passphrase should%%0A"
"be at least %u character long.",
@ -198,7 +204,12 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw)
if (nonalpha_count (pw) < minnonalpha )
{
char *desc = xtryasprintf
char *desc;
if (silent)
return gpg_error (GPG_ERR_INV_PASSPHRASE);
desc = xtryasprintf
( ngettext ("Warning: You have entered a passphrase that%%0A"
"is obviously not secure. A passphrase should%%0A"
"contain at least %u digit or special character.",
@ -226,6 +237,9 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw)
"is obviously not secure. A passphrase may not%0A"
"be a known term or match certain pattern.");
if (silent)
return gpg_error (GPG_ERR_INV_PASSPHRASE);
err = take_this_one_anyway (ctrl, desc);
if (err)
return err;
@ -242,6 +256,9 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw)
"Please confirm that you do not want to "
"have any protection on your key."));
if (silent)
return gpg_error (GPG_ERR_INV_PASSPHRASE);
err = take_this_one_anyway2 (ctrl, desc,
_("Yes, protection is not needed"));
if (err)
@ -296,6 +313,7 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen,
pi2 = pi + (sizeof *pi + 100);
pi->max_length = 100;
pi->max_tries = 3;
pi->with_qualitybar = 1;
pi2->max_length = 100;
pi2->max_tries = 3;
pi2->check_cb = reenter_compare_cb;
@ -306,7 +324,7 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen,
initial_errtext = NULL;
if (!rc)
{
if (check_passphrase_constraints (ctrl, pi->pin))
if (check_passphrase_constraints (ctrl, pi->pin, 0))
{
pi->failed_tries = 0;
pi2->failed_tries = 0;
@ -417,6 +435,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey)
pi2 = pi + (sizeof *pi + 100);
pi->max_length = 100;
pi->max_tries = 3;
pi->with_qualitybar = 1;
pi2->max_length = 100;
pi2->max_tries = 3;
pi2->check_cb = reenter_compare_cb;
@ -427,7 +446,7 @@ agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey)
initial_errtext = NULL;
if (!rc)
{
if (check_passphrase_constraints (ctrl, pi->pin))
if (check_passphrase_constraints (ctrl, pi->pin, 0))
{
pi->failed_tries = 0;
pi2->failed_tries = 0;