summaryrefslogtreecommitdiffstats
path: root/agent
diff options
context:
space:
mode:
authorWerner Koch <wk@gnupg.org>2007-09-18 13:40:09 +0200
committerWerner Koch <wk@gnupg.org>2007-09-18 13:40:09 +0200
commita6b11ea482651c3cd9430a226d875246b26af3c9 (patch)
tree54b57a0743dfc30710c91bc4d16777e882e3045d /agent
parent2007-09-14 Marcus Brinkmann <marcus@g10code.de> (diff)
downloadgnupg2-a6b11ea482651c3cd9430a226d875246b26af3c9.tar.xz
gnupg2-a6b11ea482651c3cd9430a226d875246b26af3c9.zip
Support the SETQUALITYBAR command of recent pinentries.
Diffstat (limited to 'agent')
-rw-r--r--agent/ChangeLog11
-rw-r--r--agent/agent.h3
-rw-r--r--agent/call-pinentry.c112
-rw-r--r--agent/command.c2
-rw-r--r--agent/genkey.c31
5 files changed, 150 insertions, 9 deletions
diff --git a/agent/ChangeLog b/agent/ChangeLog
index a10d29800..2aa2c1375 100644
--- a/agent/ChangeLog
+++ b/agent/ChangeLog
@@ -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
diff --git a/agent/agent.h b/agent/agent.h
index 7d76e4380..41b44c322 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -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);
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index 14cc4229a..2afe9f12a 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -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. */
diff --git a/agent/command.c b/agent/command.c
index bb3d52fbb..431639b1c 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -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)
{
diff --git a/agent/genkey.c b/agent/genkey.c
index 48ba39dee..9901e9e1e 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -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;