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

@ -1543,9 +1543,22 @@ send_back_passphrase (assuan_context_t ctx, int via_data, const char *pw)
}
/* Callback function to compare the first entered PIN with the one
currently being entered. */
static gpg_error_t
reenter_passphrase_cmp_cb (struct pin_entry_info_s *pi)
{
const char *pin1 = pi->check_cb_arg;
if (!strcmp (pin1, pi->pin))
return 0; /* okay */
return gpg_error (GPG_ERR_BAD_PASSPHRASE);
}
static const char hlp_get_passphrase[] =
"GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n"
" [--qualitybar] <cache_id>\n"
" [--qualitybar] [--newsymkey] <cache_id>\n"
" [<error_message> <prompt> <description>]\n"
"\n"
"This function is usually used to ask for a passphrase to be used\n"
@ -1567,6 +1580,9 @@ static const char hlp_get_passphrase[] =
"cache the user will not be asked to enter a passphrase but the error\n"
"code GPG_ERR_NO_DATA is returned. \n"
"\n"
"If the option\"--newsymkey\" is used the agent asks for a new passphrase\n"
"to be used in symmetric-only encryption. This must not be empty.\n"
"\n"
"If the option \"--qualitybar\" is used a visual indication of the\n"
"entered passphrase quality is shown. (Unless no minimum passphrase\n"
"length has been configured.)";
@ -1576,13 +1592,19 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
ctrl_t ctrl = assuan_get_pointer (ctx);
int rc;
char *pw;
char *response;
char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = NULL;
char *response = NULL;
char *response2 = NULL;
char *cacheid = NULL; /* May point into LINE. */
char *desc = NULL; /* Ditto */
char *prompt = NULL; /* Ditto */
char *errtext = NULL; /* Ditto */
const char *desc2 = _("Please re-enter this passphrase");
char *p;
int opt_data, opt_check, opt_no_ask, opt_qualbar;
int opt_data, opt_check, opt_no_ask, opt_qualbar, opt_newsymkey;
int opt_repeat = 0;
char *entry_errtext = NULL;
struct pin_entry_info_s *pi = NULL;
struct pin_entry_info_s *pi2 = NULL;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@ -1599,6 +1621,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
opt_repeat = 1;
}
opt_qualbar = has_option (line, "--qualitybar");
opt_newsymkey = has_option (line, "--newsymkey");
line = skip_options (line);
cacheid = line;
@ -1648,26 +1671,116 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
{
rc = send_back_passphrase (ctx, opt_data, pw);
xfree (pw);
goto leave;
}
else if (opt_no_ask)
rc = gpg_error (GPG_ERR_NO_DATA);
{
rc = gpg_error (GPG_ERR_NO_DATA);
goto leave;
}
/* Note, that we only need to replace the + characters and should
* leave the other escaping in place because the escaped string is
* send verbatim to the pinentry which does the unescaping (but not
* the + replacing) */
if (errtext)
plus_to_blank (errtext);
if (prompt)
plus_to_blank (prompt);
if (desc)
plus_to_blank (desc);
if (opt_newsymkey)
{
/* We do not want to break any existing usage of this command
* and thus we introduced the option --newsymkey to make this
* command more useful to query the passphrase for symmetric
* encryption. */
pi = gcry_calloc_secure (1, sizeof (*pi) + MAX_PASSPHRASE_LEN + 1);
if (!pi)
{
rc = gpg_error_from_syserror ();
goto leave;
}
pi2 = gcry_calloc_secure (1, sizeof (*pi2) + MAX_PASSPHRASE_LEN + 1);
if (!pi2)
{
rc = gpg_error_from_syserror ();
goto leave;
}
pi->max_length = MAX_PASSPHRASE_LEN + 1;
pi->max_tries = 3;
pi->with_qualitybar = opt_qualbar;
pi->with_repeat = opt_repeat;
pi2->max_length = MAX_PASSPHRASE_LEN + 1;
pi2->max_tries = 3;
pi2->check_cb = reenter_passphrase_cmp_cb;
pi2->check_cb_arg = pi->pin;
for (;;) /* (degenerated for-loop) */
{
xfree (response);
response = NULL;
rc = agent_get_passphrase (ctrl, &response,
desc,
prompt,
entry_errtext? entry_errtext:errtext,
opt_qualbar, cacheid, CACHE_MODE_USER,
pi);
if (rc)
goto leave;
xfree (entry_errtext);
entry_errtext = NULL;
/* We don't allow an empty passpharse in this mode. */
if (check_passphrase_constraints (ctrl, pi->pin, 1, &entry_errtext))
{
pi->failed_tries = 0;
pi2->failed_tries = 0;
continue;
}
if (*pi->pin && !pi->repeat_okay)
{
/* The passphrase is empty and the pinentry did not
* already run the repetition check, do it here. This
* is only called when using an old and simple pinentry. */
xfree (response);
response = NULL;
rc = agent_get_passphrase (ctrl, &response,
L_("Please re-enter this passphrase"),
prompt,
entry_errtext? entry_errtext:errtext,
opt_qualbar, cacheid, CACHE_MODE_USER,
pi2);
if (gpg_err_code (rc) == GPG_ERR_BAD_PASSPHRASE)
{ /* The re-entered passphrase one did not match and
* the user did not hit cancel. */
entry_errtext = xtrystrdup (L_("does not match - try again"));
if (!entry_errtext)
{
rc = gpg_error_from_syserror ();
goto leave;
}
continue;
}
}
break;
}
if (!rc && *pi->pin)
{
/* Return the passphrase. */
if (cacheid)
agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, pi->pin, 0);
rc = send_back_passphrase (ctx, opt_data, pi->pin);
}
}
else
{
/* Note, that we only need to replace the + characters and
should leave the other escaping in place because the escaped
string is send verbatim to the pinentry which does the
unescaping (but not the + replacing) */
if (errtext)
plus_to_blank (errtext);
if (prompt)
plus_to_blank (prompt);
if (desc)
plus_to_blank (desc);
next_try:
xfree (response);
response = NULL;
rc = agent_get_passphrase (ctrl, &response, desc, prompt,
entry_errtext? entry_errtext:errtext,
opt_qualbar, cacheid, CACHE_MODE_USER);
opt_qualbar, cacheid, CACHE_MODE_USER, NULL);
xfree (entry_errtext);
entry_errtext = NULL;
if (!rc)
@ -1675,27 +1788,24 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
int i;
if (opt_check
&& check_passphrase_constraints (ctrl, response, &entry_errtext))
&& check_passphrase_constraints (ctrl, response,0,&entry_errtext))
{
xfree (response);
goto next_try;
}
for (i = 0; i < opt_repeat; i++)
{
char *response2;
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
break;
xfree (response2);
response2 = NULL;
rc = agent_get_passphrase (ctrl, &response2, desc2, prompt,
errtext, 0,
cacheid, CACHE_MODE_USER);
cacheid, CACHE_MODE_USER, NULL);
if (rc)
break;
if (strcmp (response2, response))
{
xfree (response2);
xfree (response);
entry_errtext = try_percent_escape
(_("does not match - try again"), NULL);
if (!entry_errtext)
@ -1705,7 +1815,6 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
}
goto next_try;
}
xfree (response2);
}
if (!rc)
{
@ -1713,10 +1822,15 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0);
rc = send_back_passphrase (ctx, opt_data, response);
}
xfree (response);
}
}
leave:
xfree (response);
xfree (response2);
xfree (entry_errtext);
xfree (pi2);
xfree (pi);
return leave_cmd (ctx, rc);
}
@ -3555,7 +3669,9 @@ command_has_option (const char *cmd, const char *cmdopt)
if (!strcmp (cmd, "GET_PASSPHRASE"))
{
if (!strcmp (cmdopt, "repeat"))
return 1;
return 1;
if (!strcmp (cmdopt, "newsymkey"))
return 1;
}
return 0;