aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Heinecke <aheinecke@gnupg.org>2020-11-06 14:19:24 +0100
committerAndre Heinecke <aheinecke@gnupg.org>2020-11-06 14:22:28 +0100
commit557ddbde32585c534626b57a595a2ccf28fd585e (patch)
treeaa899dc3d1ec9161336826960ea7f48bc2768a09
parent31e47dfad0f40e31e8b3113b933696e8e4105136 (diff)
downloadgnupg-557ddbde32585c534626b57a595a2ccf28fd585e.tar.gz
agent: Add genpin inquiry for pinentry
* agent/call-pinentry.c (agent_get_passphrase): Setup genpin. (do_getpin): Update with new name for inquire callback. (inq_quality): Rename to inq_cb and add genpin support. (inq_cb): Renamed form inq_quality. (generate_pin): New helper to generate a pin. (agent_askpin): Fix some typos. (setup_genpin): Provide new strings for pinentry. -- This implements the gpg-agent side for generating a pin especially for symmetric encryption using libgcrypt randomness and checking it against the gpg-agent constraints.
-rw-r--r--agent/call-pinentry.c124
1 files changed, 116 insertions, 8 deletions
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index a2ac14ab2..6eabd87f2 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -38,6 +38,7 @@
#include <assuan.h>
#include "../common/sysutils.h"
#include "../common/i18n.h"
+#include "../common/zb32.h"
#ifdef _POSIX_OPEN_MAX
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
@@ -52,6 +53,11 @@
time. */
#define LOCK_TIMEOUT (1*60)
+/* Define the maximum tries to generate a pin for the GENPIN inquire */
+#define MAX_GENPIN_TRIES 10
+/* Define the number of characters to use for a generated pin */
+#define DEFAULT_GENPIN_BYTES (128 / 8)
+
/* The assuan context of the current pinentry. */
static assuan_context_t entry_ctx;
@@ -829,20 +835,40 @@ estimate_passphrase_quality (const char *pw)
return ((length*10) / goodlength)*10;
}
+static char *
+generate_pin (void)
+{
+ size_t nbytes = opt.min_passphrase_len;
+ void *rand = NULL;
+ char *generated = NULL;
+ if (nbytes < 8)
+ {
+ nbytes = DEFAULT_GENPIN_BYTES;
+ }
+ rand = gcry_random_bytes_secure (nbytes, GCRY_VERY_STRONG_RANDOM);
+ if (!rand)
+ {
+ log_error ("Failed to generate random pin\n");
+ return NULL;
+ }
+ generated = zb32_encode (rand, nbytes * 8);
+ gcry_free (rand);
+ return generated;
+}
-/* Handle the QUALITY inquiry. */
+/* Handle inquiries. */
static gpg_error_t
-inq_quality (void *opaque, const char *line)
+inq_cb (void *opaque, const char *line)
{
assuan_context_t ctx = opaque;
const char *s;
- char *pin;
int rc;
- int percent;
- char numbuf[20];
if ((s = has_leading_keyword (line, "QUALITY")))
{
+ char numbuf[20];
+ int percent;
+ char *pin;
pin = unescape_passphrase_string (s);
if (!pin)
rc = gpg_error_from_syserror ();
@@ -856,6 +882,35 @@ inq_quality (void *opaque, const char *line)
xfree (pin);
}
}
+ else if ((s = has_leading_keyword (line, "GENPIN")))
+ {
+ int tries;
+ char *pin;
+ for (tries = 0; tries < MAX_GENPIN_TRIES; tries ++)
+ {
+ pin = generate_pin ();
+ if (!pin)
+ {
+ log_error ("Failed to generate a pin \n");
+ rc = gpg_error (GPG_ERR_GENERAL);
+ break;
+ }
+ if (!check_passphrase_constraints (NULL, pin, 0, NULL))
+ {
+ rc = assuan_send_data (ctx, pin, strlen (pin));
+ xfree (pin);
+ break;
+ }
+ xfree (pin);
+ pin = NULL;
+ }
+ if (!pin)
+ {
+ log_error ("Failed to generate a pin after %i tries\n",
+ MAX_GENPIN_TRIES);
+ rc = gpg_error (GPG_ERR_GENERAL);
+ }
+ }
else
{
log_error ("unsupported inquiry '%s' from pinentry\n", line);
@@ -865,6 +920,57 @@ inq_quality (void *opaque, const char *line)
return rc;
}
+/* Helper to setup pinentry for genpin action. */
+static gpg_error_t
+setup_genpin (ctrl_t ctrl)
+{
+ int rc;
+ char line[ASSUAN_LINELENGTH];
+ char *tmpstr, *tmpstr2;
+ const char *tooltip;
+
+ (void)ctrl;
+
+ /* TRANSLATORS: This string is displayed by Pinentry as the label
+ for generating a passphrase. */
+ tmpstr = try_percent_escape (L_("Generate"), "\t\r\n\f\v");
+ snprintf (line, DIM(line), "SETGENPIN %s", tmpstr? tmpstr:"");
+ xfree (tmpstr);
+ rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc == 103 /*(Old assuan error code)*/
+ || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
+ ; /* Ignore Unknown Command from old Pinentry versions. */
+ else if (rc)
+ return rc;
+
+ tmpstr2 = gnupg_get_help_string ("pinentry.genpin.tooltip", 0);
+ if (tmpstr2)
+ tooltip = tmpstr2;
+ else
+ {
+ /* TRANSLATORS: This string is a tooltip, shown by pinentry when
+ hovering over the quality bar. Please use an appropriate
+ string to describe what this is about. The length of the
+ tooltip is limited to about 900 characters. If you do not
+ translate this entry, a default english text (see source)
+ will be used. */
+ tooltip = L_("pinentry.genpin.tooltip");
+ if (!strcmp ("pinentry.genpin.tooltip", tooltip))
+ tooltip = ("Generate a random passphrase.");
+ }
+ tmpstr = try_percent_escape (tooltip, "\t\r\n\f\v");
+ xfree (tmpstr2);
+ snprintf (line, DIM(line), "SETGENPIN_TT %s", tmpstr? tmpstr:"");
+ xfree (tmpstr);
+ rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
+ if (rc == 103 /*(Old assuan error code)*/
+ || gpg_err_code (rc) == GPG_ERR_ASS_UNKNOWN_CMD)
+ ; /* Ignore Unknown Command from old pinentry versions. */
+ else if (rc)
+ return rc;
+
+ return 0;
+}
/* Helper for agent_askpin and agent_get_passphrase. */
static gpg_error_t
@@ -1073,7 +1179,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
assuan_begin_confidential (entry_ctx);
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm,
- inq_quality, entry_ctx,
+ inq_cb, entry_ctx,
pinentry_status_cb, &parm->status);
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
/* Most pinentries out in the wild return the old Assuan error code
@@ -1316,9 +1422,9 @@ agent_askpin (ctrl_t ctrl,
/* Ask for the passphrase using the supplied arguments. The returned
passphrase needs to be freed by the caller. PININFO is optional
- and can be used to have constraints checinkg while the pinentry
+ and can be used to have constraints checking while the pinentry
dialog is open (like what we do in agent_askpin). This is very
- similar to agent_akpin and we should eventually merge the two
+ similar to agent_askpin and we should eventually merge the two
functions. */
int
agent_get_passphrase (ctrl_t ctrl,
@@ -1466,6 +1572,8 @@ agent_get_passphrase (ctrl_t ctrl,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
pininfo->with_repeat = 0; /* Pinentry does not support it. */
+
+ setup_genpin (ctrl);
}
pininfo->repeat_okay = 0;
pininfo->status = 0;