1
0
Fork 0
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:
Werner Koch 2020-07-08 14:20:01 +02:00
parent 6864bba78e
commit eace4bbe1d
No known key found for this signature in database
GPG key ID: E3FDFF218E45B72B
4 changed files with 322 additions and 58 deletions

View file

@ -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));
}