mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Add more passphrase policy rules.
(--max-passphrase-days).
This commit is contained in:
parent
15d0cb42a1
commit
f268889b8f
5
NEWS
5
NEWS
@ -7,8 +7,9 @@ Noteworthy changes in version 2.0.7
|
|||||||
* Made it work on Windows Vista. Note that the entire Windows port
|
* Made it work on Windows Vista. Note that the entire Windows port
|
||||||
is still considered Beta.
|
is still considered Beta.
|
||||||
|
|
||||||
* Add new options min-passphrase-nonalpha, check-passphrase-pattern
|
* Add new options min-passphrase-nonalpha, check-passphrase-pattern,
|
||||||
and enforce-passphrase-constraints to gpg-agent.
|
enforce-passphrase-constraints and max-passphrase-days to
|
||||||
|
gpg-agent.
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 2.0.6 (2007-08-16)
|
Noteworthy changes in version 2.0.6 (2007-08-16)
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
2007-08-28 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* gpg-agent.c (main): Add option --faked-system-time.
|
||||||
|
|
||||||
|
* protect-tool.c (read_and_unprotect): Print the protected-at date.
|
||||||
|
|
||||||
|
* agent.h (struct server_control_s): Add member IN_PASSWD.
|
||||||
|
* command.c (cmd_passwd): Set it.
|
||||||
|
* findkey.c (try_unprotect_cb): Use it.
|
||||||
|
|
||||||
|
* protect.c (do_encryption): Replace asprintf by xtryasprint.
|
||||||
|
(agent_protect): Create the protected-at item.
|
||||||
|
(agent_unprotect): Add optional arg PROTECTED_AT.
|
||||||
|
(merge_lists): Add args CUTOFF and CUTLEN.
|
||||||
|
(agent_unprotect): Use them.
|
||||||
|
* findkey.c (try_unprotect_cb): Add code to test for expired keys.
|
||||||
|
(unprotect): Allow changing the passphrase.
|
||||||
|
|
||||||
2007-08-27 Werner Koch <wk@g10code.com>
|
2007-08-27 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* gpg-agent.c: Add options --min-passphrase-nonalpha,
|
* gpg-agent.c: Add options --min-passphrase-nonalpha,
|
||||||
|
@ -88,7 +88,12 @@ struct
|
|||||||
unsigned int min_passphrase_nonalpha;
|
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. */
|
||||||
const char *check_passphrase_pattern;
|
const char *check_passphrase_pattern;
|
||||||
|
/* If not 0 the user is asked to change his passphrase after these
|
||||||
|
number of days. */
|
||||||
|
unsigned int max_passphrase_days;
|
||||||
|
/* If set, a passphrase history will be written and checked at each
|
||||||
|
passphrase change. */
|
||||||
|
int enable_passhrase_history;
|
||||||
|
|
||||||
int running_detached; /* We are running detached from the tty. */
|
int running_detached; /* We are running detached from the tty. */
|
||||||
|
|
||||||
@ -153,6 +158,8 @@ struct server_control_s
|
|||||||
|
|
||||||
int use_auth_call; /* Hack to send the PKAUTH command instead of the
|
int use_auth_call; /* Hack to send the PKAUTH command instead of the
|
||||||
PKSIGN command to the scdaemon. */
|
PKSIGN command to the scdaemon. */
|
||||||
|
int in_passwd; /* Hack to inhibit enforced passphrase change
|
||||||
|
during an explicit passwd command. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -182,7 +189,7 @@ enum
|
|||||||
/* Values for the cache_mode arguments. */
|
/* Values for the cache_mode arguments. */
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
CACHE_MODE_IGNORE = 0, /* Special mode to by pass the cache. */
|
CACHE_MODE_IGNORE = 0, /* Special mode to bypass the cache. */
|
||||||
CACHE_MODE_ANY, /* Any mode except ignore matches. */
|
CACHE_MODE_ANY, /* Any mode except ignore matches. */
|
||||||
CACHE_MODE_NORMAL, /* Normal cache (gpg-agent). */
|
CACHE_MODE_NORMAL, /* Normal cache (gpg-agent). */
|
||||||
CACHE_MODE_USER, /* GET_PASSPHRASE related cache. */
|
CACHE_MODE_USER, /* GET_PASSPHRASE related cache. */
|
||||||
@ -271,6 +278,7 @@ int agent_protect_and_store (ctrl_t ctrl, gcry_sexp_t s_skey);
|
|||||||
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
int agent_protect (const unsigned char *plainkey, const char *passphrase,
|
||||||
unsigned char **result, size_t *resultlen);
|
unsigned char **result, size_t *resultlen);
|
||||||
int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
int agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
||||||
|
gnupg_isotime_t protected_at,
|
||||||
unsigned char **result, size_t *resultlen);
|
unsigned char **result, size_t *resultlen);
|
||||||
int agent_private_key_type (const unsigned char *privatekey);
|
int agent_private_key_type (const unsigned char *privatekey);
|
||||||
unsigned char *make_shadow_info (const char *serialno, const char *idstring);
|
unsigned char *make_shadow_info (const char *serialno, const char *idstring);
|
||||||
|
@ -1039,6 +1039,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
|
|||||||
if (rc)
|
if (rc)
|
||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
|
ctrl->in_passwd++;
|
||||||
rc = agent_key_from_file (ctrl, ctrl->server_local->keydesc,
|
rc = agent_key_from_file (ctrl, ctrl->server_local->keydesc,
|
||||||
grip, &shadow_info, CACHE_MODE_IGNORE, &s_skey);
|
grip, &shadow_info, CACHE_MODE_IGNORE, &s_skey);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -1050,6 +1051,7 @@ cmd_passwd (assuan_context_t ctx, char *line)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
rc = agent_protect_and_store (ctrl, s_skey);
|
rc = agent_protect_and_store (ctrl, s_skey);
|
||||||
|
ctrl->in_passwd--;
|
||||||
|
|
||||||
xfree (ctrl->server_local->keydesc);
|
xfree (ctrl->server_local->keydesc);
|
||||||
ctrl->server_local->keydesc = NULL;
|
ctrl->server_local->keydesc = NULL;
|
||||||
|
111
agent/findkey.c
111
agent/findkey.c
@ -1,5 +1,6 @@
|
|||||||
/* findkey.c - locate the secret key
|
/* findkey.c - Locate the secret key
|
||||||
* Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
|
* Copyright (C) 2001, 2002, 2003, 2004, 2005,
|
||||||
|
* 2007 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -31,15 +32,20 @@
|
|||||||
#include <pth.h> /* (we use pth_sleep) */
|
#include <pth.h> /* (we use pth_sleep) */
|
||||||
|
|
||||||
#include "agent.h"
|
#include "agent.h"
|
||||||
|
#include "i18n.h"
|
||||||
|
|
||||||
#ifndef O_BINARY
|
#ifndef O_BINARY
|
||||||
#define O_BINARY 0
|
#define O_BINARY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Helper to pass data to the check callback of the unprotect function. */
|
/* Helper to pass data to the check callback of the unprotect function. */
|
||||||
struct try_unprotect_arg_s {
|
struct try_unprotect_arg_s
|
||||||
|
{
|
||||||
|
ctrl_t ctrl;
|
||||||
const unsigned char *protected_key;
|
const unsigned char *protected_key;
|
||||||
unsigned char *unprotected_key;
|
unsigned char *unprotected_key;
|
||||||
|
int change_required; /* Set by the callback to indicate that the
|
||||||
|
user should chnage the passphrase. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -132,10 +138,71 @@ try_unprotect_cb (struct pin_entry_info_s *pi)
|
|||||||
{
|
{
|
||||||
struct try_unprotect_arg_s *arg = pi->check_cb_arg;
|
struct try_unprotect_arg_s *arg = pi->check_cb_arg;
|
||||||
size_t dummy;
|
size_t dummy;
|
||||||
|
gpg_error_t err;
|
||||||
|
gnupg_isotime_t now, protected_at, tmptime;
|
||||||
|
char *desc = NULL;
|
||||||
|
|
||||||
assert (!arg->unprotected_key);
|
assert (!arg->unprotected_key);
|
||||||
return agent_unprotect (arg->protected_key, pi->pin,
|
|
||||||
|
arg->change_required = 0;
|
||||||
|
err = agent_unprotect (arg->protected_key, pi->pin, protected_at,
|
||||||
&arg->unprotected_key, &dummy);
|
&arg->unprotected_key, &dummy);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (!opt.max_passphrase_days || arg->ctrl->in_passwd)
|
||||||
|
return 0; /* No regular passphrase change required. */
|
||||||
|
|
||||||
|
if (!*protected_at)
|
||||||
|
{
|
||||||
|
/* No protection date known - must force passphrase change. */
|
||||||
|
desc = xtrystrdup (_("Note: This passphrase has never been changed.%0A"
|
||||||
|
"Please change it now."));
|
||||||
|
if (!desc)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gnupg_get_isotime (now);
|
||||||
|
gnupg_copy_time (tmptime, protected_at);
|
||||||
|
err = add_days_to_isotime (tmptime, opt.max_passphrase_days);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
if (strcmp (now, tmptime) > 0 )
|
||||||
|
{
|
||||||
|
/* Passphrase "expired". */
|
||||||
|
desc = xtryasprintf
|
||||||
|
(_("This passphrase has not been changed%%0A"
|
||||||
|
"since %.4s-%.2s-%.2s. Please change it now."),
|
||||||
|
protected_at, protected_at+4, protected_at+6);
|
||||||
|
if (!desc)
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (desc)
|
||||||
|
{
|
||||||
|
/* Change required. */
|
||||||
|
if (opt.enforce_passphrase_constraints)
|
||||||
|
{
|
||||||
|
err = agent_get_confirmation (arg->ctrl, desc,
|
||||||
|
_("Change passphrase"), NULL);
|
||||||
|
if (!err)
|
||||||
|
arg->change_required = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
err = agent_get_confirmation (arg->ctrl, desc,
|
||||||
|
_("Change passphrase"),
|
||||||
|
_("I'll change it later"));
|
||||||
|
if (!err)
|
||||||
|
arg->change_required = 1;
|
||||||
|
else if (gpg_err_code (err) == GPG_ERR_CANCELED)
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
xfree (desc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -260,7 +327,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
|
pw = agent_get_cache (hexgrip, cache_mode, &cache_marker);
|
||||||
if (pw)
|
if (pw)
|
||||||
{
|
{
|
||||||
rc = agent_unprotect (*keybuf, pw, &result, &resultlen);
|
rc = agent_unprotect (*keybuf, pw, NULL, &result, &resultlen);
|
||||||
agent_unlock_cache_entry (&cache_marker);
|
agent_unlock_cache_entry (&cache_marker);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
@ -272,7 +339,7 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If the pinentry is currently in use, we wait up to 60 seconds
|
/* If the pinentry is currently in use, we wait up to 60 seconds
|
||||||
for it close and check the cache again. This solves a common
|
for it to close and check the cache again. This solves a common
|
||||||
situation where several requests for unprotecting a key have
|
situation where several requests for unprotecting a key have
|
||||||
been made but the user is still entering the passphrase for
|
been made but the user is still entering the passphrase for
|
||||||
the first request. Because all requests to agent_askpin are
|
the first request. Because all requests to agent_askpin are
|
||||||
@ -303,14 +370,46 @@ unprotect (ctrl_t ctrl, const char *desc_text,
|
|||||||
pi->max_digits = 8;
|
pi->max_digits = 8;
|
||||||
pi->max_tries = 3;
|
pi->max_tries = 3;
|
||||||
pi->check_cb = try_unprotect_cb;
|
pi->check_cb = try_unprotect_cb;
|
||||||
|
arg.ctrl = ctrl;
|
||||||
arg.protected_key = *keybuf;
|
arg.protected_key = *keybuf;
|
||||||
arg.unprotected_key = NULL;
|
arg.unprotected_key = NULL;
|
||||||
|
arg.change_required = 0;
|
||||||
pi->check_cb_arg = &arg;
|
pi->check_cb_arg = &arg;
|
||||||
|
|
||||||
rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
|
rc = agent_askpin (ctrl, desc_text, NULL, NULL, pi);
|
||||||
if (!rc)
|
if (!rc)
|
||||||
{
|
{
|
||||||
assert (arg.unprotected_key);
|
assert (arg.unprotected_key);
|
||||||
|
if (arg.change_required)
|
||||||
|
{
|
||||||
|
size_t canlen, erroff;
|
||||||
|
gcry_sexp_t s_skey;
|
||||||
|
|
||||||
|
assert (arg.unprotected_key);
|
||||||
|
canlen = gcry_sexp_canon_len (arg.unprotected_key, 0, NULL, NULL);
|
||||||
|
rc = gcry_sexp_sscan (&s_skey, &erroff,
|
||||||
|
(char*)arg.unprotected_key, canlen);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("failed to build S-Exp (off=%u): %s\n",
|
||||||
|
(unsigned int)erroff, gpg_strerror (rc));
|
||||||
|
wipememory (arg.unprotected_key, canlen);
|
||||||
|
xfree (arg.unprotected_key);
|
||||||
|
xfree (pi);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
rc = agent_protect_and_store (ctrl, s_skey);
|
||||||
|
gcry_sexp_release (s_skey);
|
||||||
|
if (rc)
|
||||||
|
{
|
||||||
|
log_error ("changing the passphrase failed: %s\n",
|
||||||
|
gpg_strerror (rc));
|
||||||
|
wipememory (arg.unprotected_key, canlen);
|
||||||
|
xfree (arg.unprotected_key);
|
||||||
|
xfree (pi);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
agent_put_cache (hexgrip, cache_mode, pi->pin, 0);
|
agent_put_cache (hexgrip, cache_mode, pi->pin, 0);
|
||||||
xfree (*keybuf);
|
xfree (*keybuf);
|
||||||
*keybuf = arg.unprotected_key;
|
*keybuf = arg.unprotected_key;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
/* pksign.c - Generate a keypair
|
/* genkey.c - Generate a keypair
|
||||||
* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
|
* Copyright (C) 2002, 2003, 2004, 2007 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
|
@ -92,8 +92,11 @@ enum cmd_and_opt_values
|
|||||||
oMinPassphraseLen,
|
oMinPassphraseLen,
|
||||||
oMinPassphraseNonalpha,
|
oMinPassphraseNonalpha,
|
||||||
oCheckPassphrasePattern,
|
oCheckPassphrasePattern,
|
||||||
|
oMaxPassphraseDays,
|
||||||
|
oEnablePassphraseHistory,
|
||||||
oUseStandardSocket,
|
oUseStandardSocket,
|
||||||
oNoUseStandardSocket,
|
oNoUseStandardSocket,
|
||||||
|
oFakedSystemTime,
|
||||||
|
|
||||||
oIgnoreCacheForSigning,
|
oIgnoreCacheForSigning,
|
||||||
oAllowMarkTrusted,
|
oAllowMarkTrusted,
|
||||||
@ -137,6 +140,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
{ oScdaemonProgram, "scdaemon-program", 2 ,
|
{ oScdaemonProgram, "scdaemon-program", 2 ,
|
||||||
N_("|PGM|use PGM as the SCdaemon program") },
|
N_("|PGM|use PGM as the SCdaemon program") },
|
||||||
{ oDisableScdaemon, "disable-scdaemon", 0, N_("do not use the SCdaemon") },
|
{ oDisableScdaemon, "disable-scdaemon", 0, N_("do not use the SCdaemon") },
|
||||||
|
{ oFakedSystemTime, "faked-system-time", 2, "@" }, /* (epoch time) */
|
||||||
|
|
||||||
{ oDisplay, "display", 2, "@" },
|
{ oDisplay, "display", 2, "@" },
|
||||||
{ oTTYname, "ttyname", 2, "@" },
|
{ oTTYname, "ttyname", 2, "@" },
|
||||||
@ -157,6 +161,8 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
{ oMinPassphraseLen, "min-passphrase-len", 4, "@" },
|
{ oMinPassphraseLen, "min-passphrase-len", 4, "@" },
|
||||||
{ oMinPassphraseNonalpha, "min-passphrase-nonalpha", 4, "@" },
|
{ oMinPassphraseNonalpha, "min-passphrase-nonalpha", 4, "@" },
|
||||||
{ oCheckPassphrasePattern, "check-passphrase-pattern", 2, "@" },
|
{ oCheckPassphrasePattern, "check-passphrase-pattern", 2, "@" },
|
||||||
|
{ oMaxPassphraseDays, "max-passphrase-days", 4, "@" },
|
||||||
|
{ oEnablePassphraseHistory, "enable-passphrase-history", 0, "@" },
|
||||||
|
|
||||||
{ oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
|
{ oIgnoreCacheForSigning, "ignore-cache-for-signing", 0,
|
||||||
N_("do not use the PIN cache when signing")},
|
N_("do not use the PIN cache when signing")},
|
||||||
@ -177,6 +183,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
#define MAX_CACHE_TTL_SSH (120*60) /* 2 hours */
|
#define MAX_CACHE_TTL_SSH (120*60) /* 2 hours */
|
||||||
#define MIN_PASSPHRASE_LEN (8)
|
#define MIN_PASSPHRASE_LEN (8)
|
||||||
#define MIN_PASSPHRASE_NONALPHA (1)
|
#define MIN_PASSPHRASE_NONALPHA (1)
|
||||||
|
#define MAX_PASSPHRASE_DAYS (0)
|
||||||
|
|
||||||
/* The timer tick used for housekeeping stuff. For Windows we use a
|
/* The timer tick used for housekeeping stuff. For Windows we use a
|
||||||
longer period as the SetWaitableTimer seems to signal earlier than
|
longer period as the SetWaitableTimer seems to signal earlier than
|
||||||
@ -375,6 +382,8 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
|||||||
opt.min_passphrase_len = MIN_PASSPHRASE_LEN;
|
opt.min_passphrase_len = MIN_PASSPHRASE_LEN;
|
||||||
opt.min_passphrase_nonalpha = MIN_PASSPHRASE_NONALPHA;
|
opt.min_passphrase_nonalpha = MIN_PASSPHRASE_NONALPHA;
|
||||||
opt.check_passphrase_pattern = NULL;
|
opt.check_passphrase_pattern = NULL;
|
||||||
|
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
|
||||||
|
opt.enable_passhrase_history = 0;
|
||||||
opt.ignore_cache_for_signing = 0;
|
opt.ignore_cache_for_signing = 0;
|
||||||
opt.allow_mark_trusted = 0;
|
opt.allow_mark_trusted = 0;
|
||||||
opt.disable_scdaemon = 0;
|
opt.disable_scdaemon = 0;
|
||||||
@ -424,6 +433,12 @@ parse_rereadable_options (ARGPARSE_ARGS *pargs, int reread)
|
|||||||
case oCheckPassphrasePattern:
|
case oCheckPassphrasePattern:
|
||||||
opt.check_passphrase_pattern = pargs->r.ret_str;
|
opt.check_passphrase_pattern = pargs->r.ret_str;
|
||||||
break;
|
break;
|
||||||
|
case oMaxPassphraseDays:
|
||||||
|
opt.max_passphrase_days = pargs->r.ret_ulong;
|
||||||
|
break;
|
||||||
|
case oEnablePassphraseHistory:
|
||||||
|
opt.enable_passhrase_history = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
|
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
|
||||||
|
|
||||||
@ -646,6 +661,15 @@ main (int argc, char **argv )
|
|||||||
case oUseStandardSocket: standard_socket = 1; break;
|
case oUseStandardSocket: standard_socket = 1; break;
|
||||||
case oNoUseStandardSocket: standard_socket = 0; break;
|
case oNoUseStandardSocket: standard_socket = 0; break;
|
||||||
|
|
||||||
|
case oFakedSystemTime:
|
||||||
|
{
|
||||||
|
time_t faked_time = isotime2epoch (pargs.r.ret_str);
|
||||||
|
if (faked_time == (time_t)(-1))
|
||||||
|
faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
|
||||||
|
gnupg_set_time (faked_time, 0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case oKeepTTY: opt.keep_tty = 1; break;
|
case oKeepTTY: opt.keep_tty = 1; break;
|
||||||
case oKeepDISPLAY: opt.keep_display = 1; break;
|
case oKeepDISPLAY: opt.keep_display = 1; break;
|
||||||
|
|
||||||
@ -753,6 +777,11 @@ main (int argc, char **argv )
|
|||||||
MIN_PASSPHRASE_NONALPHA);
|
MIN_PASSPHRASE_NONALPHA);
|
||||||
printf ("check-passphrase-pattern:%lu:\n",
|
printf ("check-passphrase-pattern:%lu:\n",
|
||||||
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
|
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME);
|
||||||
|
printf ("max-passphrase-days:%lu:%d:\n",
|
||||||
|
GC_OPT_FLAG_DEFAULT|GC_OPT_FLAG_RUNTIME,
|
||||||
|
MAX_PASSPHRASE_DAYS);
|
||||||
|
printf ("enable-passphrase-history:%lu:\n",
|
||||||
|
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||||
printf ("no-grab:%lu:\n",
|
printf ("no-grab:%lu:\n",
|
||||||
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||||
printf ("ignore-cache-for-signing:%lu:\n",
|
printf ("ignore-cache-for-signing:%lu:\n",
|
||||||
|
@ -69,6 +69,7 @@ A protected key is like this:
|
|||||||
(n #00e0ce9..[some bytes not shown]..51#)
|
(n #00e0ce9..[some bytes not shown]..51#)
|
||||||
(e #010001#)
|
(e #010001#)
|
||||||
(protected mode (parms) encrypted_octet_string)
|
(protected mode (parms) encrypted_octet_string)
|
||||||
|
(protected-at <isotimestamp>)
|
||||||
)
|
)
|
||||||
(uri http://foo.bar x-foo:whatever_you_want)
|
(uri http://foo.bar x-foo:whatever_you_want)
|
||||||
(comment whatever)
|
(comment whatever)
|
||||||
@ -79,7 +80,8 @@ In this scheme the encrypted_octet_string is encrypted according to
|
|||||||
the algorithm described after the keyword protected; most protection
|
the algorithm described after the keyword protected; most protection
|
||||||
algorithms need some parameters, which are given in a list before the
|
algorithms need some parameters, which are given in a list before the
|
||||||
encrypted_octet_string. The result of the decryption process is a
|
encrypted_octet_string. The result of the decryption process is a
|
||||||
list of the secret key parameters.
|
list of the secret key parameters. The protected-at expression is
|
||||||
|
optional; the isotimestamp is 15 bytes long (e.g. "19610711T172000").
|
||||||
|
|
||||||
The only available protection mode for now is
|
The only available protection mode for now is
|
||||||
|
|
||||||
@ -115,7 +117,8 @@ easily be stripped by looking for the end of the list.
|
|||||||
The hash is calculated on the concatenation of the public key and
|
The hash is calculated on the concatenation of the public key and
|
||||||
secret key parameter lists: i.e it is required to hash the
|
secret key parameter lists: i.e it is required to hash the
|
||||||
concatenation of these 6 canonical encoded lists for RSA, including
|
concatenation of these 6 canonical encoded lists for RSA, including
|
||||||
the parenthesis and the algorithm keyword.
|
the parenthesis, the algorithm keyword and (if used) the protected-at
|
||||||
|
list.
|
||||||
|
|
||||||
(rsa
|
(rsa
|
||||||
(n #00e0ce9..[some bytes not shown]..51#)
|
(n #00e0ce9..[some bytes not shown]..51#)
|
||||||
@ -124,6 +127,7 @@ the parenthesis and the algorithm keyword.
|
|||||||
(p #00e861b..[some bytes not shown]..f1#)
|
(p #00e861b..[some bytes not shown]..f1#)
|
||||||
(q #00f7a7c..[some bytes not shown]..61#)
|
(q #00f7a7c..[some bytes not shown]..61#)
|
||||||
(u #304559a..[some bytes not shown]..9b#)
|
(u #304559a..[some bytes not shown]..9b#)
|
||||||
|
(protected-at "18950523T000000")
|
||||||
)
|
)
|
||||||
|
|
||||||
After decryption the hash must be recalculated and compared against
|
After decryption the hash must be recalculated and compared against
|
||||||
|
@ -366,12 +366,14 @@ read_and_unprotect (const char *fname)
|
|||||||
unsigned char *result;
|
unsigned char *result;
|
||||||
size_t resultlen;
|
size_t resultlen;
|
||||||
char *pw;
|
char *pw;
|
||||||
|
gnupg_isotime_t protected_at;
|
||||||
|
|
||||||
key = read_key (fname);
|
key = read_key (fname);
|
||||||
if (!key)
|
if (!key)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
rc = agent_unprotect (key, (pw=get_passphrase (1, 0)), &result, &resultlen);
|
rc = agent_unprotect (key, (pw=get_passphrase (1, 0)),
|
||||||
|
protected_at, &result, &resultlen);
|
||||||
release_passphrase (pw);
|
release_passphrase (pw);
|
||||||
xfree (key);
|
xfree (key);
|
||||||
if (rc)
|
if (rc)
|
||||||
@ -381,6 +383,11 @@ read_and_unprotect (const char *fname)
|
|||||||
log_error ("unprotecting the key failed: %s\n", gpg_strerror (rc));
|
log_error ("unprotecting the key failed: %s\n", gpg_strerror (rc));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (opt.verbose)
|
||||||
|
log_info ("key protection done at %.4s-%.2s-%.2s %.2s:%.2s:%s\n",
|
||||||
|
protected_at, protected_at+4, protected_at+6,
|
||||||
|
protected_at+9, protected_at+11, protected_at+13);
|
||||||
|
|
||||||
|
|
||||||
if (opt_armor)
|
if (opt_armor)
|
||||||
{
|
{
|
||||||
@ -883,7 +890,8 @@ export_p12_file (const char *fname)
|
|||||||
unsigned char *tmpkey;
|
unsigned char *tmpkey;
|
||||||
size_t tmplen;
|
size_t tmplen;
|
||||||
|
|
||||||
rc = agent_unprotect (key, (pw=get_passphrase (1, 0)), &tmpkey, &tmplen);
|
rc = agent_unprotect (key, (pw=get_passphrase (1, 0)),
|
||||||
|
NULL, &tmpkey, &tmplen);
|
||||||
release_passphrase (pw);
|
release_passphrase (pw);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
|
133
agent/protect.c
133
agent/protect.c
@ -163,7 +163,7 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
|
|||||||
((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
|
((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
|
||||||
|
|
||||||
We always append a full block of random bytes as padding but
|
We always append a full block of random bytes as padding but
|
||||||
encrypt only what is needed for a full blocksize */
|
encrypt only what is needed for a full blocksize. */
|
||||||
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
|
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
|
||||||
outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
|
outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
|
||||||
enclen = outlen/blklen * blklen;
|
enclen = outlen/blklen * blklen;
|
||||||
@ -229,21 +229,13 @@ do_encryption (const unsigned char *protbegin, size_t protlen,
|
|||||||
encrypted_octet_string)
|
encrypted_octet_string)
|
||||||
|
|
||||||
in canoncical format of course. We use asprintf and %n modifier
|
in canoncical format of course. We use asprintf and %n modifier
|
||||||
and spaces as palceholders. */
|
and dummy values as placeholders. */
|
||||||
asprintf (&p,
|
p = xtryasprintf
|
||||||
"(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
|
("(9:protected%d:%s((4:sha18:%n_8bytes_2:96)%d:%n%*s)%d:%n%*s)",
|
||||||
(int)strlen (modestr), modestr,
|
(int)strlen (modestr), modestr,
|
||||||
&saltpos,
|
&saltpos,
|
||||||
blklen, &ivpos, blklen, "",
|
blklen, &ivpos, blklen, "",
|
||||||
enclen, &encpos, enclen, "");
|
enclen, &encpos, enclen, "");
|
||||||
if (p)
|
|
||||||
{ /* asprintf does not use our malloc system */
|
|
||||||
char *psave = p;
|
|
||||||
p = xtrymalloc (strlen (psave)+1);
|
|
||||||
if (p)
|
|
||||||
strcpy (p, psave);
|
|
||||||
free (psave);
|
|
||||||
}
|
|
||||||
if (!p)
|
if (!p)
|
||||||
{
|
{
|
||||||
gpg_error_t tmperr = out_of_core ();
|
gpg_error_t tmperr = out_of_core ();
|
||||||
@ -276,11 +268,19 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
|||||||
size_t n;
|
size_t n;
|
||||||
int c, infidx, i;
|
int c, infidx, i;
|
||||||
unsigned char hashvalue[20];
|
unsigned char hashvalue[20];
|
||||||
|
char timestamp_exp[35];
|
||||||
unsigned char *protected;
|
unsigned char *protected;
|
||||||
size_t protectedlen;
|
size_t protectedlen;
|
||||||
int depth = 0;
|
int depth = 0;
|
||||||
unsigned char *p;
|
unsigned char *p;
|
||||||
|
gcry_md_hd_t md;
|
||||||
|
|
||||||
|
/* Create an S-expression with the procted-at timestamp. */
|
||||||
|
memcpy (timestamp_exp, "(12:protected-at15:", 19);
|
||||||
|
gnupg_get_isotime (timestamp_exp+19);
|
||||||
|
timestamp_exp[19+15] = ')';
|
||||||
|
|
||||||
|
/* Parse original key. */
|
||||||
s = plainkey;
|
s = plainkey;
|
||||||
if (*s != '(')
|
if (*s != '(')
|
||||||
return gpg_error (GPG_ERR_INV_SEXP);
|
return gpg_error (GPG_ERR_INV_SEXP);
|
||||||
@ -345,8 +345,18 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
|||||||
assert (!depth);
|
assert (!depth);
|
||||||
real_end = s-1;
|
real_end = s-1;
|
||||||
|
|
||||||
gcry_md_hash_buffer (GCRY_MD_SHA1, hashvalue,
|
|
||||||
hash_begin, hash_end - hash_begin + 1);
|
/* Hash the stuff. Because the timestamp_exp won't get protected,
|
||||||
|
we can't simply hash a continuous buffer but need to use several
|
||||||
|
md_writes. */
|
||||||
|
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
gcry_md_write (md, hash_begin, hash_end - hash_begin);
|
||||||
|
gcry_md_write (md, timestamp_exp, 35);
|
||||||
|
gcry_md_write (md, ")", 1);
|
||||||
|
memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
|
||||||
|
gcry_md_close (md);
|
||||||
|
|
||||||
rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
|
rc = do_encryption (prot_begin, prot_end - prot_begin + 1,
|
||||||
passphrase, hashvalue,
|
passphrase, hashvalue,
|
||||||
@ -356,10 +366,12 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
|||||||
|
|
||||||
/* Now create the protected version of the key. Note that the 10
|
/* Now create the protected version of the key. Note that the 10
|
||||||
extra bytes are for for the inserted "protected-" string (the
|
extra bytes are for for the inserted "protected-" string (the
|
||||||
beginning of the plaintext reads: "((11:private-key(" ). */
|
beginning of the plaintext reads: "((11:private-key(" ). The 35
|
||||||
|
term is the space for (12:protected-at15:<timestamp>). */
|
||||||
*resultlen = (10
|
*resultlen = (10
|
||||||
+ (prot_begin-plainkey)
|
+ (prot_begin-plainkey)
|
||||||
+ protectedlen
|
+ protectedlen
|
||||||
|
+ 35
|
||||||
+ (real_end-prot_end));
|
+ (real_end-prot_end));
|
||||||
*result = p = xtrymalloc (*resultlen);
|
*result = p = xtrymalloc (*resultlen);
|
||||||
if (!p)
|
if (!p)
|
||||||
@ -374,10 +386,15 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
|
|||||||
p += prot_begin - plainkey - 4;
|
p += prot_begin - plainkey - 4;
|
||||||
memcpy (p, protected, protectedlen);
|
memcpy (p, protected, protectedlen);
|
||||||
p += protectedlen;
|
p += protectedlen;
|
||||||
|
|
||||||
|
memcpy (p, timestamp_exp, 35);
|
||||||
|
p += 35;
|
||||||
|
|
||||||
memcpy (p, prot_end+1, real_end - prot_end);
|
memcpy (p, prot_end+1, real_end - prot_end);
|
||||||
p += real_end - prot_end;
|
p += real_end - prot_end;
|
||||||
assert ( p - *result == *resultlen);
|
assert ( p - *result == *resultlen);
|
||||||
xfree (protected);
|
xfree (protected);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -457,13 +474,16 @@ do_decryption (const unsigned char *protected, size_t protectedlen,
|
|||||||
/* Merge the parameter list contained in CLEARTEXT with the original
|
/* Merge the parameter list contained in CLEARTEXT with the original
|
||||||
protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
|
protect lists PROTECTEDKEY by replacing the list at REPLACEPOS.
|
||||||
Return the new list in RESULT and the MIC value in the 20 byte
|
Return the new list in RESULT and the MIC value in the 20 byte
|
||||||
buffer SHA1HASH. */
|
buffer SHA1HASH. CUTOFF and CUTLEN will receive the offset and the
|
||||||
|
length of the resulting list which should go into the MIC
|
||||||
|
calculation but then be removed. */
|
||||||
static int
|
static int
|
||||||
merge_lists (const unsigned char *protectedkey,
|
merge_lists (const unsigned char *protectedkey,
|
||||||
size_t replacepos,
|
size_t replacepos,
|
||||||
const unsigned char *cleartext,
|
const unsigned char *cleartext,
|
||||||
unsigned char *sha1hash,
|
unsigned char *sha1hash,
|
||||||
unsigned char **result, size_t *resultlen)
|
unsigned char **result, size_t *resultlen,
|
||||||
|
size_t *cutoff, size_t *cutlen)
|
||||||
{
|
{
|
||||||
size_t n, newlistlen;
|
size_t n, newlistlen;
|
||||||
unsigned char *newlist, *p;
|
unsigned char *newlist, *p;
|
||||||
@ -473,6 +493,8 @@ merge_lists (const unsigned char *protectedkey,
|
|||||||
|
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
*resultlen = 0;
|
*resultlen = 0;
|
||||||
|
*cutoff = 0;
|
||||||
|
*cutlen = 0;
|
||||||
|
|
||||||
if (replacepos < 26)
|
if (replacepos < 26)
|
||||||
return gpg_error (GPG_ERR_BUG);
|
return gpg_error (GPG_ERR_BUG);
|
||||||
@ -522,7 +544,7 @@ merge_lists (const unsigned char *protectedkey,
|
|||||||
goto invalid_sexp;
|
goto invalid_sexp;
|
||||||
endpos = s;
|
endpos = s;
|
||||||
s++;
|
s++;
|
||||||
/* short intermezzo: Get the MIC */
|
/* Intermezzo: Get the MIC */
|
||||||
if (*s != '(')
|
if (*s != '(')
|
||||||
goto invalid_sexp;
|
goto invalid_sexp;
|
||||||
s++;
|
s++;
|
||||||
@ -539,13 +561,13 @@ merge_lists (const unsigned char *protectedkey,
|
|||||||
s += n;
|
s += n;
|
||||||
if (*s != ')')
|
if (*s != ')')
|
||||||
goto invalid_sexp;
|
goto invalid_sexp;
|
||||||
/* end intermezzo */
|
/* End intermezzo */
|
||||||
|
|
||||||
/* append the parameter list */
|
/* append the parameter list */
|
||||||
memcpy (p, startpos, endpos - startpos);
|
memcpy (p, startpos, endpos - startpos);
|
||||||
p += endpos - startpos;
|
p += endpos - startpos;
|
||||||
|
|
||||||
/* skip overt the protected list element in the original list */
|
/* Skip over the protected list element in the original list. */
|
||||||
s = protectedkey + replacepos;
|
s = protectedkey + replacepos;
|
||||||
assert (*s == '(');
|
assert (*s == '(');
|
||||||
s++;
|
s++;
|
||||||
@ -553,6 +575,22 @@ merge_lists (const unsigned char *protectedkey,
|
|||||||
rc = sskip (&s, &i);
|
rc = sskip (&s, &i);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto failure;
|
goto failure;
|
||||||
|
/* Record the position of the optional protected-at expression. */
|
||||||
|
if (*s == '(')
|
||||||
|
{
|
||||||
|
const unsigned char *save_s = s;
|
||||||
|
s++;
|
||||||
|
n = snext (&s);
|
||||||
|
if (smatch (&s, n, "protected-at"))
|
||||||
|
{
|
||||||
|
i = 1;
|
||||||
|
rc = sskip (&s, &i);
|
||||||
|
if (rc)
|
||||||
|
goto failure;
|
||||||
|
*cutlen = s - save_s;
|
||||||
|
}
|
||||||
|
s = save_s;
|
||||||
|
}
|
||||||
startpos = s;
|
startpos = s;
|
||||||
i = 2; /* we are inside this level */
|
i = 2; /* we are inside this level */
|
||||||
rc = sskip (&s, &i);
|
rc = sskip (&s, &i);
|
||||||
@ -561,10 +599,13 @@ merge_lists (const unsigned char *protectedkey,
|
|||||||
assert (s[-1] == ')');
|
assert (s[-1] == ')');
|
||||||
endpos = s; /* one behind the end of the list */
|
endpos = s; /* one behind the end of the list */
|
||||||
|
|
||||||
/* append the rest */
|
/* Append the rest. */
|
||||||
|
if (*cutlen)
|
||||||
|
*cutoff = p - newlist;
|
||||||
memcpy (p, startpos, endpos - startpos);
|
memcpy (p, startpos, endpos - startpos);
|
||||||
p += endpos - startpos;
|
p += endpos - startpos;
|
||||||
|
|
||||||
|
|
||||||
/* ready */
|
/* ready */
|
||||||
*result = newlist;
|
*result = newlist;
|
||||||
*resultlen = newlistlen;
|
*resultlen = newlistlen;
|
||||||
@ -584,13 +625,16 @@ merge_lists (const unsigned char *protectedkey,
|
|||||||
|
|
||||||
|
|
||||||
/* Unprotect the key encoded in canonical format. We assume a valid
|
/* Unprotect the key encoded in canonical format. We assume a valid
|
||||||
S-Exp here. */
|
S-Exp here. If a protected-at item is available, its value will
|
||||||
|
be stored at protocted_at unless this is NULL. */
|
||||||
int
|
int
|
||||||
agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
||||||
|
gnupg_isotime_t protected_at,
|
||||||
unsigned char **result, size_t *resultlen)
|
unsigned char **result, size_t *resultlen)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const unsigned char *s;
|
const unsigned char *s;
|
||||||
|
const unsigned char *protect_list;
|
||||||
size_t n;
|
size_t n;
|
||||||
int infidx, i;
|
int infidx, i;
|
||||||
unsigned char sha1hash[20], sha1hash2[20];
|
unsigned char sha1hash[20], sha1hash2[20];
|
||||||
@ -601,6 +645,10 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
|||||||
unsigned char *cleartext;
|
unsigned char *cleartext;
|
||||||
unsigned char *final;
|
unsigned char *final;
|
||||||
size_t finallen;
|
size_t finallen;
|
||||||
|
size_t cutoff, cutlen;
|
||||||
|
|
||||||
|
if (protected_at)
|
||||||
|
*protected_at = 0;
|
||||||
|
|
||||||
s = protectedkey;
|
s = protectedkey;
|
||||||
if (*s != '(')
|
if (*s != '(')
|
||||||
@ -624,12 +672,44 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
|||||||
if (!protect_info[infidx].algo)
|
if (!protect_info[infidx].algo)
|
||||||
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
return gpg_error (GPG_ERR_UNSUPPORTED_ALGORITHM);
|
||||||
|
|
||||||
|
|
||||||
|
/* See wether we have a protected-at timestamp. */
|
||||||
|
protect_list = s; /* Save for later. */
|
||||||
|
if (protected_at)
|
||||||
|
{
|
||||||
|
while (*s == '(')
|
||||||
|
{
|
||||||
|
prot_begin = s;
|
||||||
|
s++;
|
||||||
|
n = snext (&s);
|
||||||
|
if (!n)
|
||||||
|
return gpg_error (GPG_ERR_INV_SEXP);
|
||||||
|
if (smatch (&s, n, "protected-at"))
|
||||||
|
{
|
||||||
|
n = snext (&s);
|
||||||
|
if (!n)
|
||||||
|
return gpg_error (GPG_ERR_INV_SEXP);
|
||||||
|
if (n != 15)
|
||||||
|
return gpg_error (GPG_ERR_UNKNOWN_SEXP);
|
||||||
|
memcpy (protected_at, s, 15);
|
||||||
|
protected_at[15] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
s += n;
|
||||||
|
i = 1;
|
||||||
|
rc = sskip (&s, &i);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Now find the list with the protected information. Here is an
|
/* Now find the list with the protected information. Here is an
|
||||||
example for such a list:
|
example for such a list:
|
||||||
(protected openpgp-s2k3-sha1-aes-cbc
|
(protected openpgp-s2k3-sha1-aes-cbc
|
||||||
((sha1 <salt> <count>) <Initialization_Vector>)
|
((sha1 <salt> <count>) <Initialization_Vector>)
|
||||||
<encrypted_data>)
|
<encrypted_data>)
|
||||||
*/
|
*/
|
||||||
|
s = protect_list;
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
if (*s != '(')
|
if (*s != '(')
|
||||||
@ -700,7 +780,7 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
|||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
rc = merge_lists (protectedkey, prot_begin-protectedkey, cleartext,
|
rc = merge_lists (protectedkey, prot_begin-protectedkey, cleartext,
|
||||||
sha1hash, &final, &finallen);
|
sha1hash, &final, &finallen, &cutoff, &cutlen);
|
||||||
/* Albeit cleartext has been allocated in secure memory and thus
|
/* Albeit cleartext has been allocated in secure memory and thus
|
||||||
xfree will wipe it out, we do an extra wipe just in case
|
xfree will wipe it out, we do an extra wipe just in case
|
||||||
somethings goes badly wrong. */
|
somethings goes badly wrong. */
|
||||||
@ -718,6 +798,13 @@ agent_unprotect (const unsigned char *protectedkey, const char *passphrase,
|
|||||||
xfree (final);
|
xfree (final);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
/* Now remove tha part which is included in the MIC but should not
|
||||||
|
go into the final thing. */
|
||||||
|
if (cutlen)
|
||||||
|
{
|
||||||
|
memmove (final+cutoff, final+cutoff+cutlen, finallen-cutoff-cutlen);
|
||||||
|
finallen -= cutlen;
|
||||||
|
}
|
||||||
|
|
||||||
*result = final;
|
*result = final;
|
||||||
*resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
|
*resultlen = gcry_sexp_canon_len (final, 0, NULL, NULL);
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
|
2007-08-28 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* gettime.c (check_isotime, add_isotime): New. Orginally written
|
||||||
|
for DirMngr by me.
|
||||||
|
(add_days_to_isotime): New.
|
||||||
|
(date2jd, jd2date, days_per_month, days_per_year): New. Taken from
|
||||||
|
my ancient (1988) code used in Wedit (time2.c).
|
||||||
|
|
||||||
2007-08-27 Werner Koch <wk@g10code.com>
|
2007-08-27 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* util.h (GNUPG_MODULE_NAME_CHECK_PATTERN): New.
|
* util.h (GNUPG_MODULE_NAME_CHECK_PATTERN): New.
|
||||||
|
205
common/gettime.c
205
common/gettime.c
@ -30,6 +30,10 @@
|
|||||||
static unsigned long timewarp;
|
static unsigned long timewarp;
|
||||||
static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
|
static enum { NORMAL = 0, FROZEN, FUTURE, PAST } timemode;
|
||||||
|
|
||||||
|
/* Correction used to map to real Julian days. */
|
||||||
|
#define JD_DIFF 1721060L
|
||||||
|
|
||||||
|
|
||||||
/* Wrapper for the time(3). We use this here so we can fake the time
|
/* Wrapper for the time(3). We use this here so we can fake the time
|
||||||
for tests */
|
for tests */
|
||||||
time_t
|
time_t
|
||||||
@ -363,14 +367,215 @@ asctimestamp( u32 stamp )
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
days_per_year (int y)
|
||||||
|
{
|
||||||
|
int s ;
|
||||||
|
|
||||||
|
s = !(y % 4);
|
||||||
|
if ( !(y % 100))
|
||||||
|
if ((y%400))
|
||||||
|
s = 0;
|
||||||
|
return s ? 366 : 365;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
days_per_month (int y, int m)
|
||||||
|
{
|
||||||
|
int s;
|
||||||
|
|
||||||
|
switch(m)
|
||||||
|
{
|
||||||
|
case 1: case 3: case 5: case 7: case 8: case 10: case 12:
|
||||||
|
return 31 ;
|
||||||
|
case 2:
|
||||||
|
s = !(y % 4);
|
||||||
|
if (!(y % 100))
|
||||||
|
if ((y % 400))
|
||||||
|
s = 0;
|
||||||
|
return s? 29 : 28 ;
|
||||||
|
case 4: case 6: case 9: case 11:
|
||||||
|
return 30;
|
||||||
|
}
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Convert YEAR, MONTH and DAY into the Julian date. We assume that
|
||||||
|
it is already noon; we dont; support dates before 1582-10-15. */
|
||||||
|
static unsigned long
|
||||||
|
date2jd (int year, int month, int day)
|
||||||
|
{
|
||||||
|
unsigned long jd;
|
||||||
|
|
||||||
|
jd = 365L * year + 31 * (month-1) + day + JD_DIFF;
|
||||||
|
if (month < 3)
|
||||||
|
year-- ;
|
||||||
|
else
|
||||||
|
jd -= (4 * month + 23) / 10;
|
||||||
|
|
||||||
|
jd += year / 4 - ((year / 100 + 1) *3) / 4;
|
||||||
|
|
||||||
|
return jd ;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Convert a Julian date back to YEAR, MONTH and DAY. Return day of
|
||||||
|
the year or 0 on error. This function uses some more or less
|
||||||
|
arbitrary limits, most important is that days before 1582 are not
|
||||||
|
supported. */
|
||||||
|
static int
|
||||||
|
jd2date (unsigned long jd, int *year, int *month, int *day)
|
||||||
|
{
|
||||||
|
int y, m, d;
|
||||||
|
long delta;
|
||||||
|
|
||||||
|
if (!jd)
|
||||||
|
return 0 ;
|
||||||
|
if (jd < 1721425 || jd > 2843085)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
y = (jd - JD_DIFF) / 366;
|
||||||
|
d = m = 1;
|
||||||
|
|
||||||
|
while ((delta = jd - date2jd (y, m, d)) > days_per_year (y))
|
||||||
|
y++;
|
||||||
|
|
||||||
|
m = (delta / 31) + 1;
|
||||||
|
while( (delta = jd - date2jd (y, m, d)) > days_per_month (y,m))
|
||||||
|
if (++m > 12)
|
||||||
|
{
|
||||||
|
m = 1;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
d = delta + 1 ;
|
||||||
|
if (d > days_per_month (y, m))
|
||||||
|
{
|
||||||
|
d = 1;
|
||||||
|
m++;
|
||||||
|
}
|
||||||
|
if (m > 12)
|
||||||
|
{
|
||||||
|
m = 1;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (year)
|
||||||
|
*year = y;
|
||||||
|
if (month)
|
||||||
|
*month = m;
|
||||||
|
if (day)
|
||||||
|
*day = d ;
|
||||||
|
|
||||||
|
return (jd - date2jd (y, 1, 1)) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Check that the 15 bytes in ATIME represent a valid ISO time. Note
|
||||||
|
that this function does not expect a string but a plain 15 byte
|
||||||
|
isotime buffer. */
|
||||||
|
gpg_error_t
|
||||||
|
check_isotime (const gnupg_isotime_t atime)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const char *s;
|
||||||
|
|
||||||
|
if (!*atime)
|
||||||
|
return gpg_error (GPG_ERR_NO_VALUE);
|
||||||
|
|
||||||
|
for (s=atime, i=0; i < 8; i++, s++)
|
||||||
|
if (!digitp (s))
|
||||||
|
return gpg_error (GPG_ERR_INV_TIME);
|
||||||
|
if (*s != 'T')
|
||||||
|
return gpg_error (GPG_ERR_INV_TIME);
|
||||||
|
for (s++, i=9; i < 15; i++, s++)
|
||||||
|
if (!digitp (s))
|
||||||
|
return gpg_error (GPG_ERR_INV_TIME);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Add SECONDS to ATIME. SECONDS may not be negative and is limited
|
||||||
|
to about the equivalent of 62 years which should be more then
|
||||||
|
enough for our purposes. */
|
||||||
|
gpg_error_t
|
||||||
|
add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int year, month, day, hour, minute, sec, ndays;
|
||||||
|
unsigned long jd;
|
||||||
|
|
||||||
|
err = check_isotime (atime);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (nseconds < 0 || nseconds >= (0x7fffffff - 61) )
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
year = atoi_4 (atime+0);
|
||||||
|
month = atoi_2 (atime+4);
|
||||||
|
day = atoi_2 (atime+6);
|
||||||
|
hour = atoi_2 (atime+9);
|
||||||
|
minute= atoi_2 (atime+11);
|
||||||
|
sec = atoi_2 (atime+13);
|
||||||
|
|
||||||
|
if (year <= 1582) /* The julian date functions don't support this. */
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
sec += nseconds;
|
||||||
|
minute += sec/60;
|
||||||
|
sec %= 60;
|
||||||
|
hour += minute/60;
|
||||||
|
minute %= 60;
|
||||||
|
ndays = hour/24;
|
||||||
|
hour %= 24;
|
||||||
|
|
||||||
|
jd = date2jd (year, month, day) + ndays;
|
||||||
|
jd2date (jd, &year, &month, &day);
|
||||||
|
|
||||||
|
if (year > 9999 || month > 12 || day > 31
|
||||||
|
|| year < 0 || month < 1 || day < 1)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
|
||||||
|
year, month, day, hour, minute, sec);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gpg_error_t
|
||||||
|
add_days_to_isotime (gnupg_isotime_t atime, int ndays)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
int year, month, day, hour, minute, sec;
|
||||||
|
unsigned long jd;
|
||||||
|
|
||||||
|
err = check_isotime (atime);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (ndays < 0 || ndays >= 9999*366 )
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
year = atoi_4 (atime+0);
|
||||||
|
month = atoi_2 (atime+4);
|
||||||
|
day = atoi_2 (atime+6);
|
||||||
|
hour = atoi_2 (atime+9);
|
||||||
|
minute= atoi_2 (atime+11);
|
||||||
|
sec = atoi_2 (atime+13);
|
||||||
|
|
||||||
|
if (year <= 1582) /* The julian date functions don't support this. */
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
jd = date2jd (year, month, day) + ndays;
|
||||||
|
jd2date (jd, &year, &month, &day);
|
||||||
|
|
||||||
|
if (year > 9999 || month > 12 || day > 31
|
||||||
|
|| year < 0 || month < 1 || day < 1)
|
||||||
|
return gpg_error (GPG_ERR_INV_VALUE);
|
||||||
|
|
||||||
|
snprintf (atime, 16, "%04d%02d%02dT%02d%02d%02d",
|
||||||
|
year, month, day, hour, minute, sec);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -110,7 +110,9 @@ const char *strtimevalue (u32 stamp);
|
|||||||
const char *strtimestamp (u32 stamp); /* GMT */
|
const char *strtimestamp (u32 stamp); /* GMT */
|
||||||
const char *isotimestamp (u32 stamp); /* GMT */
|
const char *isotimestamp (u32 stamp); /* GMT */
|
||||||
const char *asctimestamp (u32 stamp); /* localized */
|
const char *asctimestamp (u32 stamp); /* localized */
|
||||||
|
gpg_error_t add_seconds_to_isotime (gnupg_isotime_t atime, int nseconds);
|
||||||
|
gpg_error_t add_days_to_isotime (gnupg_isotime_t atime, int ndays);
|
||||||
|
gpg_error_t check_isotime (const gnupg_isotime_t atime);
|
||||||
|
|
||||||
/* Copy one ISO date to another, this is inline so that we can do a
|
/* Copy one ISO date to another, this is inline so that we can do a
|
||||||
sanity check. */
|
sanity check. */
|
||||||
|
@ -365,6 +365,15 @@ a policy. A better policy is to educate users on good security
|
|||||||
behavior and optional to run a passphrase cracker regularly on all
|
behavior and optional to run a passphrase cracker regularly on all
|
||||||
users passphrases t catch the very simple ones.
|
users passphrases t catch the very simple ones.
|
||||||
|
|
||||||
|
@item --max-passphrase-days @var{n}
|
||||||
|
@opindex max-passphrase-days
|
||||||
|
Ask the user to change the passphrase if @var{n} days have passed since
|
||||||
|
the last change. With @option{--enforce-passphrase-constraints} set the
|
||||||
|
user may not bypass this check.
|
||||||
|
|
||||||
|
@item --enable-passphrase-history
|
||||||
|
@opindex enable-passphrase-history
|
||||||
|
This option does nothing yet.
|
||||||
|
|
||||||
@item --pinentry-program @var{filename}
|
@item --pinentry-program @var{filename}
|
||||||
@opindex pinentry-program
|
@opindex pinentry-program
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
2007-08-28 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* de.po: Updated.
|
||||||
|
|
||||||
2007-08-16 Werner Koch <wk@g10code.com>
|
2007-08-16 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* pt_BR.po, es.po: Remove the "GNU" from the project ID. That
|
* pt_BR.po, es.po: Remove the "GNU" from the project ID. That
|
||||||
|
@ -8,6 +8,7 @@ agent/gpg-agent.c
|
|||||||
agent/preset-passphrase.c
|
agent/preset-passphrase.c
|
||||||
agent/protect-tool.c
|
agent/protect-tool.c
|
||||||
agent/trustlist.c
|
agent/trustlist.c
|
||||||
|
agent/findkey.c
|
||||||
|
|
||||||
common/exechelp.c
|
common/exechelp.c
|
||||||
common/http.c
|
common/http.c
|
||||||
|
493
po/pt_BR.po
493
po/pt_BR.po
File diff suppressed because it is too large
Load Diff
490
po/zh_CN.po
490
po/zh_CN.po
File diff suppressed because it is too large
Load Diff
490
po/zh_TW.po
490
po/zh_TW.po
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,8 @@
|
|||||||
|
2007-08-28 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
|
* gpgconf-comp.c <gpg-agent>: Add options --max-passphrase-days
|
||||||
|
and --enable-passphrase-history.
|
||||||
|
|
||||||
2007-08-27 Werner Koch <wk@g10code.com>
|
2007-08-27 Werner Koch <wk@g10code.com>
|
||||||
|
|
||||||
* gpg-check-pattern.c: New
|
* gpg-check-pattern.c: New
|
||||||
|
@ -528,6 +528,14 @@ static gc_option_t gc_options_gpg_agent[] =
|
|||||||
GC_LEVEL_EXPERT,
|
GC_LEVEL_EXPERT,
|
||||||
"gnupg", N_("|FILE|check new passphrases against pattern in FILE"),
|
"gnupg", N_("|FILE|check new passphrases against pattern in FILE"),
|
||||||
GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
|
GC_ARG_TYPE_PATHNAME, GC_BACKEND_SCDAEMON },
|
||||||
|
{ "max-passphrase-days", GC_OPT_FLAG_RUNTIME,
|
||||||
|
GC_LEVEL_EXPERT, "gnupg",
|
||||||
|
N_("|N|expire the passphrase after N days"),
|
||||||
|
GC_ARG_TYPE_UINT32, GC_BACKEND_GPG_AGENT },
|
||||||
|
{ "enable-passphrases-history", GC_OPT_FLAG_RUNTIME,
|
||||||
|
GC_LEVEL_EXPERT, "gnupg",
|
||||||
|
N_("do not allow the reuse of old passphrases"),
|
||||||
|
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
||||||
|
|
||||||
GC_OPTION_NULL
|
GC_OPTION_NULL
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user