mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
agent: New option --check-sym-passphrase-pattern.
* agent/gpg-agent.c (oCheckSymPassphrasePattern): New. (opts): Add --check-sym-passphrase-pattern. (parse_rereadable_options): Set option. (main): Return option info. * tools/gpgconf-comp.c: Add new option. * agent/agent.h (opt): Add var check_sym_passphrase_pattern. (struct pin_entry_info_s): Add var constraints_flags. (CHECK_CONSTRAINTS_NOT_EMPTY): New to replace a hardwired 1. (CHECK_CONSTRAINTS_NEW_SYMKEY): New. * agent/genkey.c (check_passphrase_pattern): Rename to ... (do_check_passphrase_pattern): this to make code reading easier. Handle the --check-sym-passphrase-pattern option. (check_passphrase_constraints): Replace arg no_empty by a generic flags arg. Also handle --check-sym-passphrase-pattern here. * agent/command.c (cmd_get_passphrase): In --newsymkey mode pass CHECK_CONSTRAINTS_NEW_SYMKEY flag. * agent/call-pinentry.c (struct entry_parm_s): Add constraints_flags. (struct inq_cb_parm_s): New. (inq_cb): Use new struct for parameter passing. Pass flags to teh constraints checking. (do_getpin): Pass constraints flag down. (agent_askpin): Take constrainst flag from the supplied pinentry struct. -- Requirements for a passphrase to protect a private key and for a passphrase used for symmetric encryption are different. Thus a the use of a different pattern file will be useful. Note that a pattern file can be used to replace the other passphrase constraints options and thus we don't need to duplicate them for symmetric encryption. GnuPG-bug-id: 5517 Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
parent
22c5461b4a
commit
7c45a69eb9
@ -126,8 +126,11 @@ struct
|
||||
/* The minimum number of non-alpha characters in a passphrase. */
|
||||
unsigned int min_passphrase_nonalpha;
|
||||
|
||||
/* File name with a patternfile or NULL if not enabled. */
|
||||
/* File name with a patternfile or NULL if not enabled. If the
|
||||
* second one is set, it is used for symmetric only encryption
|
||||
* instead of the former. */
|
||||
const char *check_passphrase_pattern;
|
||||
const char *check_sym_passphrase_pattern;
|
||||
|
||||
/* If not 0 the user is asked to change his passphrase after these
|
||||
number of days. */
|
||||
@ -302,6 +305,7 @@ struct pin_entry_info_s
|
||||
int min_digits; /* min. number of digits required or 0 for freeform entry */
|
||||
int max_digits; /* max. number of allowed digits allowed*/
|
||||
int max_tries; /* max. number of allowed tries. */
|
||||
unsigned int constraints_flags; /* CHECK_CONSTRAINTS_... */
|
||||
int failed_tries; /* Number of tries so far failed. */
|
||||
int with_qualitybar; /* Set if the quality bar should be displayed. */
|
||||
int with_repeat; /* Request repetition of the passphrase. */
|
||||
@ -524,7 +528,11 @@ gpg_error_t agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
|
||||
membuf_t *outbuf, int *r_padding);
|
||||
|
||||
/*-- genkey.c --*/
|
||||
int check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
|
||||
#define CHECK_CONSTRAINTS_NOT_EMPTY 1
|
||||
#define CHECK_CONSTRAINTS_NEW_SYMKEY 2
|
||||
|
||||
int check_passphrase_constraints (ctrl_t ctrl, const char *pw,
|
||||
unsigned int flags,
|
||||
char **failed_constraint);
|
||||
gpg_error_t agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
|
||||
char **r_passphrase);
|
||||
|
@ -91,6 +91,7 @@ struct entry_parm_s
|
||||
size_t size;
|
||||
unsigned char *buffer;
|
||||
int status;
|
||||
unsigned int constraints_flags;
|
||||
};
|
||||
|
||||
|
||||
@ -865,10 +866,17 @@ generate_pin (void)
|
||||
|
||||
|
||||
/* Handle inquiries. */
|
||||
struct inq_cb_parm_s
|
||||
{
|
||||
assuan_context_t ctx;
|
||||
unsigned int flags; /* CHECK_CONSTRAINTS_... */
|
||||
};
|
||||
|
||||
|
||||
static gpg_error_t
|
||||
inq_cb (void *opaque, const char *line)
|
||||
{
|
||||
assuan_context_t ctx = opaque;
|
||||
struct inq_cb_parm_s *parm = opaque;
|
||||
gpg_error_t err;
|
||||
const char *s;
|
||||
char *pin;
|
||||
@ -884,10 +892,10 @@ inq_cb (void *opaque, const char *line)
|
||||
else
|
||||
{
|
||||
percent = estimate_passphrase_quality (pin);
|
||||
if (check_passphrase_constraints (NULL, pin, 0, NULL))
|
||||
if (check_passphrase_constraints (NULL, pin, parm->flags, NULL))
|
||||
percent = -percent;
|
||||
snprintf (numbuf, sizeof numbuf, "%d", percent);
|
||||
err = assuan_send_data (ctx, numbuf, strlen (numbuf));
|
||||
err = assuan_send_data (parm->ctx, numbuf, strlen (numbuf));
|
||||
xfree (pin);
|
||||
}
|
||||
}
|
||||
@ -909,14 +917,14 @@ inq_cb (void *opaque, const char *line)
|
||||
err = gpg_error_from_syserror ();
|
||||
else
|
||||
{
|
||||
if (check_passphrase_constraints (NULL, pin, 0, &errtext))
|
||||
if (check_passphrase_constraints (NULL, pin, parm->flags, &errtext))
|
||||
{
|
||||
if (errtext)
|
||||
{
|
||||
/* Unescape the percent-escaped errtext because
|
||||
assuan_send_data escapes it again. */
|
||||
errtextlen = percent_unescape_inplace (errtext, 0);
|
||||
err = assuan_send_data (ctx, errtext, errtextlen);
|
||||
err = assuan_send_data (parm->ctx, errtext, errtextlen);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -926,7 +934,7 @@ inq_cb (void *opaque, const char *line)
|
||||
}
|
||||
else
|
||||
{
|
||||
err = assuan_send_data (ctx, NULL, 0);
|
||||
err = assuan_send_data (parm->ctx, NULL, 0);
|
||||
}
|
||||
xfree (errtext);
|
||||
xfree (pin);
|
||||
@ -945,11 +953,11 @@ inq_cb (void *opaque, const char *line)
|
||||
err = gpg_error (GPG_ERR_GENERAL);
|
||||
goto leave;
|
||||
}
|
||||
if (!check_passphrase_constraints (NULL, pin, 0, NULL))
|
||||
if (!check_passphrase_constraints (NULL, pin, parm->flags, NULL))
|
||||
{
|
||||
assuan_begin_confidential (ctx);
|
||||
err = assuan_send_data (ctx, pin, strlen (pin));
|
||||
assuan_end_confidential (ctx);
|
||||
assuan_begin_confidential (parm->ctx);
|
||||
err = assuan_send_data (parm->ctx, pin, strlen (pin));
|
||||
assuan_end_confidential (parm->ctx);
|
||||
xfree (pin);
|
||||
goto leave;
|
||||
}
|
||||
@ -1333,14 +1341,18 @@ do_getpin (ctrl_t ctrl, struct entry_parm_s *parm)
|
||||
int saveflag = assuan_get_flag (entry_ctx, ASSUAN_CONFIDENTIAL);
|
||||
gnupg_fd_t sock_watched = ctrl->thread_startup.fd;
|
||||
npth_t thread;
|
||||
struct inq_cb_parm_s inq_cb_parm;
|
||||
|
||||
rc = watch_sock_start (&sock_watched, &thread);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
inq_cb_parm.ctx = entry_ctx;
|
||||
inq_cb_parm.flags = parm->constraints_flags;
|
||||
|
||||
assuan_begin_confidential (entry_ctx);
|
||||
rc = assuan_transact (entry_ctx, "GETPIN", getpin_cb, parm,
|
||||
inq_cb, entry_ctx,
|
||||
inq_cb, &inq_cb_parm,
|
||||
pinentry_status_cb, &parm->status);
|
||||
assuan_set_flag (entry_ctx, ASSUAN_CONFIDENTIAL, saveflag);
|
||||
/* Most pinentries out in the wild return the old Assuan error code
|
||||
@ -1493,6 +1505,7 @@ agent_askpin (ctrl_t ctrl,
|
||||
parm.size = pininfo->max_length;
|
||||
*pininfo->pin = 0; /* Reset the PIN. */
|
||||
parm.buffer = (unsigned char*)pininfo->pin;
|
||||
parm.constraints_flags = pininfo->constraints_flags;
|
||||
|
||||
if (errtext)
|
||||
{
|
||||
|
@ -1871,6 +1871,8 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
||||
pi->max_tries = 3;
|
||||
pi->with_qualitybar = opt_qualbar;
|
||||
pi->with_repeat = opt_repeat;
|
||||
pi->constraints_flags = (CHECK_CONSTRAINTS_NOT_EMPTY
|
||||
| CHECK_CONSTRAINTS_NEW_SYMKEY);
|
||||
pi2->max_length = MAX_PASSPHRASE_LEN + 1;
|
||||
pi2->max_tries = 3;
|
||||
pi2->check_cb = reenter_passphrase_cmp_cb;
|
||||
@ -1891,7 +1893,9 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
||||
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))
|
||||
if (check_passphrase_constraints (ctrl, pi->pin,
|
||||
pi->constraints_flags,
|
||||
&entry_errtext))
|
||||
{
|
||||
pi->failed_tries = 0;
|
||||
pi2->failed_tries = 0;
|
||||
@ -1952,7 +1956,10 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
|
||||
int i;
|
||||
|
||||
if (opt_check
|
||||
&& check_passphrase_constraints (ctrl, response,0,&entry_errtext))
|
||||
&& check_passphrase_constraints
|
||||
(ctrl, response,
|
||||
(opt_newsymkey? CHECK_CONSTRAINTS_NEW_SYMKEY:0),
|
||||
&entry_errtext))
|
||||
{
|
||||
goto next_try;
|
||||
}
|
||||
|
@ -89,9 +89,11 @@ nonalpha_count (const char *s)
|
||||
|
||||
|
||||
/* Check PW against a list of pattern. Return 0 if PW does not match
|
||||
these pattern. */
|
||||
these pattern. If CHECK_CONSTRAINTS_NEW_SYMKEY is set in flags and
|
||||
--check-sym-passphrase-pattern has been configured, use the pattern
|
||||
file from that option. */
|
||||
static int
|
||||
check_passphrase_pattern (ctrl_t ctrl, const char *pw)
|
||||
do_check_passphrase_pattern (ctrl_t ctrl, const char *pw, unsigned int flags)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
const char *pgmname = gnupg_module_name (GNUPG_MODULE_NAME_CHECK_PATTERN);
|
||||
@ -99,9 +101,17 @@ check_passphrase_pattern (ctrl_t ctrl, const char *pw)
|
||||
const char *argv[10];
|
||||
pid_t pid;
|
||||
int result, i;
|
||||
const char *pattern;
|
||||
|
||||
(void)ctrl;
|
||||
|
||||
pattern = opt.check_passphrase_pattern;
|
||||
if ((flags & CHECK_CONSTRAINTS_NEW_SYMKEY)
|
||||
&& opt.check_sym_passphrase_pattern)
|
||||
pattern = opt.check_sym_passphrase_pattern;
|
||||
if (!pattern)
|
||||
return 1; /* Oops - Assume password should not be used */
|
||||
|
||||
infp = gnupg_tmpfile ();
|
||||
if (!infp)
|
||||
{
|
||||
@ -124,7 +134,7 @@ check_passphrase_pattern (ctrl_t ctrl, const char *pw)
|
||||
i = 0;
|
||||
argv[i++] = "--null";
|
||||
argv[i++] = "--",
|
||||
argv[i++] = opt.check_passphrase_pattern,
|
||||
argv[i++] = pattern,
|
||||
argv[i] = NULL;
|
||||
log_assert (i < sizeof argv);
|
||||
|
||||
@ -156,12 +166,17 @@ take_this_one_anyway (ctrl_t ctrl, const char *desc, const char *anyway_btn)
|
||||
|
||||
|
||||
/* Check whether the passphrase PW is suitable. Returns 0 if the
|
||||
passphrase is suitable and true if it is not and the user should be
|
||||
asked to provide a different one. If FAILED_CONSTRAINT is set, a
|
||||
message describing the problem is returned in
|
||||
*FAILED_CONSTRAINT. */
|
||||
* passphrase is suitable and true if it is not and the user should be
|
||||
* asked to provide a different one. If FAILED_CONSTRAINT is set, a
|
||||
* message describing the problem is returned at FAILED_CONSTRAINT.
|
||||
* The FLAGS are:
|
||||
* CHECK_CONSTRAINTS_NOT_EMPTY
|
||||
* Do not allow an empty passphrase
|
||||
* CHECK_CONSTRAINTS_NEW_SYMKEY
|
||||
* Hint that the passphrase is used for a new symmetric key.
|
||||
*/
|
||||
int
|
||||
check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
|
||||
check_passphrase_constraints (ctrl_t ctrl, const char *pw, unsigned int flags,
|
||||
char **failed_constraint)
|
||||
{
|
||||
gpg_error_t err = 0;
|
||||
@ -170,6 +185,7 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
|
||||
char *msg1 = NULL;
|
||||
char *msg2 = NULL;
|
||||
char *msg3 = NULL;
|
||||
int no_empty = !!(flags & CHECK_CONSTRAINTS_NOT_EMPTY);
|
||||
|
||||
if (ctrl && ctrl->pinentry_mode == PINENTRY_MODE_LOOPBACK)
|
||||
return 0;
|
||||
@ -247,8 +263,9 @@ check_passphrase_constraints (ctrl_t ctrl, const char *pw, int no_empty,
|
||||
and pattern. The actual test is done by an external program.
|
||||
The warning message is generic to give the user no hint on how to
|
||||
circumvent this list. */
|
||||
if (*pw && opt.check_passphrase_pattern &&
|
||||
check_passphrase_pattern (ctrl, pw))
|
||||
if (*pw
|
||||
&& (opt.check_passphrase_pattern || opt.check_sym_passphrase_pattern)
|
||||
&& do_check_passphrase_pattern (ctrl, pw, flags))
|
||||
{
|
||||
if (!failed_constraint)
|
||||
{
|
||||
|
@ -113,6 +113,7 @@ enum cmd_and_opt_values
|
||||
oMinPassphraseLen,
|
||||
oMinPassphraseNonalpha,
|
||||
oCheckPassphrasePattern,
|
||||
oCheckSymPassphrasePattern,
|
||||
oMaxPassphraseDays,
|
||||
oEnablePassphraseHistory,
|
||||
oDisableExtendedKeyFormat,
|
||||
@ -265,6 +266,8 @@ static gpgrt_opt_t opts[] = {
|
||||
" characters for a new passphrase")),
|
||||
ARGPARSE_s_s (oCheckPassphrasePattern, "check-passphrase-pattern",
|
||||
N_("|FILE|check new passphrases against pattern in FILE")),
|
||||
ARGPARSE_s_s (oCheckSymPassphrasePattern, "check-sym-passphrase-pattern",
|
||||
"@"),
|
||||
ARGPARSE_s_u (oMaxPassphraseDays, "max-passphrase-days",
|
||||
N_("|N|expire the passphrase after N days")),
|
||||
ARGPARSE_s_n (oEnablePassphraseHistory, "enable-passphrase-history",
|
||||
@ -862,6 +865,7 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
||||
opt.min_passphrase_len = MIN_PASSPHRASE_LEN;
|
||||
opt.min_passphrase_nonalpha = MIN_PASSPHRASE_NONALPHA;
|
||||
opt.check_passphrase_pattern = NULL;
|
||||
opt.check_sym_passphrase_pattern = NULL;
|
||||
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
|
||||
opt.enable_passphrase_history = 0;
|
||||
opt.enable_extended_key_format = 1;
|
||||
@ -942,6 +946,9 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
|
||||
case oCheckPassphrasePattern:
|
||||
opt.check_passphrase_pattern = pargs->r.ret_str;
|
||||
break;
|
||||
case oCheckSymPassphrasePattern:
|
||||
opt.check_sym_passphrase_pattern = pargs->r.ret_str;
|
||||
break;
|
||||
case oMaxPassphraseDays:
|
||||
opt.max_passphrase_days = pargs->r.ret_ulong;
|
||||
break;
|
||||
@ -1440,6 +1447,8 @@ main (int argc, char **argv)
|
||||
GC_OPT_FLAG_DEFAULT, MIN_PASSPHRASE_NONALPHA);
|
||||
es_printf ("check-passphrase-pattern:%lu:\n",
|
||||
GC_OPT_FLAG_DEFAULT);
|
||||
es_printf ("check-sym-passphrase-pattern:%lu:\n",
|
||||
GC_OPT_FLAG_DEFAULT);
|
||||
es_printf ("max-passphrase-days:%lu:%d:\n",
|
||||
GC_OPT_FLAG_DEFAULT, MAX_PASSPHRASE_DAYS);
|
||||
es_printf ("ssh-fingerprint-digest:%lu:\"%s:\n",
|
||||
|
@ -205,14 +205,14 @@ if used in an options file.
|
||||
|
||||
|
||||
@item -v
|
||||
@item --verbose
|
||||
@itemx --verbose
|
||||
@opindex verbose
|
||||
Outputs additional information while running.
|
||||
You can increase the verbosity by giving several
|
||||
verbose commands to @command{gpg-agent}, such as @samp{-vv}.
|
||||
|
||||
@item -q
|
||||
@item --quiet
|
||||
@itemx --quiet
|
||||
@opindex quiet
|
||||
Try to be as quiet as possible.
|
||||
|
||||
@ -429,11 +429,15 @@ of digits or special characters a warning will be displayed. Defaults
|
||||
to 1.
|
||||
|
||||
@item --check-passphrase-pattern @var{file}
|
||||
@itemx --check-sym-passphrase-pattern @var{file}
|
||||
@opindex check-passphrase-pattern
|
||||
@opindex check-sym-passphrase-pattern
|
||||
Check the passphrase against the pattern given in @var{file}. When
|
||||
entering a new passphrase matching one of these pattern a warning will
|
||||
be displayed. @var{file} should be an absolute filename. The default is
|
||||
not to use any pattern file.
|
||||
be displayed. @var{file} should be an absolute filename. The default
|
||||
is not to use any pattern file. The second version of this option is
|
||||
only used when creating a new symmetric key to allow the use of
|
||||
different patterns for such passphrases.
|
||||
|
||||
Security note: It is known that checking a passphrase against a list of
|
||||
pattern or even against a complete dictionary is not very effective to
|
||||
|
@ -351,6 +351,8 @@ static known_option_t known_options_gpg_agent[] =
|
||||
{ "min-passphrase-nonalpha", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT },
|
||||
{ "check-passphrase-pattern", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT,
|
||||
/**/ GC_ARG_TYPE_FILENAME },
|
||||
{ "check-sym-passphrase-pattern", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT,
|
||||
/**/ GC_ARG_TYPE_FILENAME },
|
||||
{ "max-passphrase-days", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT },
|
||||
{ "enable-passphrase-history", GC_OPT_FLAG_RUNTIME, GC_LEVEL_EXPERT },
|
||||
{ "pinentry-timeout", GC_OPT_FLAG_RUNTIME, GC_LEVEL_ADVANCED },
|
||||
|
Loading…
x
Reference in New Issue
Block a user