mirror of
git://git.gnupg.org/gnupg.git
synced 2025-07-02 22:46:30 +02:00
agent: New option --newsymkey for GET_PASSPHRASE
* agent/call-pinentry.c (agent_get_passphrase): Add arg pininfo. * agent/genkey.c (check_passphrase_constraints): New arg no_empty. * agent/command.c (reenter_passphrase_cmp_cb): New. (cmd_get_passphrase): Add option --newsymkey. -- This new option allows to present a passphrase with the usual repeat box as it is used by gpg-agent's internal key generation. Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
6864bba78e
commit
eace4bbe1d
4 changed files with 322 additions and 58 deletions
|
@ -849,7 +849,7 @@ inq_quality (void *opaque, const char *line)
|
|||
else
|
||||
{
|
||||
percent = estimate_passphrase_quality (pin);
|
||||
if (check_passphrase_constraints (NULL, pin, NULL))
|
||||
if (check_passphrase_constraints (NULL, pin, 0, NULL))
|
||||
percent = -percent;
|
||||
snprintf (numbuf, sizeof numbuf, "%d", percent);
|
||||
rc = assuan_send_data (ctx, numbuf, strlen (numbuf));
|
||||
|
@ -1301,9 +1301,11 @@ agent_askpin (ctrl_t ctrl,
|
|||
}
|
||||
|
||||
if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
/* The password was read from the cache. Don't count this
|
||||
against the retry count. */
|
||||
pininfo->failed_tries --;
|
||||
{
|
||||
/* The password was read from the cache. Don't count this
|
||||
against the retry count. */
|
||||
pininfo->failed_tries --;
|
||||
}
|
||||
}
|
||||
|
||||
return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
|
||||
|
@ -1313,14 +1315,20 @@ agent_askpin (ctrl_t ctrl,
|
|||
|
||||
|
||||
/* Ask for the passphrase using the supplied arguments. The returned
|
||||
passphrase needs to be freed by the caller. */
|
||||
passphrase needs to be freed by the caller. PININFO is optional
|
||||
and can be used to have constraints checinkg 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
|
||||
functions. */
|
||||
int
|
||||
agent_get_passphrase (ctrl_t ctrl,
|
||||
char **retpass, const char *desc, const char *prompt,
|
||||
const char *errtext, int with_qualitybar,
|
||||
const char *keyinfo, cache_mode_t cache_mode)
|
||||
const char *keyinfo, cache_mode_t cache_mode,
|
||||
struct pin_entry_info_s *pininfo)
|
||||
{
|
||||
int rc;
|
||||
int is_pin;
|
||||
char line[ASSUAN_LINELENGTH];
|
||||
struct entry_parm_s parm;
|
||||
|
||||
|
@ -1330,17 +1338,42 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||
|
||||
if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
|
||||
{
|
||||
unsigned char *passphrase;
|
||||
size_t size;
|
||||
|
||||
if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
|
||||
return gpg_error (GPG_ERR_CANCELED);
|
||||
|
||||
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
|
||||
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK && pininfo)
|
||||
{
|
||||
size_t size;
|
||||
*pininfo->pin = 0; /* Reset the PIN. */
|
||||
rc = pinentry_loopback (ctrl, "PASSPHRASE",
|
||||
&passphrase, &size,
|
||||
pininfo->max_length - 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
memcpy (&pininfo->pin, passphrase, size);
|
||||
wipememory (passphrase, size);
|
||||
xfree (passphrase);
|
||||
pininfo->pin[size] = 0;
|
||||
if (pininfo->check_cb)
|
||||
{
|
||||
/* More checks by utilizing the optional callback. */
|
||||
pininfo->cb_errtext = NULL;
|
||||
rc = pininfo->check_cb (pininfo);
|
||||
}
|
||||
return rc;
|
||||
|
||||
}
|
||||
else if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
|
||||
{
|
||||
/* Legacy variant w/o PININFO. */
|
||||
return pinentry_loopback (ctrl, "PASSPHRASE",
|
||||
(unsigned char **)retpass, &size,
|
||||
MAX_PASSPHRASE_LEN);
|
||||
}
|
||||
|
||||
return gpg_error (GPG_ERR_NO_PIN_ENTRY);
|
||||
}
|
||||
|
||||
|
@ -1348,9 +1381,14 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (!prompt)
|
||||
prompt = desc && strstr (desc, "PIN")? L_("PIN:"): L_("Passphrase:");
|
||||
|
||||
/* Set IS_PIN and if needed a default prompt. */
|
||||
if (prompt)
|
||||
is_pin = !!strstr (prompt, "PIN");
|
||||
else
|
||||
{
|
||||
is_pin = desc && strstr (desc, "PIN");
|
||||
prompt = is_pin? L_("PIN:"): L_("Passphrase:");
|
||||
}
|
||||
|
||||
/* If we have a KEYINFO string and are normal, user, or ssh cache
|
||||
mode, we tell that the Pinentry so it may use it for own caching
|
||||
|
@ -1371,7 +1409,6 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||
if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
|
||||
|
||||
if (desc)
|
||||
build_cmd_setdesc (line, DIM(line), desc);
|
||||
else
|
||||
|
@ -1385,7 +1422,8 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||
if (rc)
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
|
||||
if (with_qualitybar && opt.min_passphrase_len)
|
||||
if ((with_qualitybar || (pininfo && pininfo->with_qualitybar))
|
||||
&& opt.min_passphrase_len)
|
||||
{
|
||||
rc = setup_qualitybar (ctrl);
|
||||
if (rc)
|
||||
|
@ -1395,23 +1433,132 @@ agent_get_passphrase (ctrl_t ctrl,
|
|||
if (errtext)
|
||||
{
|
||||
snprintf (line, DIM(line), "SETERROR %s", errtext);
|
||||
rc = assuan_transact (entry_ctx, line, NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
rc = assuan_transact (entry_ctx, line,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
}
|
||||
|
||||
memset (&parm, 0, sizeof parm);
|
||||
parm.size = ASSUAN_LINELENGTH/2 - 5;
|
||||
parm.buffer = gcry_malloc_secure (parm.size+10);
|
||||
if (!parm.buffer)
|
||||
return unlock_pinentry (ctrl, out_of_core ());
|
||||
if (!pininfo)
|
||||
{
|
||||
/* Legacy method without PININFO. */
|
||||
memset (&parm, 0, sizeof parm);
|
||||
parm.size = ASSUAN_LINELENGTH/2 - 5;
|
||||
parm.buffer = gcry_malloc_secure (parm.size+10);
|
||||
if (!parm.buffer)
|
||||
return unlock_pinentry (ctrl, out_of_core ());
|
||||
|
||||
rc = do_getpin (ctrl, &parm);
|
||||
if (rc)
|
||||
xfree (parm.buffer);
|
||||
else
|
||||
*retpass = parm.buffer;
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
rc = do_getpin (ctrl, &parm);
|
||||
if (rc)
|
||||
xfree (parm.buffer);
|
||||
else
|
||||
*retpass = parm.buffer;
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
}
|
||||
|
||||
/* We got PININFO. */
|
||||
|
||||
if (pininfo->with_repeat)
|
||||
{
|
||||
snprintf (line, DIM(line), "SETREPEATERROR %s",
|
||||
L_("does not match - try again"));
|
||||
rc = assuan_transact (entry_ctx, line,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
pininfo->with_repeat = 0; /* Pinentry does not support it. */
|
||||
}
|
||||
pininfo->repeat_okay = 0;
|
||||
pininfo->status = 0;
|
||||
|
||||
for (;pininfo->failed_tries < pininfo->max_tries; pininfo->failed_tries++)
|
||||
{
|
||||
memset (&parm, 0, sizeof parm);
|
||||
parm.size = pininfo->max_length;
|
||||
parm.buffer = (unsigned char*)pininfo->pin;
|
||||
*pininfo->pin = 0; /* Reset the PIN. */
|
||||
|
||||
if (errtext)
|
||||
{
|
||||
/* TRANSLATORS: The string is appended to an error message in
|
||||
the pinentry. The %s is the actual error message, the
|
||||
two %d give the current and maximum number of tries. */
|
||||
snprintf (line, DIM(line), L_("SETERROR %s (try %d of %d)"),
|
||||
errtext, pininfo->failed_tries+1, pininfo->max_tries);
|
||||
rc = assuan_transact (entry_ctx, line,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
errtext = NULL;
|
||||
}
|
||||
|
||||
if (pininfo->with_repeat)
|
||||
{
|
||||
snprintf (line, DIM(line), "SETREPEAT %s", L_("Repeat:"));
|
||||
rc = assuan_transact (entry_ctx, line,
|
||||
NULL, NULL, NULL, NULL, NULL, NULL);
|
||||
if (rc)
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
}
|
||||
|
||||
rc = do_getpin (ctrl, &parm);
|
||||
pininfo->status = parm.status;
|
||||
if (gpg_err_code (rc) == GPG_ERR_ASS_TOO_MUCH_DATA)
|
||||
errtext = is_pin? L_("PIN too long")
|
||||
: L_("Passphrase too long");
|
||||
else if (rc)
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
|
||||
if (!errtext && pininfo->min_digits)
|
||||
{
|
||||
/* do some basic checks on the entered PIN. */
|
||||
if (!all_digitsp (pininfo->pin))
|
||||
errtext = L_("Invalid characters in PIN");
|
||||
else if (pininfo->max_digits
|
||||
&& strlen (pininfo->pin) > pininfo->max_digits)
|
||||
errtext = L_("PIN too long");
|
||||
else if (strlen (pininfo->pin) < pininfo->min_digits)
|
||||
errtext = L_("PIN too short");
|
||||
}
|
||||
|
||||
if (!errtext && pininfo->check_cb)
|
||||
{
|
||||
/* More checks by utilizing the optional callback. */
|
||||
pininfo->cb_errtext = NULL;
|
||||
rc = pininfo->check_cb (pininfo);
|
||||
/* When pinentry cache causes an error, return now. */
|
||||
if (rc && (pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
|
||||
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
|
||||
{
|
||||
if (pininfo->cb_errtext)
|
||||
errtext = pininfo->cb_errtext;
|
||||
else if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE
|
||||
|| gpg_err_code (rc) == GPG_ERR_BAD_PIN)
|
||||
errtext = (is_pin? L_("Bad PIN") : L_("Bad Passphrase"));
|
||||
}
|
||||
else if (rc)
|
||||
return unlock_pinentry (ctrl, rc);
|
||||
}
|
||||
|
||||
if (!errtext)
|
||||
{
|
||||
if (pininfo->with_repeat
|
||||
&& (pininfo->status & PINENTRY_STATUS_PIN_REPEATED))
|
||||
pininfo->repeat_okay = 1;
|
||||
return unlock_pinentry (ctrl, 0); /* okay, got a PIN or passphrase */
|
||||
}
|
||||
|
||||
if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
|
||||
{
|
||||
/* The password was read from the Pinentry's own cache.
|
||||
Don't count this against the retry count. */
|
||||
pininfo->failed_tries--;
|
||||
}
|
||||
}
|
||||
|
||||
return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN
|
||||
: GPG_ERR_BAD_PASSPHRASE));
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue