mirror of git://git.gnupg.org/gnupg.git
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.
This commit is contained in:
parent
31e47dfad0
commit
557ddbde32
|
@ -38,6 +38,7 @@
|
||||||
#include <assuan.h>
|
#include <assuan.h>
|
||||||
#include "../common/sysutils.h"
|
#include "../common/sysutils.h"
|
||||||
#include "../common/i18n.h"
|
#include "../common/i18n.h"
|
||||||
|
#include "../common/zb32.h"
|
||||||
|
|
||||||
#ifdef _POSIX_OPEN_MAX
|
#ifdef _POSIX_OPEN_MAX
|
||||||
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
|
#define MAX_OPEN_FDS _POSIX_OPEN_MAX
|
||||||
|
@ -52,6 +53,11 @@
|
||||||
time. */
|
time. */
|
||||||
#define LOCK_TIMEOUT (1*60)
|
#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. */
|
/* The assuan context of the current pinentry. */
|
||||||
static assuan_context_t entry_ctx;
|
static assuan_context_t entry_ctx;
|
||||||
|
|
||||||
|
@ -829,20 +835,40 @@ estimate_passphrase_quality (const char *pw)
|
||||||
return ((length*10) / goodlength)*10;
|
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
|
static gpg_error_t
|
||||||
inq_quality (void *opaque, const char *line)
|
inq_cb (void *opaque, const char *line)
|
||||||
{
|
{
|
||||||
assuan_context_t ctx = opaque;
|
assuan_context_t ctx = opaque;
|
||||||
const char *s;
|
const char *s;
|
||||||
char *pin;
|
|
||||||
int rc;
|
int rc;
|
||||||
int percent;
|
|
||||||
char numbuf[20];
|
|
||||||
|
|
||||||
if ((s = has_leading_keyword (line, "QUALITY")))
|
if ((s = has_leading_keyword (line, "QUALITY")))
|
||||||
{
|
{
|
||||||
|
char numbuf[20];
|
||||||
|
int percent;
|
||||||
|
char *pin;
|
||||||
pin = unescape_passphrase_string (s);
|
pin = unescape_passphrase_string (s);
|
||||||
if (!pin)
|
if (!pin)
|
||||||
rc = gpg_error_from_syserror ();
|
rc = gpg_error_from_syserror ();
|
||||||
|
@ -856,6 +882,35 @@ inq_quality (void *opaque, const char *line)
|
||||||
xfree (pin);
|
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
|
else
|
||||||
{
|
{
|
||||||
log_error ("unsupported inquiry '%s' from pinentry\n", line);
|
log_error ("unsupported inquiry '%s' from pinentry\n", line);
|
||||||
|
@ -865,6 +920,57 @@ inq_quality (void *opaque, const char *line)
|
||||||
return rc;
|
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. */
|
/* Helper for agent_askpin and agent_get_passphrase. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
|
@ -1073,7 +1179,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
|
||||||
|
|
||||||
assuan_begin_confidential (entry_ctx);
|
assuan_begin_confidential (entry_ctx);
|
||||||
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm,
|
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm,
|
||||||
inq_quality, entry_ctx,
|
inq_cb, entry_ctx,
|
||||||
pinentry_status_cb, &parm->status);
|
pinentry_status_cb, &parm->status);
|
||||||
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
|
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
|
||||||
/* Most pinentries out in the wild return the old Assuan error code
|
/* 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
|
/* Ask for the passphrase using the supplied arguments. The returned
|
||||||
passphrase needs to be freed by the caller. PININFO is optional
|
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
|
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. */
|
functions. */
|
||||||
int
|
int
|
||||||
agent_get_passphrase (ctrl_t ctrl,
|
agent_get_passphrase (ctrl_t ctrl,
|
||||||
|
@ -1466,6 +1572,8 @@ agent_get_passphrase (ctrl_t ctrl,
|
||||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||||
if (rc)
|
if (rc)
|
||||||
pininfo->with_repeat = 0; /* Pinentry does not support it. */
|
pininfo->with_repeat = 0; /* Pinentry does not support it. */
|
||||||
|
|
||||||
|
setup_genpin (ctrl);
|
||||||
}
|
}
|
||||||
pininfo->repeat_okay = 0;
|
pininfo->repeat_okay = 0;
|
||||||
pininfo->status = 0;
|
pininfo->status = 0;
|
||||||
|
|
Loading…
Reference in New Issue