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> 2007-09-14 Marcus Brinkmann <marcus@g10code.de>
* call-pinentry.c (agent_popup_message_stop): Implement kill for * 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_digits; /* max. number of allowed digits allowed*/
int max_tries; int max_tries;
int failed_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 */ 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 */ 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 */ 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); membuf_t *outbuf);
/*-- genkey.c --*/ /*-- 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, int agent_genkey (ctrl_t ctrl,
const char *keyparam, size_t keyparmlen, membuf_t *outbuf); const char *keyparam, size_t keyparmlen, membuf_t *outbuf);
int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey); 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 /* 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 number here and repeat it as long as we have invalid formed
@ -463,6 +563,16 @@ agent_askpin (ctrl_t ctrl,
if (rc) if (rc)
return unlock_pinentry (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) if (initial_errtext)
{ {
@ -497,7 +607,7 @@ agent_askpin (ctrl_t ctrl,
} }
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, &parm, 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 /* Most pinentries out in the wild return the old Assuan error code
for canceled which gets translated to an assuan Cancel error and for canceled which gets translated to an assuan Cancel error and
not to the code for a user cancel. Fix this here. */ 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 while (!rc
&& opt_check && opt_check
&& check_passphrase_constraints (ctrl, response)); && check_passphrase_constraints (ctrl, response, 0));
if (!rc) 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 /* 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 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 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; gpg_error_t err;
unsigned int minlen = opt.min_passphrase_len; 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 ) 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" ( ngettext ("Warning: You have entered a passphrase that%%0A"
"is obviously not secure. A passphrase should%%0A" "is obviously not secure. A passphrase should%%0A"
"be at least %u character long.", "be at least %u character long.",
@ -198,7 +204,12 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw)
if (nonalpha_count (pw) < minnonalpha ) 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" ( ngettext ("Warning: You have entered a passphrase that%%0A"
"is obviously not secure. A passphrase should%%0A" "is obviously not secure. A passphrase should%%0A"
"contain at least %u digit or special character.", "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" "is obviously not secure. A passphrase may not%0A"
"be a known term or match certain pattern."); "be a known term or match certain pattern.");
if (silent)
return gpg_error (GPG_ERR_INV_PASSPHRASE);
err = take_this_one_anyway (ctrl, desc); err = take_this_one_anyway (ctrl, desc);
if (err) if (err)
return err; return err;
@ -242,6 +256,9 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw)
"Please confirm that you do not want to " "Please confirm that you do not want to "
"have any protection on your key.")); "have any protection on your key."));
if (silent)
return gpg_error (GPG_ERR_INV_PASSPHRASE);
err = take_this_one_anyway2 (ctrl, desc, err = take_this_one_anyway2 (ctrl, desc,
_("Yes, protection is not needed")); _("Yes, protection is not needed"));
if (err) if (err)
@ -296,6 +313,7 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen,
pi2 = pi + (sizeof *pi + 100); pi2 = pi + (sizeof *pi + 100);
pi->max_length = 100; pi->max_length = 100;
pi->max_tries = 3; pi->max_tries = 3;
pi->with_qualitybar = 1;
pi2->max_length = 100; pi2->max_length = 100;
pi2->max_tries = 3; pi2->max_tries = 3;
pi2->check_cb = reenter_compare_cb; pi2->check_cb = reenter_compare_cb;
@ -306,7 +324,7 @@ agent_genkey (ctrl_t ctrl, const char *keyparam, size_t keyparamlen,
initial_errtext = NULL; initial_errtext = NULL;
if (!rc) if (!rc)
{ {
if (check_passphrase_constraints (ctrl, pi->pin)) if (check_passphrase_constraints (ctrl, pi->pin, 0))
{ {
pi->failed_tries = 0; pi->failed_tries = 0;
pi2->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); pi2 = pi + (sizeof *pi + 100);
pi->max_length = 100; pi->max_length = 100;
pi->max_tries = 3; pi->max_tries = 3;
pi->with_qualitybar = 1;
pi2->max_length = 100; pi2->max_length = 100;
pi2->max_tries = 3; pi2->max_tries = 3;
pi2->check_cb = reenter_compare_cb; 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; initial_errtext = NULL;
if (!rc) if (!rc)
{ {
if (check_passphrase_constraints (ctrl, pi->pin)) if (check_passphrase_constraints (ctrl, pi->pin, 0))
{ {
pi->failed_tries = 0; pi->failed_tries = 0;
pi2->failed_tries = 0; pi2->failed_tries = 0;