mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
agent: Ignore passphrase constraints for a generated passphrase.
* agent/agent.h (PINENTRY_STATUS_PASSWORD_GENERATED): New. (MAX_GENPIN_TRIES): Remove. * agent/call-pinentry.c (struct entry_parm_s): (struct inq_cb_parm_s): Add genpinhash and genpinhas_valid. (is_generated_pin): New. (inq_cb): Suppress constraints checking for a generated passphrase. No more need for several tries to generate the passphrase. (do_getpin): Store a generated passphrase/pin in the status field. (agent_askpin): Suppress constraints checking for a generated passphrase. (agent_get_passphrase): Ditto. * agent/command.c (cmd_get_passphrase): Ditto. -- A generated passphrase has enough entropy so that all kind of extra checks would only reduce the actual available entropy. We thus detect if a passphrase has been generated (and not changed) and skip all passphrase constraints checking.
This commit is contained in:
parent
8ed7910347
commit
b89b1f35c2
@ -296,7 +296,8 @@ enum
|
|||||||
{
|
{
|
||||||
PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
|
PINENTRY_STATUS_CLOSE_BUTTON = 1 << 0,
|
||||||
PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
|
PINENTRY_STATUS_PIN_REPEATED = 1 << 8,
|
||||||
PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9
|
PINENTRY_STATUS_PASSWORD_FROM_CACHE = 1 << 9,
|
||||||
|
PINENTRY_STATUS_PASSWORD_GENERATED = 1 << 10
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Information pertaining to pinentry requests. */
|
/* Information pertaining to pinentry requests. */
|
||||||
|
@ -53,8 +53,6 @@
|
|||||||
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 bits to use for a generated pin. The
|
/* Define the number of bits to use for a generated pin. The
|
||||||
* passphrase will be rendered as zbase32 which results for 150 bits
|
* passphrase will be rendered as zbase32 which results for 150 bits
|
||||||
* in a string of 30 characters. That fits nicely into the 5
|
* in a string of 30 characters. That fits nicely into the 5
|
||||||
@ -882,9 +880,32 @@ struct inq_cb_parm_s
|
|||||||
{
|
{
|
||||||
assuan_context_t ctx;
|
assuan_context_t ctx;
|
||||||
unsigned int flags; /* CHECK_CONSTRAINTS_... */
|
unsigned int flags; /* CHECK_CONSTRAINTS_... */
|
||||||
|
int genpinhash_valid;
|
||||||
|
char genpinhash[32]; /* Hash of the last generated pin. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* Return true if PIN is indentical to the last generated pin. */
|
||||||
|
static int
|
||||||
|
is_generated_pin (struct inq_cb_parm_s *parm, const char *pin)
|
||||||
|
{
|
||||||
|
char hashbuf[32];
|
||||||
|
|
||||||
|
if (!parm->genpinhash_valid)
|
||||||
|
return 0;
|
||||||
|
if (!*pin)
|
||||||
|
return 0;
|
||||||
|
/* Note that we compare the hash so that we do not need to save the
|
||||||
|
* generated PIN longer than needed. */
|
||||||
|
gcry_md_hash_buffer (GCRY_MD_SHA256, hashbuf, pin, strlen (pin));
|
||||||
|
|
||||||
|
if (!memcmp (hashbuf, parm->genpinhash, 32))
|
||||||
|
return 1; /* yes, it is the same. */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
inq_cb (void *opaque, const char *line)
|
inq_cb (void *opaque, const char *line)
|
||||||
{
|
{
|
||||||
@ -929,7 +950,8 @@ inq_cb (void *opaque, const char *line)
|
|||||||
err = gpg_error_from_syserror ();
|
err = gpg_error_from_syserror ();
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (check_passphrase_constraints (NULL, pin, parm->flags, &errtext))
|
if (!is_generated_pin (parm, pin)
|
||||||
|
&& check_passphrase_constraints (NULL, pin,parm->flags, &errtext))
|
||||||
{
|
{
|
||||||
if (errtext)
|
if (errtext)
|
||||||
{
|
{
|
||||||
@ -954,32 +976,24 @@ inq_cb (void *opaque, const char *line)
|
|||||||
}
|
}
|
||||||
else if ((s = has_leading_keyword (line, "GENPIN")))
|
else if ((s = has_leading_keyword (line, "GENPIN")))
|
||||||
{
|
{
|
||||||
int tries;
|
int wasconf;
|
||||||
|
|
||||||
for (tries = 0; tries < MAX_GENPIN_TRIES; tries ++)
|
parm->genpinhash_valid = 0;
|
||||||
|
pin = generate_pin ();
|
||||||
|
if (!pin)
|
||||||
{
|
{
|
||||||
pin = generate_pin ();
|
log_error ("failed to generate a passphrase\n");
|
||||||
if (!pin)
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
{
|
goto leave;
|
||||||
log_error ("failed to generate a passphrase\n");
|
|
||||||
err = gpg_error (GPG_ERR_GENERAL);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
if (!check_passphrase_constraints (NULL, pin, parm->flags, NULL))
|
|
||||||
{
|
|
||||||
int wasconf = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
|
||||||
assuan_begin_confidential (parm->ctx);
|
|
||||||
err = assuan_send_data (parm->ctx, pin, strlen (pin));
|
|
||||||
if (!wasconf)
|
|
||||||
assuan_end_confidential (parm->ctx);
|
|
||||||
xfree (pin);
|
|
||||||
goto leave;
|
|
||||||
}
|
|
||||||
xfree (pin);
|
|
||||||
}
|
}
|
||||||
log_error ("failed to generate a passphrase after %i tries\n",
|
wasconf = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
||||||
MAX_GENPIN_TRIES);
|
assuan_begin_confidential (parm->ctx);
|
||||||
err = gpg_error (GPG_ERR_GENERAL);
|
err = assuan_send_data (parm->ctx, pin, strlen (pin));
|
||||||
|
if (!wasconf)
|
||||||
|
assuan_end_confidential (parm->ctx);
|
||||||
|
gcry_md_hash_buffer (GCRY_MD_SHA256, parm->genpinhash, pin, strlen (pin));
|
||||||
|
parm->genpinhash_valid = 1;
|
||||||
|
xfree (pin);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1376,6 +1390,7 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
|
|||||||
|
|
||||||
inq_cb_parm.ctx = entry_ctx;
|
inq_cb_parm.ctx = entry_ctx;
|
||||||
inq_cb_parm.flags = parm->constraints_flags;
|
inq_cb_parm.flags = parm->constraints_flags;
|
||||||
|
inq_cb_parm.genpinhash_valid = 0;
|
||||||
|
|
||||||
wasconf = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
wasconf = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
||||||
assuan_begin_confidential (entry_ctx);
|
assuan_begin_confidential (entry_ctx);
|
||||||
@ -1385,6 +1400,11 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
|
|||||||
if (!wasconf)
|
if (!wasconf)
|
||||||
assuan_end_confidential (entry_ctx);
|
assuan_end_confidential (entry_ctx);
|
||||||
|
|
||||||
|
if (!rc && parm->buffer && is_generated_pin (&inq_cb_parm, parm->buffer))
|
||||||
|
parm->status |= PINENTRY_STATUS_PASSWORD_GENERATED;
|
||||||
|
else
|
||||||
|
parm->status &= ~PINENTRY_STATUS_PASSWORD_GENERATED;
|
||||||
|
|
||||||
/* 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. */
|
||||||
@ -1417,6 +1437,7 @@ agent_askpin (ctrl_t ctrl,
|
|||||||
struct entry_parm_s parm;
|
struct entry_parm_s parm;
|
||||||
const char *errtext = NULL;
|
const char *errtext = NULL;
|
||||||
int is_pin = 0;
|
int is_pin = 0;
|
||||||
|
int is_generated;
|
||||||
|
|
||||||
if (opt.batch)
|
if (opt.batch)
|
||||||
return 0; /* fixme: we should return BAD PIN */
|
return 0; /* fixme: we should return BAD PIN */
|
||||||
@ -1562,13 +1583,15 @@ agent_askpin (ctrl_t ctrl,
|
|||||||
|
|
||||||
rc = do_getpin (ctrl, &parm);
|
rc = do_getpin (ctrl, &parm);
|
||||||
pininfo->status = parm.status;
|
pininfo->status = parm.status;
|
||||||
|
is_generated = !!(parm.status & PINENTRY_STATUS_PASSWORD_GENERATED);
|
||||||
|
|
||||||
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
|
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
|
||||||
errtext = is_pin? L_("PIN too long")
|
errtext = is_pin? L_("PIN too long")
|
||||||
: L_("Passphrase too long");
|
: L_("Passphrase too long");
|
||||||
else if (rc)
|
else if (rc)
|
||||||
return unlock_pinentry (ctrl, rc);
|
return unlock_pinentry (ctrl, rc);
|
||||||
|
|
||||||
if (!errtext && pininfo->min_digits)
|
if (!errtext && pininfo->min_digits && !is_generated)
|
||||||
{
|
{
|
||||||
/* do some basic checks on the entered PIN. */
|
/* do some basic checks on the entered PIN. */
|
||||||
if (!all_digitsp (pininfo->pin))
|
if (!all_digitsp (pininfo->pin))
|
||||||
@ -1580,7 +1603,7 @@ agent_askpin (ctrl_t ctrl,
|
|||||||
errtext = L_("PIN too short");
|
errtext = L_("PIN too short");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!errtext && pininfo->check_cb)
|
if (!errtext && pininfo->check_cb && !is_generated)
|
||||||
{
|
{
|
||||||
/* More checks by utilizing the optional callback. */
|
/* More checks by utilizing the optional callback. */
|
||||||
pininfo->cb_errtext = NULL;
|
pininfo->cb_errtext = NULL;
|
||||||
@ -1639,6 +1662,7 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
int is_pin;
|
int is_pin;
|
||||||
|
int is_generated;
|
||||||
char line[ASSUAN_LINELENGTH];
|
char line[ASSUAN_LINELENGTH];
|
||||||
struct entry_parm_s parm;
|
struct entry_parm_s parm;
|
||||||
|
|
||||||
@ -1793,6 +1817,7 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||||||
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
|
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
|
||||||
{
|
{
|
||||||
memset (&parm, 0, sizeof parm);
|
memset (&parm, 0, sizeof parm);
|
||||||
|
parm.constraints_flags = pininfo->constraints_flags;
|
||||||
parm.size = pininfo->max_length;
|
parm.size = pininfo->max_length;
|
||||||
parm.buffer = (unsigned char*)pininfo->pin;
|
parm.buffer = (unsigned char*)pininfo->pin;
|
||||||
*pininfo->pin = 0; /* Reset the PIN. */
|
*pininfo->pin = 0; /* Reset the PIN. */
|
||||||
@ -1822,13 +1847,15 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||||||
|
|
||||||
rc = do_getpin (ctrl, &parm);
|
rc = do_getpin (ctrl, &parm);
|
||||||
pininfo->status = parm.status;
|
pininfo->status = parm.status;
|
||||||
|
is_generated = !!(parm.status & PINENTRY_STATUS_PASSWORD_GENERATED);
|
||||||
|
|
||||||
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
|
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
|
||||||
errtext = is_pin? L_("PIN too long")
|
errtext = is_pin? L_("PIN too long")
|
||||||
: L_("Passphrase too long");
|
: L_("Passphrase too long");
|
||||||
else if (rc)
|
else if (rc)
|
||||||
return unlock_pinentry (ctrl, rc);
|
return unlock_pinentry (ctrl, rc);
|
||||||
|
|
||||||
if (!errtext && pininfo->min_digits)
|
if (!errtext && pininfo->min_digits && !is_generated)
|
||||||
{
|
{
|
||||||
/* do some basic checks on the entered PIN. */
|
/* do some basic checks on the entered PIN. */
|
||||||
if (!all_digitsp (pininfo->pin))
|
if (!all_digitsp (pininfo->pin))
|
||||||
@ -1840,7 +1867,7 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||||||
errtext = L_("PIN too short");
|
errtext = L_("PIN too short");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!errtext && pininfo->check_cb)
|
if (!errtext && pininfo->check_cb && !is_generated)
|
||||||
{
|
{
|
||||||
/* More checks by utilizing the optional callback. */
|
/* More checks by utilizing the optional callback. */
|
||||||
pininfo->cb_errtext = NULL;
|
pininfo->cb_errtext = NULL;
|
||||||
|
@ -1760,6 +1760,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
|||||||
char *entry_errtext = NULL;
|
char *entry_errtext = NULL;
|
||||||
struct pin_entry_info_s *pi = NULL;
|
struct pin_entry_info_s *pi = NULL;
|
||||||
struct pin_entry_info_s *pi2 = NULL;
|
struct pin_entry_info_s *pi2 = NULL;
|
||||||
|
int is_generated;
|
||||||
|
|
||||||
if (ctrl->restricted)
|
if (ctrl->restricted)
|
||||||
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
|
||||||
@ -1892,10 +1893,13 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
|||||||
goto leave;
|
goto leave;
|
||||||
xfree (entry_errtext);
|
xfree (entry_errtext);
|
||||||
entry_errtext = NULL;
|
entry_errtext = NULL;
|
||||||
|
is_generated = !!(pi->status & PINENTRY_STATUS_PASSWORD_GENERATED);
|
||||||
|
|
||||||
/* We don't allow an empty passpharse in this mode. */
|
/* We don't allow an empty passpharse in this mode. */
|
||||||
if (check_passphrase_constraints (ctrl, pi->pin,
|
if (!is_generated
|
||||||
pi->constraints_flags,
|
&& check_passphrase_constraints (ctrl, pi->pin,
|
||||||
&entry_errtext))
|
pi->constraints_flags,
|
||||||
|
&entry_errtext))
|
||||||
{
|
{
|
||||||
pi->failed_tries = 0;
|
pi->failed_tries = 0;
|
||||||
pi2->failed_tries = 0;
|
pi2->failed_tries = 0;
|
||||||
@ -1951,11 +1955,14 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
|||||||
opt_qualbar, cacheid, CACHE_MODE_USER, NULL);
|
opt_qualbar, cacheid, CACHE_MODE_USER, NULL);
|
||||||
xfree (entry_errtext);
|
xfree (entry_errtext);
|
||||||
entry_errtext = NULL;
|
entry_errtext = NULL;
|
||||||
|
is_generated = !!(pi->status & PINENTRY_STATUS_PASSWORD_GENERATED);
|
||||||
|
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (opt_check
|
if (opt_check
|
||||||
|
&& !is_generated
|
||||||
&& check_passphrase_constraints
|
&& check_passphrase_constraints
|
||||||
(ctrl, response,
|
(ctrl, response,
|
||||||
(opt_newsymkey? CHECK_CONSTRAINTS_NEW_SYMKEY:0),
|
(opt_newsymkey? CHECK_CONSTRAINTS_NEW_SYMKEY:0),
|
||||||
|
@ -476,7 +476,11 @@ user for a new passphrase and masking of the passphrase is turned off.
|
|||||||
|
|
||||||
If passphrase formatting is enabled, then all non-breaking space characters
|
If passphrase formatting is enabled, then all non-breaking space characters
|
||||||
are stripped from the entered passphrase. Passphrase formatting is mostly
|
are stripped from the entered passphrase. Passphrase formatting is mostly
|
||||||
useful in combination with passphrases generated with the GENPIN command.
|
useful in combination with passphrases generated with the GENPIN
|
||||||
|
feature of some Pinentries. Note that such a generated
|
||||||
|
passphrase, if not modified by the user, skips all passphrase
|
||||||
|
constraints checking because such constraints would actually weaken
|
||||||
|
the generated passphrase.
|
||||||
|
|
||||||
@item --pinentry-program @var{filename}
|
@item --pinentry-program @var{filename}
|
||||||
@opindex pinentry-program
|
@opindex pinentry-program
|
||||||
|
Loading…
x
Reference in New Issue
Block a user