1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-06-13 18:21:03 +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

@ -478,7 +478,8 @@ gpg_error_t agent_askpin (ctrl_t ctrl,
int agent_get_passphrase (ctrl_t ctrl, char **retpass, int agent_get_passphrase (ctrl_t ctrl, char **retpass,
const char *desc, const char *prompt, const char *desc, const char *prompt,
const char *errtext, int with_qualitybar, 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 agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok, int agent_get_confirmation (ctrl_t ctrl, const char *desc, const char *ok,
const char *notokay, int with_cancel); const char *notokay, int with_cancel);
int agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn); int agent_show_message (ctrl_t ctrl, const char *desc, const char *ok_btn);
@ -515,7 +516,7 @@ int agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
membuf_t *outbuf, int *r_padding); membuf_t *outbuf, int *r_padding);
/*-- genkey.c --*/ /*-- genkey.c --*/
int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
char **failed_constraint); char **failed_constraint);
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt, gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
char **r_passphrase); char **r_passphrase);

View File

@ -849,7 +849,7 @@ inq_quality (void *opaque, const char *line)
else else
{ {
percent = estimate_passphrase_quality (pin); percent = estimate_passphrase_quality (pin);
if (check_passphrase_constraints (NULL, pin, NULL)) if (check_passphrase_constraints (NULL, pin, 0, NULL))
percent = -percent; percent = -percent;
snprintf (numbuf, sizeof numbuf, "%d", percent); snprintf (numbuf, sizeof numbuf, "%d", percent);
rc = assuan_send_data (ctx, numbuf, strlen (numbuf)); 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)) if ((pininfo->status & PINENTRY_STATUS_PASSWORD_FROM_CACHE))
/* The password was read from the cache. Don't count this {
against the retry count. */ /* The password was read from the cache. Don't count this
pininfo->failed_tries --; against the retry count. */
pininfo->failed_tries --;
}
} }
return unlock_pinentry (ctrl, gpg_error (pininfo->min_digits? GPG_ERR_BAD_PIN 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 /* 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 int
agent_get_passphrase (ctrl_t ctrl, agent_get_passphrase (ctrl_t ctrl,
char **retpass, const char *desc, const char *prompt, char **retpass, const char *desc, const char *prompt,
const char *errtext, int with_qualitybar, 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 rc;
int is_pin;
char line[ASSUAN_LINELENGTH]; char line[ASSUAN_LINELENGTH];
struct entry_parm_s parm; struct entry_parm_s parm;
@ -1330,17 +1338,42 @@ agent_get_passphrase (ctrl_t ctrl,
if (ctrl->pinentry_mode != PINENTRY_MODE_ASK) if (ctrl->pinentry_mode != PINENTRY_MODE_ASK)
{ {
unsigned char *passphrase;
size_t size;
if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL) if (ctrl->pinentry_mode == PINENTRY_MODE_CANCEL)
return gpg_error (GPG_ERR_CANCELED); 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", return pinentry_loopback (ctrl, "PASSPHRASE",
(unsigned char **)retpass, &size, (unsigned char **)retpass, &size,
MAX_PASSPHRASE_LEN); MAX_PASSPHRASE_LEN);
} }
return gpg_error (GPG_ERR_NO_PIN_ENTRY); return gpg_error (GPG_ERR_NO_PIN_ENTRY);
} }
@ -1348,9 +1381,14 @@ agent_get_passphrase (ctrl_t ctrl,
if (rc) if (rc)
return rc; return rc;
if (!prompt) /* Set IS_PIN and if needed a default prompt. */
prompt = desc && strstr (desc, "PIN")? L_("PIN:"): L_("Passphrase:"); 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 /* 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 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) if (rc && gpg_err_code (rc) != GPG_ERR_ASS_UNKNOWN_CMD)
return unlock_pinentry (ctrl, rc); return unlock_pinentry (ctrl, rc);
if (desc) if (desc)
build_cmd_setdesc (line, DIM(line), desc); build_cmd_setdesc (line, DIM(line), desc);
else else
@ -1385,7 +1422,8 @@ agent_get_passphrase (ctrl_t ctrl,
if (rc) if (rc)
return unlock_pinentry (ctrl, 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); rc = setup_qualitybar (ctrl);
if (rc) if (rc)
@ -1395,23 +1433,132 @@ agent_get_passphrase (ctrl_t ctrl,
if (errtext) if (errtext)
{ {
snprintf (line, DIM(line), "SETERROR %s", 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) if (rc)
return unlock_pinentry (ctrl, rc); return unlock_pinentry (ctrl, rc);
} }
memset (&parm, 0, sizeof parm); if (!pininfo)
parm.size = ASSUAN_LINELENGTH/2 - 5; {
parm.buffer = gcry_malloc_secure (parm.size+10); /* Legacy method without PININFO. */
if (!parm.buffer) memset (&parm, 0, sizeof parm);
return unlock_pinentry (ctrl, out_of_core ()); 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); rc = do_getpin (ctrl, &parm);
if (rc) if (rc)
xfree (parm.buffer); xfree (parm.buffer);
else else
*retpass = parm.buffer; *retpass = parm.buffer;
return unlock_pinentry (ctrl, rc); 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));
} }

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[] = static const char hlp_get_passphrase[] =
"GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n" "GET_PASSPHRASE [--data] [--check] [--no-ask] [--repeat[=N]]\n"
" [--qualitybar] <cache_id>\n" " [--qualitybar] [--newsymkey] <cache_id>\n"
" [<error_message> <prompt> <description>]\n" " [<error_message> <prompt> <description>]\n"
"\n" "\n"
"This function is usually used to ask for a passphrase to be used\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" "cache the user will not be asked to enter a passphrase but the error\n"
"code GPG_ERR_NO_DATA is returned. \n" "code GPG_ERR_NO_DATA is returned. \n"
"\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" "If the option \"--qualitybar\" is used a visual indication of the\n"
"entered passphrase quality is shown. (Unless no minimum passphrase\n" "entered passphrase quality is shown. (Unless no minimum passphrase\n"
"length has been configured.)"; "length has been configured.)";
@ -1576,13 +1592,19 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
ctrl_t ctrl = assuan_get_pointer (ctx); ctrl_t ctrl = assuan_get_pointer (ctx);
int rc; int rc;
char *pw; char *pw;
char *response; char *response = NULL;
char *cacheid = NULL, *desc = NULL, *prompt = NULL, *errtext = 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"); const char *desc2 = _("Please re-enter this passphrase");
char *p; 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; int opt_repeat = 0;
char *entry_errtext = NULL; char *entry_errtext = NULL;
struct pin_entry_info_s *pi = NULL;
struct pin_entry_info_s *pi2 = NULL;
if (ctrl->restricted) if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN)); 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_repeat = 1;
} }
opt_qualbar = has_option (line, "--qualitybar"); opt_qualbar = has_option (line, "--qualitybar");
opt_newsymkey = has_option (line, "--newsymkey");
line = skip_options (line); line = skip_options (line);
cacheid = line; cacheid = line;
@ -1648,26 +1671,116 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
{ {
rc = send_back_passphrase (ctx, opt_data, pw); rc = send_back_passphrase (ctx, opt_data, pw);
xfree (pw); xfree (pw);
goto leave;
} }
else if (opt_no_ask) 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 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: next_try:
xfree (response);
response = NULL;
rc = agent_get_passphrase (ctrl, &response, desc, prompt, rc = agent_get_passphrase (ctrl, &response, desc, prompt,
entry_errtext? entry_errtext:errtext, entry_errtext? entry_errtext:errtext,
opt_qualbar, cacheid, CACHE_MODE_USER); opt_qualbar, cacheid, CACHE_MODE_USER, NULL);
xfree (entry_errtext); xfree (entry_errtext);
entry_errtext = NULL; entry_errtext = NULL;
if (!rc) if (!rc)
@ -1675,27 +1788,24 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
int i; int i;
if (opt_check if (opt_check
&& check_passphrase_constraints (ctrl, response, &entry_errtext)) && check_passphrase_constraints (ctrl, response,0,&entry_errtext))
{ {
xfree (response);
goto next_try; goto next_try;
} }
for (i = 0; i < opt_repeat; i++) for (i = 0; i < opt_repeat; i++)
{ {
char *response2;
if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK) if (ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
break; break;
xfree (response2);
response2 = NULL;
rc = agent_get_passphrase (ctrl, &response2, desc2, prompt, rc = agent_get_passphrase (ctrl, &response2, desc2, prompt,
errtext, 0, errtext, 0,
cacheid, CACHE_MODE_USER); cacheid, CACHE_MODE_USER, NULL);
if (rc) if (rc)
break; break;
if (strcmp (response2, response)) if (strcmp (response2, response))
{ {
xfree (response2);
xfree (response);
entry_errtext = try_percent_escape entry_errtext = try_percent_escape
(_("does not match - try again"), NULL); (_("does not match - try again"), NULL);
if (!entry_errtext) if (!entry_errtext)
@ -1705,7 +1815,6 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
} }
goto next_try; goto next_try;
} }
xfree (response2);
} }
if (!rc) 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); agent_put_cache (ctrl, cacheid, CACHE_MODE_USER, response, 0);
rc = send_back_passphrase (ctx, opt_data, response); 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); 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 (cmd, "GET_PASSPHRASE"))
{ {
if (!strcmp (cmdopt, "repeat")) if (!strcmp (cmdopt, "repeat"))
return 1; return 1;
if (!strcmp (cmdopt, "newsymkey"))
return 1;
} }
return 0; return 0;

View File

@ -161,7 +161,7 @@ take_this_one_anyway (ctrl_t ctrl, const char *desc, const char *anyway_btn)
message describing the problem is returned in message describing the problem is returned in
*FAILED_CONSTRAINT. */ *FAILED_CONSTRAINT. */
int int
check_passphrase_constraints (ctrl_t ctrl, const char *pw, check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
char **failed_constraint) char **failed_constraint)
{ {
gpg_error_t err = 0; gpg_error_t err = 0;
@ -180,7 +180,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw,
/* The first check is to warn about an empty passphrase. */ /* The first check is to warn about an empty passphrase. */
if (!*pw) if (!*pw)
{ {
const char *desc = (opt.enforce_passphrase_constraints? const char *desc = (opt.enforce_passphrase_constraints || no_empty?
L_("You have not entered a passphrase!%0A" L_("You have not entered a passphrase!%0A"
"An empty passphrase is not allowed.") : "An empty passphrase is not allowed.") :
L_("You have not entered a passphrase - " L_("You have not entered a passphrase - "
@ -191,7 +191,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw,
err = 1; err = 1;
if (failed_constraint) if (failed_constraint)
{ {
if (opt.enforce_passphrase_constraints) if (opt.enforce_passphrase_constraints || no_empty)
*failed_constraint = xstrdup (desc); *failed_constraint = xstrdup (desc);
else else
err = take_this_one_anyway (ctrl, desc, err = take_this_one_anyway (ctrl, desc,
@ -381,7 +381,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
initial_errtext = NULL; initial_errtext = NULL;
if (!err) if (!err)
{ {
if (check_passphrase_constraints (ctrl, pi->pin, &initial_errtext)) if (check_passphrase_constraints (ctrl, pi->pin, 0, &initial_errtext))
{ {
pi->failed_tries = 0; pi->failed_tries = 0;
pi2->failed_tries = 0; pi2->failed_tries = 0;