mirror of
git://git.gnupg.org/gnupg.git
synced 2024-11-10 21:38:50 +01:00
Merge branch 'master' into gniibe/decryption-key
This commit is contained in:
commit
e8caa282d3
42
NEWS
42
NEWS
@ -1,6 +1,36 @@
|
|||||||
Noteworthy changes in version 2.3.0 (unreleased)
|
Noteworthy changes in version 2.3.0 (unreleased)
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
|
|
||||||
|
Changes also found in 2.2.8:
|
||||||
|
|
||||||
|
* gpg: Decryption of messages not using the MDC mode will now lead
|
||||||
|
to a hard failure even if a legacy cipher algorithm was used. The
|
||||||
|
option --ignore-mdc-error can be used to turn this failure into a
|
||||||
|
warning. Take care: Never use that option unconditionally or
|
||||||
|
without a prior warning.
|
||||||
|
|
||||||
|
* gpg: The MDC encryption mode is now always used regardless of the
|
||||||
|
cipher algorithm or any preferences. For testing --rfc2440 can be
|
||||||
|
used to create a message without an MDC.
|
||||||
|
|
||||||
|
* gpg: Sanitize the diagnostic output of the original file name in
|
||||||
|
verbose mode. [#4012,CVE-2018-12020]
|
||||||
|
|
||||||
|
* gpg: Detect suspicious multiple plaintext packets in a more
|
||||||
|
reliable way. [#4000]
|
||||||
|
|
||||||
|
* gpg: Fix the duplicate key signature detection code. [#3994]
|
||||||
|
|
||||||
|
* gpg: The options --no-mdc-warn, --force-mdc, --no-force-mdc,
|
||||||
|
--disable-mdc and --no-disable-mdc have no more effect.
|
||||||
|
|
||||||
|
* gpg: New command --show-keys.
|
||||||
|
|
||||||
|
* agent: Add DBUS_SESSION_BUS_ADDRESS and a few other envvars to the
|
||||||
|
list of startup environment variables. [#3947]
|
||||||
|
|
||||||
|
See-also: gnupg-announce/2018q2/000425.html
|
||||||
|
|
||||||
Changes also found in 2.2.7:
|
Changes also found in 2.2.7:
|
||||||
|
|
||||||
* gpg: New option --no-symkey-cache to disable the passphrase cache
|
* gpg: New option --no-symkey-cache to disable the passphrase cache
|
||||||
@ -36,6 +66,8 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
|||||||
* agent,dirmngr: New sub-command "getenv" for "getinfo" to ease
|
* agent,dirmngr: New sub-command "getenv" for "getinfo" to ease
|
||||||
debugging.
|
debugging.
|
||||||
|
|
||||||
|
See-also: gnupg-announce/2018q2/000424.html
|
||||||
|
|
||||||
Changes also found in 2.2.6:
|
Changes also found in 2.2.6:
|
||||||
|
|
||||||
* gpg,gpgsm: New option --request-origin to pretend requests coming
|
* gpg,gpgsm: New option --request-origin to pretend requests coming
|
||||||
@ -81,6 +113,8 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
|||||||
|
|
||||||
* Allow the use of UNC directory names as homedir. [#3818]
|
* Allow the use of UNC directory names as homedir. [#3818]
|
||||||
|
|
||||||
|
See-also: gnupg-announce/2018q2/000421.html
|
||||||
|
|
||||||
Changes also found in 2.2.5:
|
Changes also found in 2.2.5:
|
||||||
|
|
||||||
* gpg: Allow the use of the "cv25519" and "ed25519" short names in
|
* gpg: Allow the use of the "cv25519" and "ed25519" short names in
|
||||||
@ -124,6 +158,8 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
|||||||
with statically linked versions of the core GnuPG libraries. Also
|
with statically linked versions of the core GnuPG libraries. Also
|
||||||
use --enable-wks-tools by default by Speedo builds for Unix.
|
use --enable-wks-tools by default by Speedo builds for Unix.
|
||||||
|
|
||||||
|
See-also: gnupg-announce/2018q1/000420.html
|
||||||
|
|
||||||
Changes also found in 2.2.4:
|
Changes also found in 2.2.4:
|
||||||
|
|
||||||
* gpg: Change default preferences to prefer SHA512.
|
* gpg: Change default preferences to prefer SHA512.
|
||||||
@ -153,6 +189,8 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
|||||||
* New configure option --enable-run-gnupg-user-socket to first try a
|
* New configure option --enable-run-gnupg-user-socket to first try a
|
||||||
socket directory which is not removed by systemd at session end.
|
socket directory which is not removed by systemd at session end.
|
||||||
|
|
||||||
|
See-also: gnupg-announce/2017q4/000419.html
|
||||||
|
|
||||||
Changes also found in 2.2.3:
|
Changes also found in 2.2.3:
|
||||||
|
|
||||||
* gpgsm: Fix initial keybox creation on Windows. [#3507]
|
* gpgsm: Fix initial keybox creation on Windows. [#3507]
|
||||||
@ -172,7 +210,6 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
|||||||
|
|
||||||
See-also: gnupg-announce/2017q4/000417.html
|
See-also: gnupg-announce/2017q4/000417.html
|
||||||
|
|
||||||
|
|
||||||
Changes also found in 2.2.2:
|
Changes also found in 2.2.2:
|
||||||
|
|
||||||
* gpg: Avoid duplicate key imports by concurrently running gpg
|
* gpg: Avoid duplicate key imports by concurrently running gpg
|
||||||
@ -236,6 +273,8 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
|||||||
certificates are configured. If build with GNUTLS, this was
|
certificates are configured. If build with GNUTLS, this was
|
||||||
already the case.
|
already the case.
|
||||||
|
|
||||||
|
See-also: gnupg-announce/2017q3/000415.html
|
||||||
|
|
||||||
Release dates of 2.2.x versions:
|
Release dates of 2.2.x versions:
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
Version 2.2.1 (2017-09-19)
|
Version 2.2.1 (2017-09-19)
|
||||||
@ -245,6 +284,7 @@ Noteworthy changes in version 2.3.0 (unreleased)
|
|||||||
Version 2.2.5 (2018-02-22)
|
Version 2.2.5 (2018-02-22)
|
||||||
Version 2.2.6 (2018-04-09)
|
Version 2.2.6 (2018-04-09)
|
||||||
Version 2.2.7 (2018-05-02)
|
Version 2.2.7 (2018-05-02)
|
||||||
|
Version 2.2.8 (2018-06-08)
|
||||||
|
|
||||||
|
|
||||||
Noteworthy changes in version 2.2.0 (2017-08-28)
|
Noteworthy changes in version 2.2.0 (2017-08-28)
|
||||||
|
@ -304,11 +304,12 @@ enum
|
|||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
CACHE_MODE_IGNORE = 0, /* Special mode to bypass 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 and data 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. */
|
||||||
CACHE_MODE_SSH, /* SSH related cache. */
|
CACHE_MODE_SSH, /* SSH related cache. */
|
||||||
CACHE_MODE_NONCE /* This is a non-predictable nonce. */
|
CACHE_MODE_NONCE, /* This is a non-predictable nonce. */
|
||||||
|
CACHE_MODE_DATA /* Arbitrary data. */
|
||||||
}
|
}
|
||||||
cache_mode_t;
|
cache_mode_t;
|
||||||
|
|
||||||
|
@ -28,6 +28,10 @@
|
|||||||
|
|
||||||
#include "agent.h"
|
#include "agent.h"
|
||||||
|
|
||||||
|
/* The default TTL for DATA items. This has no configure
|
||||||
|
* option because it is expected that clients provide a TTL. */
|
||||||
|
#define DEF_CACHE_TTL_DATA (10 * 60) /* 10 minutes. */
|
||||||
|
|
||||||
/* The size of the encryption key in bytes. */
|
/* The size of the encryption key in bytes. */
|
||||||
#define ENCRYPTION_KEYSIZE (128/8)
|
#define ENCRYPTION_KEYSIZE (128/8)
|
||||||
|
|
||||||
@ -50,11 +54,12 @@ struct secret_data_s {
|
|||||||
char data[1]; /* A string. */
|
char data[1]; /* A string. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* The cache object. */
|
||||||
typedef struct cache_item_s *ITEM;
|
typedef struct cache_item_s *ITEM;
|
||||||
struct cache_item_s {
|
struct cache_item_s {
|
||||||
ITEM next;
|
ITEM next;
|
||||||
time_t created;
|
time_t created;
|
||||||
time_t accessed;
|
time_t accessed; /* Not updated for CACHE_MODE_DATA */
|
||||||
int ttl; /* max. lifetime given in seconds, -1 one means infinite */
|
int ttl; /* max. lifetime given in seconds, -1 one means infinite */
|
||||||
struct secret_data_s *pw;
|
struct secret_data_s *pw;
|
||||||
cache_mode_t cache_mode;
|
cache_mode_t cache_mode;
|
||||||
@ -211,14 +216,18 @@ housekeeping (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Second, make sure that we also remove them based on the created stamp so
|
/* Second, make sure that we also remove them based on the created
|
||||||
that the user has to enter it from time to time. */
|
* stamp so that the user has to enter it from time to time. We
|
||||||
|
* don't do this for data items which are used to storage secrets in
|
||||||
|
* meory and are not user entered passphrases etc. */
|
||||||
for (r=thecache; r; r = r->next)
|
for (r=thecache; r; r = r->next)
|
||||||
{
|
{
|
||||||
unsigned long maxttl;
|
unsigned long maxttl;
|
||||||
|
|
||||||
switch (r->cache_mode)
|
switch (r->cache_mode)
|
||||||
{
|
{
|
||||||
|
case CACHE_MODE_DATA:
|
||||||
|
continue; /* No MAX TTL here. */
|
||||||
case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
|
case CACHE_MODE_SSH: maxttl = opt.max_cache_ttl_ssh; break;
|
||||||
default: maxttl = opt.max_cache_ttl; break;
|
default: maxttl = opt.max_cache_ttl; break;
|
||||||
}
|
}
|
||||||
@ -315,8 +324,11 @@ static int
|
|||||||
cache_mode_equal (cache_mode_t a, cache_mode_t b)
|
cache_mode_equal (cache_mode_t a, cache_mode_t b)
|
||||||
{
|
{
|
||||||
/* CACHE_MODE_ANY matches any mode other than CACHE_MODE_IGNORE. */
|
/* CACHE_MODE_ANY matches any mode other than CACHE_MODE_IGNORE. */
|
||||||
return ((a == CACHE_MODE_ANY && b != CACHE_MODE_IGNORE)
|
return ((a == CACHE_MODE_ANY
|
||||||
|| (b == CACHE_MODE_ANY && a != CACHE_MODE_IGNORE) || a == b);
|
&& !(b == CACHE_MODE_IGNORE || b == CACHE_MODE_DATA))
|
||||||
|
|| (b == CACHE_MODE_ANY
|
||||||
|
&& !(a == CACHE_MODE_IGNORE || a == CACHE_MODE_DATA))
|
||||||
|
|| a == b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -349,6 +361,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
|
|||||||
switch(cache_mode)
|
switch(cache_mode)
|
||||||
{
|
{
|
||||||
case CACHE_MODE_SSH: ttl = opt.def_cache_ttl_ssh; break;
|
case CACHE_MODE_SSH: ttl = opt.def_cache_ttl_ssh; break;
|
||||||
|
case CACHE_MODE_DATA: ttl = DEF_CACHE_TTL_DATA; break;
|
||||||
default: ttl = opt.def_cache_ttl; break;
|
default: ttl = opt.def_cache_ttl; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -415,9 +428,7 @@ agent_put_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Try to find an item in the cache. Note that we currently don't
|
/* Try to find an item in the cache. */
|
||||||
make use of CACHE_MODE except for CACHE_MODE_NONCE and
|
|
||||||
CACHE_MODE_USER. */
|
|
||||||
char *
|
char *
|
||||||
agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
|
agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
|
||||||
{
|
{
|
||||||
@ -458,8 +469,11 @@ agent_get_cache (ctrl_t ctrl, const char *key, cache_mode_t cache_mode)
|
|||||||
&& r->restricted == restricted
|
&& r->restricted == restricted
|
||||||
&& !strcmp (r->key, key))
|
&& !strcmp (r->key, key))
|
||||||
{
|
{
|
||||||
/* Note: To avoid races KEY may not be accessed anymore below. */
|
/* Note: To avoid races KEY may not be accessed anymore
|
||||||
r->accessed = gnupg_get_time ();
|
* below. Note also that we don't update the accessed time
|
||||||
|
* for data items. */
|
||||||
|
if (r->cache_mode != CACHE_MODE_DATA)
|
||||||
|
r->accessed = gnupg_get_time ();
|
||||||
if (DBG_CACHE)
|
if (DBG_CACHE)
|
||||||
log_debug ("... hit\n");
|
log_debug ("... hit\n");
|
||||||
if (r->pw->totallen < 32)
|
if (r->pw->totallen < 32)
|
||||||
|
233
agent/command.c
233
agent/command.c
@ -50,6 +50,8 @@
|
|||||||
#define MAXLEN_KEYPARAM 1024
|
#define MAXLEN_KEYPARAM 1024
|
||||||
/* Maximum allowed size of key data as used in inquiries (bytes). */
|
/* Maximum allowed size of key data as used in inquiries (bytes). */
|
||||||
#define MAXLEN_KEYDATA 8192
|
#define MAXLEN_KEYDATA 8192
|
||||||
|
/* Maximum length of a secret to store under one key. */
|
||||||
|
#define MAXLEN_PUT_SECRET 4096
|
||||||
/* The size of the import/export KEK key (in bytes). */
|
/* The size of the import/export KEK key (in bytes). */
|
||||||
#define KEYWRAP_KEYSIZE (128/8)
|
#define KEYWRAP_KEYSIZE (128/8)
|
||||||
|
|
||||||
@ -292,6 +294,31 @@ parse_keygrip (assuan_context_t ctx, const char *string, unsigned char *buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Parse the TTL from STRING. Leading and trailing spaces are
|
||||||
|
* skipped. The value is constrained to -1 .. MAXINT. On error 0 is
|
||||||
|
* returned, else the number of bytes scanned. */
|
||||||
|
static size_t
|
||||||
|
parse_ttl (const char *string, int *r_ttl)
|
||||||
|
{
|
||||||
|
const char *string_orig = string;
|
||||||
|
long ttl;
|
||||||
|
char *pend;
|
||||||
|
|
||||||
|
ttl = strtol (string, &pend, 10);
|
||||||
|
string = pend;
|
||||||
|
if (string == string_orig || !(spacep (string) || !*string)
|
||||||
|
|| ttl < -1L || (int)ttl != (long)ttl)
|
||||||
|
{
|
||||||
|
*r_ttl = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (spacep (string) || *string== '\n')
|
||||||
|
string++;
|
||||||
|
*r_ttl = (int)ttl;
|
||||||
|
return string - string_orig;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write an Assuan status line. KEYWORD is the first item on the
|
/* Write an Assuan status line. KEYWORD is the first item on the
|
||||||
* status line. The following arguments are all separated by a space
|
* status line. The following arguments are all separated by a space
|
||||||
* in the output. The last argument must be a NULL. Linefeeds and
|
* in the output. The last argument must be a NULL. Linefeeds and
|
||||||
@ -2567,6 +2594,187 @@ cmd_keytocard (assuan_context_t ctx, char *line)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const char hlp_get_secret[] =
|
||||||
|
"GET_SECRET <key>\n"
|
||||||
|
"\n"
|
||||||
|
"Return the secret value stored under KEY\n";
|
||||||
|
static gpg_error_t
|
||||||
|
cmd_get_secret (assuan_context_t ctx, char *line)
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
gpg_error_t err;
|
||||||
|
char *p, *key;
|
||||||
|
char *value = NULL;
|
||||||
|
size_t valuelen;
|
||||||
|
|
||||||
|
/* For now we allow this only for local connections. */
|
||||||
|
if (ctrl->restricted)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
line = skip_options (line);
|
||||||
|
|
||||||
|
for (p=line; *p == ' '; p++)
|
||||||
|
;
|
||||||
|
key = p;
|
||||||
|
p = strchr (key, ' ');
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
*p++ = 0;
|
||||||
|
for (; *p == ' '; p++)
|
||||||
|
;
|
||||||
|
if (*p)
|
||||||
|
{
|
||||||
|
err = set_error (GPG_ERR_ASS_PARAMETER, "too many arguments");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!*key)
|
||||||
|
{
|
||||||
|
err = set_error (GPG_ERR_ASS_PARAMETER, "no key given");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
value = agent_get_cache (ctrl, key, CACHE_MODE_DATA);
|
||||||
|
if (!value)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
valuelen = percent_unescape_inplace (value, 0);
|
||||||
|
err = assuan_send_data (ctx, value, valuelen);
|
||||||
|
wipememory (value, valuelen);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
xfree (value);
|
||||||
|
return leave_cmd (ctx, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const char hlp_put_secret[] =
|
||||||
|
"PUT_SECRET [--clear] <key> <ttl> [<percent_escaped_value>]\n"
|
||||||
|
"\n"
|
||||||
|
"This commands stores a secret under KEY in gpg-agent's in-memory\n"
|
||||||
|
"cache. The TTL must be explicitly given by TTL and the options\n"
|
||||||
|
"from the configuration file are not used. The value is either given\n"
|
||||||
|
"percent-escaped as 3rd argument or if not given inquired by gpg-agent\n"
|
||||||
|
"using the keyword \"SECRET\".\n"
|
||||||
|
"The option --clear removes the secret from the cache."
|
||||||
|
"";
|
||||||
|
static gpg_error_t
|
||||||
|
cmd_put_secret (assuan_context_t ctx, char *line)
|
||||||
|
{
|
||||||
|
ctrl_t ctrl = assuan_get_pointer (ctx);
|
||||||
|
gpg_error_t err = 0;
|
||||||
|
int opt_clear;
|
||||||
|
unsigned char *value = NULL;
|
||||||
|
size_t valuelen = 0;
|
||||||
|
size_t n;
|
||||||
|
char *p, *key, *ttlstr;
|
||||||
|
unsigned char *valstr;
|
||||||
|
int ttl;
|
||||||
|
char *string = NULL;
|
||||||
|
|
||||||
|
/* For now we allow this only for local connections. */
|
||||||
|
if (ctrl->restricted)
|
||||||
|
{
|
||||||
|
err = gpg_error (GPG_ERR_FORBIDDEN);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
opt_clear = has_option (line, "--clear");
|
||||||
|
line = skip_options (line);
|
||||||
|
|
||||||
|
for (p=line; *p == ' '; p++)
|
||||||
|
;
|
||||||
|
key = p;
|
||||||
|
ttlstr = NULL;
|
||||||
|
valstr = NULL;
|
||||||
|
p = strchr (key, ' ');
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
*p++ = 0;
|
||||||
|
for (; *p == ' '; p++)
|
||||||
|
;
|
||||||
|
if (*p)
|
||||||
|
{
|
||||||
|
ttlstr = p;
|
||||||
|
p = strchr (ttlstr, ' ');
|
||||||
|
if (p)
|
||||||
|
{
|
||||||
|
*p++ = 0;
|
||||||
|
for (; *p == ' '; p++)
|
||||||
|
;
|
||||||
|
if (*p)
|
||||||
|
valstr = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!*key)
|
||||||
|
{
|
||||||
|
err = set_error (GPG_ERR_ASS_PARAMETER, "no key given");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
if (!ttlstr || !*ttlstr || !(n = parse_ttl (ttlstr, &ttl)))
|
||||||
|
{
|
||||||
|
err = set_error (GPG_ERR_ASS_PARAMETER, "no or invalid TTL given");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
if (valstr && opt_clear)
|
||||||
|
{
|
||||||
|
err = set_error (GPG_ERR_ASS_PARAMETER,
|
||||||
|
"value not expected with --clear");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valstr)
|
||||||
|
{
|
||||||
|
valuelen = percent_unescape_inplace (valstr, 0);
|
||||||
|
value = NULL;
|
||||||
|
}
|
||||||
|
else /* Inquire the value to store */
|
||||||
|
{
|
||||||
|
err = print_assuan_status (ctx, "INQUIRE_MAXLEN", "%u",MAXLEN_PUT_SECRET);
|
||||||
|
if (!err)
|
||||||
|
err = assuan_inquire (ctx, "SECRET",
|
||||||
|
&value, &valuelen, MAXLEN_PUT_SECRET);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Our cache expects strings and thus we need to turn the buffer
|
||||||
|
* into a string. Instead of resorting to base64 encoding we use a
|
||||||
|
* special percent escaping which only quoted the Nul and the
|
||||||
|
* percent character. */
|
||||||
|
string = percent_data_escape (value? value : valstr, valuelen);
|
||||||
|
if (!string)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
err = agent_put_cache (ctrl, key, CACHE_MODE_DATA, string, ttl);
|
||||||
|
|
||||||
|
|
||||||
|
leave:
|
||||||
|
if (string)
|
||||||
|
{
|
||||||
|
wipememory (string, strlen (string));
|
||||||
|
xfree (string);
|
||||||
|
}
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
wipememory (value, valuelen);
|
||||||
|
xfree (value);
|
||||||
|
}
|
||||||
|
return leave_cmd (ctx, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static const char hlp_getval[] =
|
static const char hlp_getval[] =
|
||||||
"GETVAL <key>\n"
|
"GETVAL <key>\n"
|
||||||
@ -3259,6 +3467,8 @@ register_commands (assuan_context_t ctx)
|
|||||||
{ "IMPORT_KEY", cmd_import_key, hlp_import_key },
|
{ "IMPORT_KEY", cmd_import_key, hlp_import_key },
|
||||||
{ "EXPORT_KEY", cmd_export_key, hlp_export_key },
|
{ "EXPORT_KEY", cmd_export_key, hlp_export_key },
|
||||||
{ "DELETE_KEY", cmd_delete_key, hlp_delete_key },
|
{ "DELETE_KEY", cmd_delete_key, hlp_delete_key },
|
||||||
|
{ "GET_SECRET", cmd_get_secret, hlp_get_secret },
|
||||||
|
{ "PUT_SECRET", cmd_put_secret, hlp_put_secret },
|
||||||
{ "GETVAL", cmd_getval, hlp_getval },
|
{ "GETVAL", cmd_getval, hlp_getval },
|
||||||
{ "PUTVAL", cmd_putval, hlp_putval },
|
{ "PUTVAL", cmd_putval, hlp_putval },
|
||||||
{ "UPDATESTARTUPTTY", cmd_updatestartuptty, hlp_updatestartuptty },
|
{ "UPDATESTARTUPTTY", cmd_updatestartuptty, hlp_updatestartuptty },
|
||||||
@ -3351,7 +3561,8 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
assuan_peercred_t client_creds;
|
assuan_peercred_t client_creds; /* Note: Points into CTX. */
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
rc = assuan_accept (ctx);
|
rc = assuan_accept (ctx);
|
||||||
if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
|
if (gpg_err_code (rc) == GPG_ERR_EOF || rc == -1)
|
||||||
@ -3367,17 +3578,21 @@ start_command_handler (ctrl_t ctrl, gnupg_fd_t listen_fd, gnupg_fd_t fd)
|
|||||||
rc = assuan_get_peercred (ctx, &client_creds);
|
rc = assuan_get_peercred (ctx, &client_creds);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_info ("Assuan get_peercred failed: %s\n", gpg_strerror (rc));
|
|
||||||
client_creds->pid = assuan_get_pid (ctx);
|
if (listen_fd == GNUPG_INVALID_FD && fd == GNUPG_INVALID_FD)
|
||||||
|
;
|
||||||
|
else
|
||||||
|
log_info ("Assuan get_peercred failed: %s\n", gpg_strerror (rc));
|
||||||
|
pid = assuan_get_pid (ctx);
|
||||||
ctrl->client_uid = -1;
|
ctrl->client_uid = -1;
|
||||||
}
|
}
|
||||||
ctrl->server_local->connect_from_self =
|
|
||||||
(client_creds->pid == getpid ());
|
|
||||||
if (client_creds->pid != ASSUAN_INVALID_PID)
|
|
||||||
ctrl->client_pid = (unsigned long)client_creds->pid;
|
|
||||||
else
|
else
|
||||||
ctrl->client_pid = 0;
|
{
|
||||||
ctrl->client_uid = client_creds->uid;
|
pid = client_creds->pid;
|
||||||
|
ctrl->client_uid = client_creds->uid;
|
||||||
|
}
|
||||||
|
ctrl->client_pid = (pid == ASSUAN_INVALID_PID)? 0 : (unsigned long)pid;
|
||||||
|
ctrl->server_local->connect_from_self = (pid == getpid ());
|
||||||
|
|
||||||
rc = assuan_process (ctx);
|
rc = assuan_process (ctx);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -1979,15 +1979,15 @@ agent_deinit_default_ctrl (ctrl_t ctrl)
|
|||||||
gpg_error_t
|
gpg_error_t
|
||||||
agent_copy_startup_env (ctrl_t ctrl)
|
agent_copy_startup_env (ctrl_t ctrl)
|
||||||
{
|
{
|
||||||
static const char *names[] =
|
|
||||||
{"GPG_TTY", "DISPLAY", "TERM", "XAUTHORITY", "PINENTRY_USER_DATA", NULL};
|
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
int idx;
|
int iterator = 0;
|
||||||
const char *value;
|
const char *name, *value;
|
||||||
|
|
||||||
for (idx=0; !err && names[idx]; idx++)
|
while (!err && (name = session_env_list_stdenvnames (&iterator, NULL)))
|
||||||
if ((value = session_env_getenv (opt.startup_env, names[idx])))
|
{
|
||||||
err = session_env_setenv (ctrl->session_env, names[idx], value);
|
if ((value = session_env_getenv (opt.startup_env, name)))
|
||||||
|
err = session_env_setenv (ctrl->session_env, name, value);
|
||||||
|
}
|
||||||
|
|
||||||
if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype)
|
if (!err && !ctrl->lc_ctype && opt.startup_lc_ctype)
|
||||||
if (!(ctrl->lc_ctype = xtrystrdup (opt.startup_lc_ctype)))
|
if (!(ctrl->lc_ctype = xtrystrdup (opt.startup_lc_ctype)))
|
||||||
|
@ -49,7 +49,7 @@ common_sources = \
|
|||||||
strlist.c strlist.h \
|
strlist.c strlist.h \
|
||||||
utf8conv.c utf8conv.h \
|
utf8conv.c utf8conv.h \
|
||||||
argparse.c argparse.h \
|
argparse.c argparse.h \
|
||||||
logging.c logging.h \
|
logging.h \
|
||||||
dotlock.c dotlock.h \
|
dotlock.c dotlock.h \
|
||||||
mischelp.c mischelp.h \
|
mischelp.c mischelp.h \
|
||||||
status.c status.h\
|
status.c status.h\
|
||||||
|
@ -210,7 +210,11 @@ _init_common_subsystems (gpg_err_source_t errsource, int *argcp, char ***argvp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* --version et al shall use estream as well. */
|
/* --version et al shall use estream as well. */
|
||||||
argparse_register_outfnc (writestring_via_estream);
|
argparse_register_outfnc (writestring_via_estream); /* legacy. */
|
||||||
|
gpgrt_set_usage_outfnc (writestring_via_estream);
|
||||||
|
|
||||||
|
/* Register our string mapper with gpgrt. */
|
||||||
|
gpgrt_set_fixed_string_mapper (map_static_macro_string);
|
||||||
|
|
||||||
/* Logging shall use the standard socket directory as fallback. */
|
/* Logging shall use the standard socket directory as fallback. */
|
||||||
log_set_socket_dir_cb (gnupg_socketdir);
|
log_set_socket_dir_cb (gnupg_socketdir);
|
||||||
|
1121
common/logging.c
1121
common/logging.c
File diff suppressed because it is too large
Load Diff
@ -38,10 +38,9 @@
|
|||||||
#include "mischelp.h"
|
#include "mischelp.h"
|
||||||
#include "w32help.h"
|
#include "w32help.h"
|
||||||
|
|
||||||
#if defined(GPGRT_ENABLE_LOG_MACROS) && defined(log_debug_string)
|
/* We use the libgpg-error provided log functions. but we need one
|
||||||
/* We use the libgpg-error provided log functions. but we need one
|
* more function: */
|
||||||
* more function: */
|
#ifdef GPGRT_HAVE_MACRO_FUNCTION
|
||||||
# ifdef GPGRT_HAVE_MACRO_FUNCTION
|
|
||||||
# define BUG() bug_at ( __FILE__, __LINE__, __FUNCTION__)
|
# define BUG() bug_at ( __FILE__, __LINE__, __FUNCTION__)
|
||||||
static inline void bug_at (const char *file, int line, const char *func)
|
static inline void bug_at (const char *file, int line, const char *func)
|
||||||
GPGRT_ATTR_NORETURN;
|
GPGRT_ATTR_NORETURN;
|
||||||
@ -52,7 +51,7 @@ bug_at (const char *file, int line, const char *func)
|
|||||||
file, line, func);
|
file, line, func);
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
# else
|
#else
|
||||||
# define BUG() bug_at ( __FILE__, __LINE__)
|
# define BUG() bug_at ( __FILE__, __LINE__)
|
||||||
static inline void bug_at (const char *file, int line)
|
static inline void bug_at (const char *file, int line)
|
||||||
GPGRT_ATTR_NORETURN;
|
GPGRT_ATTR_NORETURN;
|
||||||
@ -62,94 +61,9 @@ bug_at (const char *file, int line)
|
|||||||
gpgrt_log (GPGRT_LOGLVL_BUG, "there is a bug at %s:%d\n", file, line);
|
gpgrt_log (GPGRT_LOGLVL_BUG, "there is a bug at %s:%d\n", file, line);
|
||||||
abort ();
|
abort ();
|
||||||
}
|
}
|
||||||
# endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
|
|
||||||
|
|
||||||
|
|
||||||
#else /* Use gnupg internal logging functions. */
|
|
||||||
|
|
||||||
int log_get_errorcount (int clear);
|
|
||||||
void log_inc_errorcount (void);
|
|
||||||
void log_set_file( const char *name );
|
|
||||||
void log_set_fd (int fd);
|
|
||||||
void log_set_socket_dir_cb (const char *(*fnc)(void));
|
|
||||||
void log_set_pid_suffix_cb (int (*cb)(unsigned long *r_value));
|
|
||||||
void log_set_prefix (const char *text, unsigned int flags);
|
|
||||||
const char *log_get_prefix (unsigned int *flags);
|
|
||||||
int log_test_fd (int fd);
|
|
||||||
int log_get_fd(void);
|
|
||||||
estream_t log_get_stream (void);
|
|
||||||
|
|
||||||
#ifdef GPGRT_HAVE_MACRO_FUNCTION
|
|
||||||
void bug_at (const char *file, int line, const char *func)
|
|
||||||
GPGRT_ATTR_NORETURN;
|
|
||||||
void _log_assert (const char *expr, const char *file, int line,
|
|
||||||
const char *func) GPGRT_ATTR_NORETURN;
|
|
||||||
# define BUG() bug_at( __FILE__ , __LINE__, __FUNCTION__)
|
|
||||||
# define log_assert(expr) \
|
|
||||||
((expr) \
|
|
||||||
? (void) 0 \
|
|
||||||
: _log_assert (#expr, __FILE__, __LINE__, __FUNCTION__))
|
|
||||||
#else /*!GPGRT_HAVE_MACRO_FUNCTION*/
|
|
||||||
void bug_at (const char *file, int line);
|
|
||||||
void _log_assert (const char *expr, const char *file, int line);
|
|
||||||
# define BUG() bug_at( __FILE__ , __LINE__ )
|
|
||||||
# define log_assert(expr) \
|
|
||||||
((expr) \
|
|
||||||
? (void) 0 \
|
|
||||||
: _log_assert (#expr, __FILE__, __LINE__))
|
|
||||||
#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
|
#endif /*!GPGRT_HAVE_MACRO_FUNCTION*/
|
||||||
|
|
||||||
/* Flag values for log_set_prefix. */
|
|
||||||
#define GPGRT_LOG_WITH_PREFIX 1
|
|
||||||
#define GPGRT_LOG_WITH_TIME 2
|
|
||||||
#define GPGRT_LOG_WITH_PID 4
|
|
||||||
#define GPGRT_LOG_RUN_DETACHED 256
|
|
||||||
#define GPGRT_LOG_NO_REGISTRY 512
|
|
||||||
|
|
||||||
/* Log levels as used by log_log. */
|
|
||||||
enum jnlib_log_levels {
|
|
||||||
GPGRT_LOG_BEGIN,
|
|
||||||
GPGRT_LOG_CONT,
|
|
||||||
GPGRT_LOG_INFO,
|
|
||||||
GPGRT_LOG_WARN,
|
|
||||||
GPGRT_LOG_ERROR,
|
|
||||||
GPGRT_LOG_FATAL,
|
|
||||||
GPGRT_LOG_BUG,
|
|
||||||
GPGRT_LOG_DEBUG
|
|
||||||
};
|
|
||||||
#define GPGRT_LOGLVL_BEGIN GPGRT_LOG_BEGIN
|
|
||||||
#define GPGRT_LOGLVL_CONT GPGRT_LOG_CONT
|
|
||||||
#define GPGRT_LOGLVL_INFO GPGRT_LOG_INFO
|
|
||||||
#define GPGRT_LOGLVL_WARN GPGRT_LOG_WARN
|
|
||||||
#define GPGRT_LOGLVL_ERROR GPGRT_LOG_ERROR
|
|
||||||
#define GPGRT_LOGLVL_FATAL GPGRT_LOG_FATAL
|
|
||||||
#define GPGRT_LOGLVL_BUG GPGRT_LOG_BUG
|
|
||||||
#define GPGRT_LOGLVL_DEBUG GPGRT_LOG_DEBUG
|
|
||||||
|
|
||||||
void log_log (int level, const char *fmt, ...) GPGRT_ATTR_PRINTF(2,3);
|
|
||||||
void log_logv (int level, const char *fmt, va_list arg_ptr);
|
|
||||||
void log_logv_prefix (int level, const char *prefix,
|
|
||||||
const char *fmt, va_list arg_ptr);
|
|
||||||
void log_string (int level, const char *string);
|
|
||||||
void log_bug (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2);
|
|
||||||
void log_fatal (const char *fmt, ...) GPGRT_ATTR_NR_PRINTF(1,2);
|
|
||||||
void log_error (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
|
|
||||||
void log_info (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
|
|
||||||
void log_debug (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
|
|
||||||
void log_debug_string (const char *string, const char *fmt,
|
|
||||||
...) GPGRT_ATTR_PRINTF(2,3);
|
|
||||||
void log_printf (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
|
|
||||||
void log_flush (void);
|
|
||||||
|
|
||||||
/* Print a hexdump of BUFFER. With TEXT passes as NULL print just the
|
|
||||||
raw dump, with TEXT being an empty string, print a trailing
|
|
||||||
linefeed, otherwise print an entire debug line with TEXT followed
|
|
||||||
by the hexdump and a final LF. */
|
|
||||||
void log_printhex (const void *buffer, size_t length, const char *text);
|
|
||||||
|
|
||||||
void log_clock (const char *fmt, ...) GPGRT_ATTR_PRINTF(1,2);
|
|
||||||
|
|
||||||
#endif /* Use gnupg internal logging functions. */
|
|
||||||
|
|
||||||
/* Some handy assertion macros which don't abort. */
|
/* Some handy assertion macros which don't abort. */
|
||||||
|
|
||||||
|
@ -102,7 +102,7 @@ gpg_error_t nvc_set_private_key (nvc_t pk, gcry_sexp_t sexp);
|
|||||||
|
|
||||||
/* Parsing and serialization. */
|
/* Parsing and serialization. */
|
||||||
|
|
||||||
/* Parse STREAM and return a newly allocated private key container
|
/* Parse STREAM and return a newly allocated name-value container
|
||||||
structure in RESULT. If ERRLINEP is given, the line number the
|
structure in RESULT. If ERRLINEP is given, the line number the
|
||||||
parser was last considering is stored there. */
|
parser was last considering is stored there. */
|
||||||
gpg_error_t nvc_parse (nvc_t *result, int *errlinep, estream_t stream);
|
gpg_error_t nvc_parse (nvc_t *result, int *errlinep, estream_t stream);
|
||||||
|
@ -87,6 +87,50 @@ percent_plus_escape (const char *string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a newly alloced string from (DATA,DATALEN) with embedded
|
||||||
|
* Nuls quoted as %00. The standard percent unescaping can be
|
||||||
|
* used to reverse this encoding. */
|
||||||
|
char *
|
||||||
|
percent_data_escape (const void *data, size_t datalen)
|
||||||
|
{
|
||||||
|
char *buffer, *p;
|
||||||
|
const char *s;
|
||||||
|
size_t n, length;
|
||||||
|
|
||||||
|
for (length=1, s=data, n=datalen; n; s++, n--)
|
||||||
|
{
|
||||||
|
if (!*s || *s == '%')
|
||||||
|
length += 3;
|
||||||
|
else
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer = p = xtrymalloc (length);
|
||||||
|
if (!buffer)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (s=data, n=datalen; n; s++, n--)
|
||||||
|
{
|
||||||
|
if (!*s)
|
||||||
|
{
|
||||||
|
memcpy (p, "%00", 3);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
else if (*s == '%')
|
||||||
|
{
|
||||||
|
memcpy (p, "%25", 3);
|
||||||
|
p += 3;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*p++ = *s;
|
||||||
|
}
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Do the percent and plus/space unescaping from STRING to BUFFER and
|
/* Do the percent and plus/space unescaping from STRING to BUFFER and
|
||||||
return the length of the valid buffer. Plus unescaping is only
|
return the length of the valid buffer. Plus unescaping is only
|
||||||
done if WITHPLUS is true. An escaped Nul character will be
|
done if WITHPLUS is true. An escaped Nul character will be
|
||||||
|
@ -99,6 +99,55 @@ test_percent_plus_escape (void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_percent_data_escape (void)
|
||||||
|
{
|
||||||
|
static struct {
|
||||||
|
const char *data;
|
||||||
|
size_t datalen;
|
||||||
|
const char *expect;
|
||||||
|
} tbl[] = {
|
||||||
|
{
|
||||||
|
"", 0,
|
||||||
|
""
|
||||||
|
}, {
|
||||||
|
"a", 1,
|
||||||
|
"a",
|
||||||
|
}, {
|
||||||
|
"%22", 3,
|
||||||
|
"%2522"
|
||||||
|
}, {
|
||||||
|
"%%", 3,
|
||||||
|
"%25%25%00"
|
||||||
|
}, {
|
||||||
|
"\n \0BC\t", 6,
|
||||||
|
"\n %00BC\t"
|
||||||
|
}, { NULL, 0, NULL }
|
||||||
|
};
|
||||||
|
char *buf;
|
||||||
|
int i;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
for (i=0; tbl[i].data; i++)
|
||||||
|
{
|
||||||
|
buf = percent_data_escape (tbl[i].data, tbl[i].datalen);
|
||||||
|
if (!buf)
|
||||||
|
{
|
||||||
|
fprintf (stderr, "out of core: %s\n", strerror (errno));
|
||||||
|
exit (2);
|
||||||
|
}
|
||||||
|
if (strcmp (buf, tbl[i].expect))
|
||||||
|
fail (i);
|
||||||
|
len = percent_plus_unescape_inplace (buf, 0);
|
||||||
|
if (len != tbl[i].datalen)
|
||||||
|
fail (i);
|
||||||
|
else if (memcmp (buf, tbl[i].data, tbl[i].datalen))
|
||||||
|
fail (i);
|
||||||
|
xfree (buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main (int argc, char **argv)
|
main (int argc, char **argv)
|
||||||
@ -109,6 +158,6 @@ main (int argc, char **argv)
|
|||||||
/* FIXME: We escape_unescape is not tested - only
|
/* FIXME: We escape_unescape is not tested - only
|
||||||
percent_plus_unescape. */
|
percent_plus_unescape. */
|
||||||
test_percent_plus_escape ();
|
test_percent_plus_escape ();
|
||||||
|
test_percent_data_escape ();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -39,21 +39,6 @@
|
|||||||
* libgpg-error version. Define them here.
|
* libgpg-error version. Define them here.
|
||||||
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
|
* Example: (#if GPG_ERROR_VERSION_NUMBER < 0x011500 // 1.21)
|
||||||
*/
|
*/
|
||||||
#if GPG_ERROR_VERSION_NUMBER < 0x011a00 /* 1.26 */
|
|
||||||
# define GPG_ERR_UNKNOWN_FLAG 309
|
|
||||||
# define GPG_ERR_INV_ORDER 310
|
|
||||||
# define GPG_ERR_ALREADY_FETCHED 311
|
|
||||||
# define GPG_ERR_TRY_LATER 312
|
|
||||||
# define GPG_ERR_SYSTEM_BUG 666
|
|
||||||
# define GPG_ERR_DNS_UNKNOWN 711
|
|
||||||
# define GPG_ERR_DNS_SECTION 712
|
|
||||||
# define GPG_ERR_DNS_ADDRESS 713
|
|
||||||
# define GPG_ERR_DNS_NO_QUERY 714
|
|
||||||
# define GPG_ERR_DNS_NO_ANSWER 715
|
|
||||||
# define GPG_ERR_DNS_CLOSED 716
|
|
||||||
# define GPG_ERR_DNS_VERIFY 717
|
|
||||||
# define GPG_ERR_DNS_TIMEOUT 718
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* Hash function used with libksba. */
|
/* Hash function used with libksba. */
|
||||||
@ -216,6 +201,7 @@ char *hex2str_alloc (const char *hexstring, size_t *r_count);
|
|||||||
|
|
||||||
/*-- percent.c --*/
|
/*-- percent.c --*/
|
||||||
char *percent_plus_escape (const char *string);
|
char *percent_plus_escape (const char *string);
|
||||||
|
char *percent_data_escape (const void *data, size_t datalen);
|
||||||
char *percent_plus_unescape (const char *string, int nulrepl);
|
char *percent_plus_unescape (const char *string, int nulrepl);
|
||||||
char *percent_unescape (const char *string, int nulrepl);
|
char *percent_unescape (const char *string, int nulrepl);
|
||||||
|
|
||||||
|
30
configure.ac
30
configure.ac
@ -53,7 +53,7 @@ AC_INIT([mym4_package],[mym4_version], [https://bugs.gnupg.org])
|
|||||||
# build-aux/speedo.mk and Makefile.am
|
# build-aux/speedo.mk and Makefile.am
|
||||||
AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg24", [swdb tag for this branch])
|
AC_DEFINE_UNQUOTED(GNUPG_SWDB_TAG, "gnupg24", [swdb tag for this branch])
|
||||||
|
|
||||||
NEED_GPG_ERROR_VERSION=1.24
|
NEED_GPG_ERROR_VERSION=1.29
|
||||||
|
|
||||||
NEED_LIBGCRYPT_API=1
|
NEED_LIBGCRYPT_API=1
|
||||||
NEED_LIBGCRYPT_VERSION=1.7.0
|
NEED_LIBGCRYPT_VERSION=1.7.0
|
||||||
@ -507,6 +507,9 @@ AH_BOTTOM([
|
|||||||
#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
|
#define GNUPG_PRIVATE_KEYS_DIR "private-keys-v1.d"
|
||||||
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
|
#define GNUPG_OPENPGP_REVOC_DIR "openpgp-revocs.d"
|
||||||
|
|
||||||
|
#define GNUPG_DEF_COPYRIGHT_LINE \
|
||||||
|
"Copyright (C) 2018 Free Software Foundation, Inc."
|
||||||
|
|
||||||
/* For some systems (DOS currently), we hardcode the path here. For
|
/* For some systems (DOS currently), we hardcode the path here. For
|
||||||
POSIX systems the values are constructed by the Makefiles, so that
|
POSIX systems the values are constructed by the Makefiles, so that
|
||||||
the values may be overridden by the make invocations; this is to
|
the values may be overridden by the make invocations; this is to
|
||||||
@ -1216,6 +1219,8 @@ elif test x"$with_mailprog" != xno ; then
|
|||||||
AC_SUBST(SENDMAIL,$with_mailprog)
|
AC_SUBST(SENDMAIL,$with_mailprog)
|
||||||
AC_MSG_RESULT($with_mailprog)
|
AC_MSG_RESULT($with_mailprog)
|
||||||
fi
|
fi
|
||||||
|
AC_DEFINE_UNQUOTED(NAME_OF_SENDMAIL,"$SENDMAIL",
|
||||||
|
[Tool with sendmail -t interface])
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -1387,18 +1392,17 @@ AC_CHECK_DECLS(getpagesize)
|
|||||||
AC_FUNC_FSEEKO
|
AC_FUNC_FSEEKO
|
||||||
AC_FUNC_VPRINTF
|
AC_FUNC_VPRINTF
|
||||||
AC_FUNC_FORK
|
AC_FUNC_FORK
|
||||||
AC_CHECK_FUNCS([strerror strlwr tcgetattr mmap canonicalize_file_name])
|
AC_CHECK_FUNCS([atexit canonicalize_file_name clock_gettime ctermid \
|
||||||
AC_CHECK_FUNCS([strcasecmp strncasecmp ctermid times gmtime_r strtoull])
|
fcntl flockfile fsync ftello ftruncate funlockfile \
|
||||||
AC_CHECK_FUNCS([setenv unsetenv fcntl ftruncate inet_ntop])
|
getaddrinfo getenv getpagesize getpwnam getpwuid \
|
||||||
AC_CHECK_FUNCS([canonicalize_file_name])
|
getrlimit getrusage gettimeofday gmtime_r \
|
||||||
AC_CHECK_FUNCS([gettimeofday getrusage getrlimit setrlimit clock_gettime])
|
inet_ntop inet_pton isascii lstat \
|
||||||
AC_CHECK_FUNCS([atexit raise getpagesize strftime nl_langinfo setlocale])
|
memicmp memmove memrchr mmap nl_langinfo pipe \
|
||||||
AC_CHECK_FUNCS([waitpid wait4 sigaction sigprocmask pipe getaddrinfo])
|
raise rand setenv setlocale setrlimit sigaction \
|
||||||
AC_CHECK_FUNCS([ttyname rand ftello fsync stat lstat])
|
sigprocmask stat stpcpy strcasecmp strerror strftime \
|
||||||
AC_CHECK_FUNCS([memicmp stpcpy strsep strlwr strtoul memmove stricmp strtol \
|
stricmp strlwr strncasecmp strpbrk strsep \
|
||||||
memrchr isascii timegm getrusage setrlimit stat setlocale \
|
strtol strtoul strtoull tcgetattr timegm times \
|
||||||
flockfile funlockfile getpwnam getpwuid \
|
ttyname unsetenv wait4 waitpid ])
|
||||||
getenv inet_pton strpbrk])
|
|
||||||
|
|
||||||
# On some systems (e.g. Solaris) nanosleep requires linking to librl.
|
# On some systems (e.g. Solaris) nanosleep requires linking to librl.
|
||||||
# Given that we use nanosleep only as an optimization over a select
|
# Given that we use nanosleep only as an optimization over a select
|
||||||
|
@ -612,6 +612,8 @@ libdns_init (void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ld.resolv_conf->options.recurse = recursive_resolver_p ();
|
||||||
|
|
||||||
/* dns_hints_local for stub mode, dns_hints_root for recursive. */
|
/* dns_hints_local for stub mode, dns_hints_root for recursive. */
|
||||||
ld.hints = (recursive_resolver
|
ld.hints = (recursive_resolver
|
||||||
? dns_hints_root (ld.resolv_conf, &derr)
|
? dns_hints_root (ld.resolv_conf, &derr)
|
||||||
|
@ -5371,13 +5371,16 @@ struct dns_resolv_conf *dns_resconf_open(int *error) {
|
|||||||
if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
|
if (0 != gethostname(resconf->search[0], sizeof resconf->search[0]))
|
||||||
goto syerr;
|
goto syerr;
|
||||||
|
|
||||||
dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
|
|
||||||
dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX: If gethostname() returned a string without any label
|
* If gethostname() returned a string without any label
|
||||||
* separator, then search[0][0] should be NUL.
|
* separator, then search[0][0] should be NUL.
|
||||||
*/
|
*/
|
||||||
|
if (strchr (resconf->search[0], '.')) {
|
||||||
|
dns_d_anchor(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
|
||||||
|
dns_d_cleave(resconf->search[0], sizeof resconf->search[0], resconf->search[0], strlen(resconf->search[0]));
|
||||||
|
} else {
|
||||||
|
memset (resconf->search[0], 0, sizeof resconf->search[0]);
|
||||||
|
}
|
||||||
|
|
||||||
dns_resconf_acquire(resconf);
|
dns_resconf_acquire(resconf);
|
||||||
|
|
||||||
@ -5549,6 +5552,7 @@ int dns_resconf_pton(struct sockaddr_storage *ss, const char *src) {
|
|||||||
unsigned short port = 0;
|
unsigned short port = 0;
|
||||||
int ch, af = AF_INET, error;
|
int ch, af = AF_INET, error;
|
||||||
|
|
||||||
|
memset(ss, 0, sizeof *ss);
|
||||||
while ((ch = *src++)) {
|
while ((ch = *src++)) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case ' ':
|
case ' ':
|
||||||
@ -6096,17 +6100,9 @@ int dns_nssconf_loadfile(struct dns_resolv_conf *resconf, FILE *fp) {
|
|||||||
dns_anyconf_skip(" \t", fp);
|
dns_anyconf_skip(" \t", fp);
|
||||||
|
|
||||||
if ('[' == dns_anyconf_peek(fp)) {
|
if ('[' == dns_anyconf_peek(fp)) {
|
||||||
dns_anyconf_skip("[ \t", fp);
|
dns_anyconf_skip("[! \t", fp);
|
||||||
|
|
||||||
for (;;) {
|
while (dns_anyconf_scan(&cf, "%w_", fp, &error)) {
|
||||||
if ('!' == dns_anyconf_peek(fp)) {
|
|
||||||
dns_anyconf_skip("! \t", fp);
|
|
||||||
/* FIXME: negating statuses; currently not implemented */
|
|
||||||
dns_anyconf_skip("^#;]\n", fp); /* skip to end of criteria */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) break;
|
|
||||||
dns_anyconf_skip("= \t", fp);
|
dns_anyconf_skip("= \t", fp);
|
||||||
if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
|
if (!dns_anyconf_scan(&cf, "%w_", fp, &error)) {
|
||||||
dns_anyconf_pop(&cf); /* discard status */
|
dns_anyconf_pop(&cf); /* discard status */
|
||||||
@ -6319,6 +6315,7 @@ int dns_resconf_setiface(struct dns_resolv_conf *resconf, const char *addr, unsi
|
|||||||
int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
|
int af = (strchr(addr, ':'))? AF_INET6 : AF_INET;
|
||||||
int error;
|
int error;
|
||||||
|
|
||||||
|
memset(&resconf->iface, 0, sizeof (struct sockaddr_storage));
|
||||||
if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
|
if ((error = dns_pton(af, addr, dns_sa_addr(af, &resconf->iface, NULL))))
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
@ -6630,6 +6627,7 @@ struct dns_hints *dns_hints_root(struct dns_resolv_conf *resconf, int *error_) {
|
|||||||
for (i = 0; i < lengthof(root_hints); i++) {
|
for (i = 0; i < lengthof(root_hints); i++) {
|
||||||
af = root_hints[i].af;
|
af = root_hints[i].af;
|
||||||
|
|
||||||
|
memset(&ss, 0, sizeof ss);
|
||||||
if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
|
if ((error = dns_pton(af, root_hints[i].addr, dns_sa_addr(af, &ss, NULL))))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -7123,6 +7121,8 @@ static int dns_socket(struct sockaddr *local, int type, int *error_) {
|
|||||||
if (type != SOCK_DGRAM)
|
if (type != SOCK_DGRAM)
|
||||||
return fd;
|
return fd;
|
||||||
|
|
||||||
|
#define LEAVE_SELECTION_OF_PORT_TO_KERNEL
|
||||||
|
#if !defined(LEAVE_SELECTION_OF_PORT_TO_KERNEL)
|
||||||
/*
|
/*
|
||||||
* FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
|
* FreeBSD, Linux, OpenBSD, OS X, and Solaris use random ports by
|
||||||
* default. Though the ephemeral range is quite small on OS X
|
* default. Though the ephemeral range is quite small on OS X
|
||||||
@ -7148,6 +7148,7 @@ static int dns_socket(struct sockaddr *local, int type, int *error_) {
|
|||||||
|
|
||||||
/* NB: continue to next bind statement */
|
/* NB: continue to next bind statement */
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (0 == bind(fd, local, dns_sa_len(local)))
|
if (0 == bind(fd, local, dns_sa_len(local)))
|
||||||
return fd;
|
return fd;
|
||||||
@ -7619,8 +7620,23 @@ retry:
|
|||||||
|
|
||||||
so->state++; /* FALL THROUGH */
|
so->state++; /* FALL THROUGH */
|
||||||
case DNS_SO_UDP_CONN:
|
case DNS_SO_UDP_CONN:
|
||||||
|
udp_connect_retry:
|
||||||
error = dns_connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
|
error = dns_connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
|
||||||
dns_trace_sys_connect(so->trace, so->udp, SOCK_DGRAM, (struct sockaddr *)&so->remote, error);
|
dns_trace_sys_connect(so->trace, so->udp, SOCK_DGRAM, (struct sockaddr *)&so->remote, error);
|
||||||
|
|
||||||
|
/* Linux returns EINVAL when address was bound to
|
||||||
|
localhost and it's external IP address now. */
|
||||||
|
if (error == EINVAL) {
|
||||||
|
struct sockaddr unspec_addr;
|
||||||
|
memset (&unspec_addr, 0, sizeof unspec_addr);
|
||||||
|
unspec_addr.sa_family = AF_UNSPEC;
|
||||||
|
connect(so->udp, &unspec_addr, sizeof unspec_addr);
|
||||||
|
goto udp_connect_retry;
|
||||||
|
} else if (error == ECONNREFUSED)
|
||||||
|
/* Error for previous socket operation may
|
||||||
|
be reserverd asynchronously. */
|
||||||
|
goto udp_connect_retry;
|
||||||
|
|
||||||
if (error)
|
if (error)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
@ -8829,7 +8845,10 @@ exec:
|
|||||||
if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
|
if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
|
||||||
dgoto(R->sp, DNS_R_FOREACH_A);
|
dgoto(R->sp, DNS_R_FOREACH_A);
|
||||||
|
|
||||||
if ((error = dns_so_check(&R->so)))
|
error = dns_so_check(&R->so);
|
||||||
|
if (R->so.state != DNS_SO_SOCKS_CONN && error == ECONNREFUSED)
|
||||||
|
dgoto(R->sp, DNS_R_FOREACH_A);
|
||||||
|
else if (error)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
|
if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
|
||||||
@ -8962,7 +8981,10 @@ exec:
|
|||||||
if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
|
if (dns_so_elapsed(&R->so) >= dns_resconf_timeout(R->resconf))
|
||||||
dgoto(R->sp, DNS_R_FOREACH_AAAA);
|
dgoto(R->sp, DNS_R_FOREACH_AAAA);
|
||||||
|
|
||||||
if ((error = dns_so_check(&R->so)))
|
error = dns_so_check(&R->so);
|
||||||
|
if (error == ECONNREFUSED)
|
||||||
|
dgoto(R->sp, DNS_R_FOREACH_AAAA);
|
||||||
|
else if (error)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
|
if (!dns_p_setptr(&F->answer, dns_so_fetch(&R->so, &error)))
|
||||||
@ -10874,6 +10896,7 @@ static int send_query(int argc, char *argv[]) {
|
|||||||
struct dns_socket *so;
|
struct dns_socket *so;
|
||||||
int error, type;
|
int error, type;
|
||||||
|
|
||||||
|
memset(&ss, 0, sizeof ss);
|
||||||
if (argc > 1) {
|
if (argc > 1) {
|
||||||
ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
|
ss.ss_family = (strchr(argv[1], ':'))? AF_INET6 : AF_INET;
|
||||||
|
|
||||||
|
23
doc/DETAILS
23
doc/DETAILS
@ -59,6 +59,7 @@ described here.
|
|||||||
- uat :: User attribute (same as user id except for field 10).
|
- uat :: User attribute (same as user id except for field 10).
|
||||||
- sig :: Signature
|
- sig :: Signature
|
||||||
- rev :: Revocation signature
|
- rev :: Revocation signature
|
||||||
|
- rvs :: Recocation signature (standalone) [since 2.2.9]
|
||||||
- fpr :: Fingerprint (fingerprint is in field 10)
|
- fpr :: Fingerprint (fingerprint is in field 10)
|
||||||
- pkd :: Public key data [*]
|
- pkd :: Public key data [*]
|
||||||
- grp :: Keygrip
|
- grp :: Keygrip
|
||||||
@ -179,6 +180,9 @@ described here.
|
|||||||
revocation key is also given here, 'x' and 'l' is used the same
|
revocation key is also given here, 'x' and 'l' is used the same
|
||||||
way. This field if not used for X.509.
|
way. This field if not used for X.509.
|
||||||
|
|
||||||
|
"rev" and "rvs" may be followed by a comma and a 2 digit hexnumber
|
||||||
|
with the revocation reason.
|
||||||
|
|
||||||
*** Field 12 - Key capabilities
|
*** Field 12 - Key capabilities
|
||||||
|
|
||||||
The defined capabilities are:
|
The defined capabilities are:
|
||||||
@ -207,12 +211,13 @@ described here.
|
|||||||
For "uid" records this field lists the preferences in the same way
|
For "uid" records this field lists the preferences in the same way
|
||||||
gpg's --edit-key menu does.
|
gpg's --edit-key menu does.
|
||||||
|
|
||||||
For "sig" records, this is the fingerprint of the key that issued
|
For "sig", "rev" and "rvs" records, this is the fingerprint of the
|
||||||
the signature. Note that this may only be filled if the signature
|
key that issued the signature. Note that this may only be filled
|
||||||
verified correctly. Note also that for various technical reasons,
|
if the signature verified correctly. Note also that for various
|
||||||
this fingerprint is only available if --no-sig-cache is used.
|
technical reasons, this fingerprint is only available if
|
||||||
Since 2.2.7 this field will also be set if the key is missing but
|
--no-sig-cache is used. Since 2.2.7 this field will also be set
|
||||||
the signature carries an issuer fingerprint as meta data.
|
if the key is missing but the signature carries an issuer
|
||||||
|
fingerprint as meta data.
|
||||||
|
|
||||||
*** Field 14 - Flag field
|
*** Field 14 - Flag field
|
||||||
|
|
||||||
@ -260,6 +265,12 @@ described here.
|
|||||||
optionally followed by a space and an URL. This goes along with
|
optionally followed by a space and an URL. This goes along with
|
||||||
the previous field. The URL is quoted in C style.
|
the previous field. The URL is quoted in C style.
|
||||||
|
|
||||||
|
*** Field 21 - Comment
|
||||||
|
|
||||||
|
This is currently only used in "rev" and "rvs" records to carry
|
||||||
|
the the comment field of the recocation reason. The value is
|
||||||
|
quoted in C style.
|
||||||
|
|
||||||
** Special fields
|
** Special fields
|
||||||
|
|
||||||
*** PKD - Public key data
|
*** PKD - Public key data
|
||||||
|
22
doc/gpg.texi
22
doc/gpg.texi
@ -328,7 +328,7 @@ following the "sig" tag (and thus before the flags described below. A
|
|||||||
"!" indicates that the signature has been successfully verified, a "-"
|
"!" indicates that the signature has been successfully verified, a "-"
|
||||||
denotes a bad signature and a "%" is used if an error occurred while
|
denotes a bad signature and a "%" is used if an error occurred while
|
||||||
checking the signature (e.g. a non supported algorithm). Signatures
|
checking the signature (e.g. a non supported algorithm). Signatures
|
||||||
where the public key is not availabale are not listed; to see their
|
where the public key is not available are not listed; to see their
|
||||||
keyids the command @option{--list-sigs} can be used.
|
keyids the command @option{--list-sigs} can be used.
|
||||||
|
|
||||||
For each signature listed, there are several flags in between the
|
For each signature listed, there are several flags in between the
|
||||||
@ -353,6 +353,16 @@ may thus be used to see what keys @command{@gpgname} might use. In
|
|||||||
particular external methods as defined by @option{--auto-key-locate} may
|
particular external methods as defined by @option{--auto-key-locate} may
|
||||||
be used to locate a key. Only public keys are listed.
|
be used to locate a key. Only public keys are listed.
|
||||||
|
|
||||||
|
@item --show-keys
|
||||||
|
@opindex show-keys
|
||||||
|
This commands takes OpenPGP keys as input and prints information about
|
||||||
|
them in the same way the command @option{--list-keys} does for locally
|
||||||
|
stored key. In addition the list options @code{show-unusable-uids},
|
||||||
|
@code{show-unusable-subkeys}, @code{show-notations} and
|
||||||
|
@code{show-policy-urls} are also enabled. As usual for automated
|
||||||
|
processing, this command should be combined with the option
|
||||||
|
@option{--with-colons}.
|
||||||
|
|
||||||
@item --fingerprint
|
@item --fingerprint
|
||||||
@opindex fingerprint
|
@opindex fingerprint
|
||||||
List all keys (or the specified ones) along with their
|
List all keys (or the specified ones) along with their
|
||||||
@ -2305,7 +2315,8 @@ opposite meaning. The options are:
|
|||||||
Show a listing of the key as imported right before it is stored.
|
Show a listing of the key as imported right before it is stored.
|
||||||
This can be combined with the option @option{--dry-run} to only look
|
This can be combined with the option @option{--dry-run} to only look
|
||||||
at keys; the option @option{show-only} is a shortcut for this
|
at keys; the option @option{show-only} is a shortcut for this
|
||||||
combination. Note that suffixes like '#' for "sec" and "sbb" lines
|
combination. The command @option{--show-keys} is another shortcut
|
||||||
|
for this. Note that suffixes like '#' for "sec" and "sbb" lines
|
||||||
may or may not be printed.
|
may or may not be printed.
|
||||||
|
|
||||||
@item import-export
|
@item import-export
|
||||||
@ -2417,6 +2428,11 @@ The available properties are:
|
|||||||
Boolean indicating whether a key or subkey is a secret one.
|
Boolean indicating whether a key or subkey is a secret one.
|
||||||
(drop-subkey)
|
(drop-subkey)
|
||||||
|
|
||||||
|
@item usage
|
||||||
|
A string indicating the usage flags for the subkey, from the
|
||||||
|
sequence ``ecsa?''. For example, a subkey capable of just signing
|
||||||
|
and authentication would be an exact match for ``sa''. (drop-subkey)
|
||||||
|
|
||||||
@item sig_created
|
@item sig_created
|
||||||
@itemx sig_created_d
|
@itemx sig_created_d
|
||||||
The first is the timestamp a signature packet was created. The
|
The first is the timestamp a signature packet was created. The
|
||||||
@ -3368,7 +3384,7 @@ absolute date in the form YYYY-MM-DD. Defaults to "0".
|
|||||||
@opindex default-new-key-algo @var{string}
|
@opindex default-new-key-algo @var{string}
|
||||||
This option can be used to change the default algorithms for key
|
This option can be used to change the default algorithms for key
|
||||||
generation. The @var{string} is similar to the arguments required for
|
generation. The @var{string} is similar to the arguments required for
|
||||||
the command @option{--quick-add-key} but slighly different. For
|
the command @option{--quick-add-key} but slightly different. For
|
||||||
example the current default of @code{"rsa2048/cert,sign+rsa2048/encr"}
|
example the current default of @code{"rsa2048/cert,sign+rsa2048/encr"}
|
||||||
(or @code{"rsa3072"}) can be changed to the value of what we currently
|
(or @code{"rsa3072"}) can be changed to the value of what we currently
|
||||||
call future default, which is @code{"ed25519/cert,sign+cv25519/encr"}.
|
call future default, which is @code{"ed25519/cert,sign+cv25519/encr"}.
|
||||||
|
@ -399,7 +399,7 @@ comes with almost all German banking cards.
|
|||||||
This application adds read-only support for keys and certificates
|
This application adds read-only support for keys and certificates
|
||||||
stored on a @uref{http://www.smartcard-hsm.com, SmartCard-HSM}.
|
stored on a @uref{http://www.smartcard-hsm.com, SmartCard-HSM}.
|
||||||
|
|
||||||
To generate keys and store certifiates you may use
|
To generate keys and store certificates you may use
|
||||||
@uref{https://github.com/OpenSC/OpenSC/wiki/SmartCardHSM, OpenSC} or
|
@uref{https://github.com/OpenSC/OpenSC/wiki/SmartCardHSM, OpenSC} or
|
||||||
the tools from @uref{http://www.openscdp.org, OpenSCDP}.
|
the tools from @uref{http://www.openscdp.org, OpenSCDP}.
|
||||||
|
|
||||||
|
@ -290,7 +290,7 @@ Check the options for the component @var{component}.
|
|||||||
Apply the configuration settings listed in @var{file} to the
|
Apply the configuration settings listed in @var{file} to the
|
||||||
configuration files. If @var{file} has no suffix and no slashes the
|
configuration files. If @var{file} has no suffix and no slashes the
|
||||||
command first tries to read a file with the suffix @code{.prf} from
|
command first tries to read a file with the suffix @code{.prf} from
|
||||||
the the data directory (@code{gpgconf --list-dirs datadir}) before it
|
the data directory (@code{gpgconf --list-dirs datadir}) before it
|
||||||
reads the file verbatim. A profile is divided into sections using the
|
reads the file verbatim. A profile is divided into sections using the
|
||||||
bracketed component name. Each section then lists the option which
|
bracketed component name. Each section then lists the option which
|
||||||
shall go into the respective configuration file.
|
shall go into the respective configuration file.
|
||||||
|
@ -152,6 +152,7 @@ gpg_sources = server.c \
|
|||||||
trust.c $(trust_source) $(tofu_source) \
|
trust.c $(trust_source) $(tofu_source) \
|
||||||
$(card_source) \
|
$(card_source) \
|
||||||
exec.c exec.h \
|
exec.c exec.h \
|
||||||
|
key-clean.c key-clean.h \
|
||||||
key-check.c key-check.h
|
key-check.c key-check.h
|
||||||
|
|
||||||
gpg_SOURCES = gpg.c \
|
gpg_SOURCES = gpg.c \
|
||||||
|
@ -851,6 +851,7 @@ fetch_url (ctrl_t ctrl)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
agent_release_card_info (&info);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
19
g10/export.c
19
g10/export.c
@ -41,6 +41,8 @@
|
|||||||
#include "../common/init.h"
|
#include "../common/init.h"
|
||||||
#include "trustdb.h"
|
#include "trustdb.h"
|
||||||
#include "call-agent.h"
|
#include "call-agent.h"
|
||||||
|
#include "key-clean.h"
|
||||||
|
|
||||||
|
|
||||||
/* An object to keep track of subkeys. */
|
/* An object to keep track of subkeys. */
|
||||||
struct subkey_list_s
|
struct subkey_list_s
|
||||||
@ -2001,12 +2003,19 @@ do_export_stream (ctrl_t ctrl, iobuf_t out, strlist_t users, int secret,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Always do the cleaning on the public key part if requested.
|
/* Always do the cleaning on the public key part if requested.
|
||||||
* Note that both export-clean and export-minimal only apply to
|
* A designated revocation is never stripped, even with
|
||||||
* UID sigs (0x10, 0x11, 0x12, and 0x13). A designated
|
* export-minimal set. */
|
||||||
* revocation is never stripped, even with export-minimal set. */
|
|
||||||
if ((options & EXPORT_CLEAN))
|
if ((options & EXPORT_CLEAN))
|
||||||
clean_key (ctrl, keyblock, opt.verbose,
|
{
|
||||||
(options&EXPORT_MINIMAL), NULL, NULL);
|
merge_keys_and_selfsig (ctrl, keyblock);
|
||||||
|
clean_all_uids (ctrl, keyblock, opt.verbose,
|
||||||
|
(options&EXPORT_MINIMAL), NULL, NULL);
|
||||||
|
clean_all_subkeys (ctrl, keyblock, opt.verbose,
|
||||||
|
(options&EXPORT_MINIMAL)? KEY_CLEAN_ALL
|
||||||
|
/**/ : KEY_CLEAN_AUTHENCR,
|
||||||
|
NULL, NULL);
|
||||||
|
commit_kbnode (&keyblock);
|
||||||
|
}
|
||||||
|
|
||||||
if (export_keep_uid)
|
if (export_keep_uid)
|
||||||
{
|
{
|
||||||
|
49
g10/getkey.c
49
g10/getkey.c
@ -677,6 +677,24 @@ pk_from_block (PKT_public_key *pk, kbnode_t keyblock, kbnode_t found_key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Specialized version of get_pubkey which retrieves the key based on
|
||||||
|
* information in SIG. In contrast to get_pubkey PK is required. */
|
||||||
|
gpg_error_t
|
||||||
|
get_pubkey_for_sig (ctrl_t ctrl, PKT_public_key *pk, PKT_signature *sig)
|
||||||
|
{
|
||||||
|
const byte *fpr;
|
||||||
|
size_t fprlen;
|
||||||
|
|
||||||
|
/* First try the new ISSUER_FPR info. */
|
||||||
|
fpr = issuer_fpr_raw (sig, &fprlen);
|
||||||
|
if (fpr && !get_pubkey_byfprint (ctrl, pk, NULL, fpr, fprlen))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Fallback to use the ISSUER_KEYID. */
|
||||||
|
return get_pubkey (ctrl, pk, sig->keyid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the public key with the key id KEYID and store it at PK.
|
/* Return the public key with the key id KEYID and store it at PK.
|
||||||
* The resources in *PK should be released using
|
* The resources in *PK should be released using
|
||||||
* release_public_key_parts(). This function also stores a copy of
|
* release_public_key_parts(). This function also stores a copy of
|
||||||
@ -739,8 +757,9 @@ get_pubkey (ctrl_t ctrl, PKT_public_key * pk, u32 * keyid)
|
|||||||
/* Do a lookup. */
|
/* Do a lookup. */
|
||||||
{
|
{
|
||||||
struct getkey_ctx_s ctx;
|
struct getkey_ctx_s ctx;
|
||||||
KBNODE kb = NULL;
|
kbnode_t kb = NULL;
|
||||||
KBNODE found_key = NULL;
|
kbnode_t found_key = NULL;
|
||||||
|
|
||||||
memset (&ctx, 0, sizeof ctx);
|
memset (&ctx, 0, sizeof ctx);
|
||||||
ctx.exact = 1; /* Use the key ID exactly as given. */
|
ctx.exact = 1; /* Use the key ID exactly as given. */
|
||||||
ctx.not_allocated = 1;
|
ctx.not_allocated = 1;
|
||||||
@ -863,6 +882,28 @@ get_pubkey_fast (PKT_public_key * pk, u32 * keyid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the entire keyblock used to create SIG. This is a
|
||||||
|
* specialized version of get_pubkeyblock.
|
||||||
|
*
|
||||||
|
* FIXME: This is a hack because get_pubkey_for_sig was already called
|
||||||
|
* and it could have used a cache to hold the key. */
|
||||||
|
kbnode_t
|
||||||
|
get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig)
|
||||||
|
{
|
||||||
|
const byte *fpr;
|
||||||
|
size_t fprlen;
|
||||||
|
kbnode_t keyblock;
|
||||||
|
|
||||||
|
/* First try the new ISSUER_FPR info. */
|
||||||
|
fpr = issuer_fpr_raw (sig, &fprlen);
|
||||||
|
if (fpr && !get_pubkey_byfprint (ctrl, NULL, &keyblock, fpr, fprlen))
|
||||||
|
return keyblock;
|
||||||
|
|
||||||
|
/* Fallback to use the ISSUER_KEYID. */
|
||||||
|
return get_pubkeyblock (ctrl, sig->keyid);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the key block for the key with key id KEYID or NULL, if an
|
/* Return the key block for the key with key id KEYID or NULL, if an
|
||||||
* error occurs. Use release_kbnode() to release the key block.
|
* error occurs. Use release_kbnode() to release the key block.
|
||||||
*
|
*
|
||||||
@ -1802,6 +1843,8 @@ get_pubkey_byfprint (ctrl_t ctrl, PKT_public_key *pk, kbnode_t *r_keyblock,
|
|||||||
memset (&ctx, 0, sizeof ctx);
|
memset (&ctx, 0, sizeof ctx);
|
||||||
ctx.exact = 1;
|
ctx.exact = 1;
|
||||||
ctx.not_allocated = 1;
|
ctx.not_allocated = 1;
|
||||||
|
/* FIXME: We should get the handle from the cache like we do in
|
||||||
|
* get_pubkey. */
|
||||||
ctx.kr_handle = keydb_new ();
|
ctx.kr_handle = keydb_new ();
|
||||||
if (!ctx.kr_handle)
|
if (!ctx.kr_handle)
|
||||||
return gpg_error_from_syserror ();
|
return gpg_error_from_syserror ();
|
||||||
@ -3142,7 +3185,7 @@ buf_to_sig (const byte * buf, size_t len)
|
|||||||
|
|
||||||
if (parse_signature (iobuf, PKT_SIGNATURE, len, sig) != 0)
|
if (parse_signature (iobuf, PKT_SIGNATURE, len, sig) != 0)
|
||||||
{
|
{
|
||||||
xfree (sig);
|
free_seckey_enc (sig);
|
||||||
sig = NULL;
|
sig = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
17
g10/gpg.c
17
g10/gpg.c
@ -150,6 +150,7 @@ enum cmd_and_opt_values
|
|||||||
aSearchKeys,
|
aSearchKeys,
|
||||||
aRefreshKeys,
|
aRefreshKeys,
|
||||||
aFetchKeys,
|
aFetchKeys,
|
||||||
|
aShowKeys,
|
||||||
aExport,
|
aExport,
|
||||||
aExportSecret,
|
aExportSecret,
|
||||||
aExportSecretSub,
|
aExportSecretSub,
|
||||||
@ -500,6 +501,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
N_("update all keys from a keyserver")),
|
N_("update all keys from a keyserver")),
|
||||||
ARGPARSE_c (aLocateKeys, "locate-keys", "@"),
|
ARGPARSE_c (aLocateKeys, "locate-keys", "@"),
|
||||||
ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
|
ARGPARSE_c (aFetchKeys, "fetch-keys" , "@" ),
|
||||||
|
ARGPARSE_c (aShowKeys, "show-keys" , "@" ),
|
||||||
ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
|
ARGPARSE_c (aExportSecret, "export-secret-keys" , "@" ),
|
||||||
ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ),
|
ARGPARSE_c (aExportSecretSub, "export-secret-subkeys" , "@" ),
|
||||||
ARGPARSE_c (aExportSshKey, "export-ssh-key", "@" ),
|
ARGPARSE_c (aExportSshKey, "export-ssh-key", "@" ),
|
||||||
@ -740,6 +742,7 @@ static ARGPARSE_OPTS opts[] = {
|
|||||||
ARGPARSE_c (aListKeys, "list-key", "@"), /* alias */
|
ARGPARSE_c (aListKeys, "list-key", "@"), /* alias */
|
||||||
ARGPARSE_c (aListSigs, "list-sig", "@"), /* alias */
|
ARGPARSE_c (aListSigs, "list-sig", "@"), /* alias */
|
||||||
ARGPARSE_c (aCheckKeys, "check-sig", "@"), /* alias */
|
ARGPARSE_c (aCheckKeys, "check-sig", "@"), /* alias */
|
||||||
|
ARGPARSE_c (aShowKeys, "show-key", "@"), /* alias */
|
||||||
ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"),
|
ARGPARSE_s_n (oSkipVerify, "skip-verify", "@"),
|
||||||
ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"),
|
ARGPARSE_s_n (oSkipHiddenRecipients, "skip-hidden-recipients", "@"),
|
||||||
ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
|
ARGPARSE_s_n (oNoSkipHiddenRecipients, "no-skip-hidden-recipients", "@"),
|
||||||
@ -2642,6 +2645,17 @@ main (int argc, char **argv)
|
|||||||
greeting=1;
|
greeting=1;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case aShowKeys:
|
||||||
|
set_cmd (&cmd, pargs.r_opt);
|
||||||
|
opt.import_options |= IMPORT_SHOW;
|
||||||
|
opt.import_options |= IMPORT_DRY_RUN;
|
||||||
|
opt.import_options &= ~IMPORT_REPAIR_KEYS;
|
||||||
|
opt.list_options |= LIST_SHOW_UNUSABLE_UIDS;
|
||||||
|
opt.list_options |= LIST_SHOW_UNUSABLE_SUBKEYS;
|
||||||
|
opt.list_options |= LIST_SHOW_NOTATIONS;
|
||||||
|
opt.list_options |= LIST_SHOW_POLICY_URLS;
|
||||||
|
break;
|
||||||
|
|
||||||
case aDetachedSign: detached_sig = 1; set_cmd( &cmd, aSign ); break;
|
case aDetachedSign: detached_sig = 1; set_cmd( &cmd, aSign ); break;
|
||||||
|
|
||||||
case aDecryptFiles: multifile=1; /* fall through */
|
case aDecryptFiles: multifile=1; /* fall through */
|
||||||
@ -3611,7 +3625,7 @@ main (int argc, char **argv)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
pargs.err = ARGPARSE_PRINT_ERROR;
|
pargs.err = ARGPARSE_PRINT_ERROR;
|
||||||
/* The argparse fucntion calls a plain exit and thus
|
/* The argparse function calls a plain exit and thus
|
||||||
* we need to print a status here. */
|
* we need to print a status here. */
|
||||||
write_status_failure ("option-parser",
|
write_status_failure ("option-parser",
|
||||||
gpg_error(GPG_ERR_GENERAL));
|
gpg_error(GPG_ERR_GENERAL));
|
||||||
@ -4638,6 +4652,7 @@ main (int argc, char **argv)
|
|||||||
case aFastImport:
|
case aFastImport:
|
||||||
opt.import_options |= IMPORT_FAST; /* fall through */
|
opt.import_options |= IMPORT_FAST; /* fall through */
|
||||||
case aImport:
|
case aImport:
|
||||||
|
case aShowKeys:
|
||||||
import_keys (ctrl, argc? argv:NULL, argc, NULL,
|
import_keys (ctrl, argc? argv:NULL, argc, NULL,
|
||||||
opt.import_options, opt.key_origin, opt.key_origin_url);
|
opt.import_options, opt.key_origin, opt.key_origin_url);
|
||||||
break;
|
break;
|
||||||
|
@ -1835,7 +1835,7 @@ signature (const char *option, int argc, char *argv[], void *cookie)
|
|||||||
debug ("Wrote signature packet:\n");
|
debug ("Wrote signature packet:\n");
|
||||||
dump_component (&pkt);
|
dump_component (&pkt);
|
||||||
|
|
||||||
xfree (sig);
|
free_seckey_enc (sig);
|
||||||
release_kbnode (si.issuer_kb);
|
release_kbnode (si.issuer_kb);
|
||||||
xfree (si.revocation_key);
|
xfree (si.revocation_key);
|
||||||
|
|
||||||
|
15
g10/gpgv.c
15
g10/gpgv.c
@ -772,3 +772,18 @@ tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||||
|
char **r_comment, size_t *r_commentlen)
|
||||||
|
{
|
||||||
|
(void)sig;
|
||||||
|
(void)r_commentlen;
|
||||||
|
|
||||||
|
if (r_reason)
|
||||||
|
*r_reason = NULL;
|
||||||
|
if (r_comment)
|
||||||
|
*r_comment = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
550
g10/import.c
550
g10/import.c
@ -41,6 +41,7 @@
|
|||||||
#include "../common/init.h"
|
#include "../common/init.h"
|
||||||
#include "../common/mbox-util.h"
|
#include "../common/mbox-util.h"
|
||||||
#include "key-check.h"
|
#include "key-check.h"
|
||||||
|
#include "key-clean.h"
|
||||||
|
|
||||||
|
|
||||||
struct import_stats_s
|
struct import_stats_s
|
||||||
@ -113,8 +114,8 @@ static int import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
|
|||||||
struct import_stats_s *stats, int batch,
|
struct import_stats_s *stats, int batch,
|
||||||
unsigned int options, int for_migration,
|
unsigned int options, int for_migration,
|
||||||
import_screener_t screener, void *screener_arg);
|
import_screener_t screener, void *screener_arg);
|
||||||
static int import_revoke_cert (ctrl_t ctrl,
|
static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
|
||||||
kbnode_t node, struct import_stats_s *stats);
|
struct import_stats_s *stats);
|
||||||
static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
||||||
int *non_self);
|
int *non_self);
|
||||||
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
|
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
|
||||||
@ -494,7 +495,9 @@ import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
|
|||||||
|
|
||||||
if (!stats_handle)
|
if (!stats_handle)
|
||||||
{
|
{
|
||||||
import_print_stats (stats);
|
if ((options & (IMPORT_SHOW | IMPORT_DRY_RUN))
|
||||||
|
!= (IMPORT_SHOW | IMPORT_DRY_RUN))
|
||||||
|
import_print_stats (stats);
|
||||||
import_release_stats_handle (stats);
|
import_release_stats_handle (stats);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,7 +591,7 @@ import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
|
|||||||
screener, screener_arg);
|
screener, screener_arg);
|
||||||
else if (keyblock->pkt->pkttype == PKT_SIGNATURE
|
else if (keyblock->pkt->pkttype == PKT_SIGNATURE
|
||||||
&& IS_KEY_REV (keyblock->pkt->pkt.signature) )
|
&& IS_KEY_REV (keyblock->pkt->pkt.signature) )
|
||||||
rc = import_revoke_cert (ctrl, keyblock, stats);
|
rc = import_revoke_cert (ctrl, keyblock, options, stats);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
|
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
|
||||||
@ -778,7 +781,7 @@ read_block( IOBUF a, int with_meta,
|
|||||||
struct parse_packet_ctx_s parsectx;
|
struct parse_packet_ctx_s parsectx;
|
||||||
PACKET *pkt;
|
PACKET *pkt;
|
||||||
kbnode_t root = NULL;
|
kbnode_t root = NULL;
|
||||||
int in_cert, in_v3key;
|
int in_cert, in_v3key, skip_sigs;
|
||||||
|
|
||||||
*r_v3keys = 0;
|
*r_v3keys = 0;
|
||||||
|
|
||||||
@ -797,6 +800,7 @@ read_block( IOBUF a, int with_meta,
|
|||||||
if (!with_meta)
|
if (!with_meta)
|
||||||
parsectx.skip_meta = 1;
|
parsectx.skip_meta = 1;
|
||||||
in_v3key = 0;
|
in_v3key = 0;
|
||||||
|
skip_sigs = 0;
|
||||||
while ((rc=parse_packet (&parsectx, pkt)) != -1)
|
while ((rc=parse_packet (&parsectx, pkt)) != -1)
|
||||||
{
|
{
|
||||||
if (rc && (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY
|
if (rc && (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY
|
||||||
@ -811,8 +815,25 @@ read_block( IOBUF a, int with_meta,
|
|||||||
}
|
}
|
||||||
else if (rc ) /* (ignore errors) */
|
else if (rc ) /* (ignore errors) */
|
||||||
{
|
{
|
||||||
|
skip_sigs = 0;
|
||||||
if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET)
|
if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET)
|
||||||
; /* Do not show a diagnostic. */
|
; /* Do not show a diagnostic. */
|
||||||
|
else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
|
||||||
|
&& (pkt->pkttype == PKT_USER_ID
|
||||||
|
|| pkt->pkttype == PKT_ATTRIBUTE))
|
||||||
|
{
|
||||||
|
/* This indicates a too large user id or attribute
|
||||||
|
* packet. We skip this packet and all following
|
||||||
|
* signatures. Sure, this won't allow to repair a
|
||||||
|
* garbled keyring in case one of the signatures belong
|
||||||
|
* to another user id. However, this better mitigates
|
||||||
|
* DoS using inserted user ids. */
|
||||||
|
skip_sigs = 1;
|
||||||
|
}
|
||||||
|
else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
|
||||||
|
&& (pkt->pkttype == PKT_OLD_COMMENT
|
||||||
|
|| pkt->pkttype == PKT_COMMENT))
|
||||||
|
; /* Ignore too large comment packets. */
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
log_error("read_block: read error: %s\n", gpg_strerror (rc) );
|
log_error("read_block: read error: %s\n", gpg_strerror (rc) );
|
||||||
@ -824,76 +845,88 @@ read_block( IOBUF a, int with_meta,
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY
|
if (skip_sigs)
|
||||||
|| pkt->pkttype == PKT_SECRET_KEY))
|
{
|
||||||
{
|
if (pkt->pkttype == PKT_SIGNATURE)
|
||||||
free_packet (pkt, &parsectx);
|
{
|
||||||
init_packet(pkt);
|
free_packet (pkt, &parsectx);
|
||||||
continue;
|
init_packet (pkt);
|
||||||
}
|
continue;
|
||||||
in_v3key = 0;
|
}
|
||||||
|
skip_sigs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (!root && pkt->pkttype == PKT_SIGNATURE
|
if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
&& IS_KEY_REV (pkt->pkt.signature) )
|
|| pkt->pkttype == PKT_SECRET_KEY))
|
||||||
{
|
{
|
||||||
/* This is a revocation certificate which is handled in a
|
free_packet (pkt, &parsectx);
|
||||||
* special way. */
|
init_packet(pkt);
|
||||||
root = new_kbnode( pkt );
|
continue;
|
||||||
pkt = NULL;
|
}
|
||||||
goto ready;
|
in_v3key = 0;
|
||||||
}
|
|
||||||
|
|
||||||
/* Make a linked list of all packets. */
|
if (!root && pkt->pkttype == PKT_SIGNATURE
|
||||||
switch (pkt->pkttype)
|
&& IS_KEY_REV (pkt->pkt.signature) )
|
||||||
{
|
{
|
||||||
case PKT_COMPRESSED:
|
/* This is a revocation certificate which is handled in a
|
||||||
if (check_compress_algo (pkt->pkt.compressed->algorithm))
|
* special way. */
|
||||||
{
|
root = new_kbnode( pkt );
|
||||||
rc = GPG_ERR_COMPR_ALGO;
|
pkt = NULL;
|
||||||
goto ready;
|
goto ready;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
|
|
||||||
pkt->pkt.compressed->buf = NULL;
|
|
||||||
if (push_compress_filter2 (a, cfx,
|
|
||||||
pkt->pkt.compressed->algorithm, 1))
|
|
||||||
xfree (cfx); /* e.g. in case of compression_algo NONE. */
|
|
||||||
}
|
|
||||||
free_packet (pkt, &parsectx);
|
|
||||||
init_packet(pkt);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case PKT_RING_TRUST:
|
/* Make a linked list of all packets. */
|
||||||
/* Skip those packets unless we are in restore mode. */
|
switch (pkt->pkttype)
|
||||||
if ((opt.import_options & IMPORT_RESTORE))
|
{
|
||||||
goto x_default;
|
case PKT_COMPRESSED:
|
||||||
free_packet (pkt, &parsectx);
|
if (check_compress_algo (pkt->pkt.compressed->algorithm))
|
||||||
init_packet(pkt);
|
{
|
||||||
break;
|
rc = GPG_ERR_COMPR_ALGO;
|
||||||
|
goto ready;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
|
||||||
|
pkt->pkt.compressed->buf = NULL;
|
||||||
|
if (push_compress_filter2 (a, cfx,
|
||||||
|
pkt->pkt.compressed->algorithm, 1))
|
||||||
|
xfree (cfx); /* e.g. in case of compression_algo NONE. */
|
||||||
|
}
|
||||||
|
free_packet (pkt, &parsectx);
|
||||||
|
init_packet(pkt);
|
||||||
|
break;
|
||||||
|
|
||||||
case PKT_PUBLIC_KEY:
|
case PKT_RING_TRUST:
|
||||||
case PKT_SECRET_KEY:
|
/* Skip those packets unless we are in restore mode. */
|
||||||
if (in_cert ) /* Store this packet. */
|
if ((opt.import_options & IMPORT_RESTORE))
|
||||||
{
|
goto x_default;
|
||||||
*pending_pkt = pkt;
|
free_packet (pkt, &parsectx);
|
||||||
pkt = NULL;
|
init_packet(pkt);
|
||||||
goto ready;
|
break;
|
||||||
}
|
|
||||||
in_cert = 1; /* fall through */
|
case PKT_PUBLIC_KEY:
|
||||||
default:
|
case PKT_SECRET_KEY:
|
||||||
x_default:
|
if (in_cert ) /* Store this packet. */
|
||||||
if (in_cert && valid_keyblock_packet (pkt->pkttype))
|
{
|
||||||
{
|
*pending_pkt = pkt;
|
||||||
if (!root )
|
pkt = NULL;
|
||||||
root = new_kbnode (pkt);
|
goto ready;
|
||||||
else
|
}
|
||||||
add_kbnode (root, new_kbnode (pkt));
|
in_cert = 1;
|
||||||
pkt = xmalloc (sizeof *pkt);
|
/* fall through */
|
||||||
}
|
default:
|
||||||
init_packet(pkt);
|
x_default:
|
||||||
break;
|
if (in_cert && valid_keyblock_packet (pkt->pkttype))
|
||||||
}
|
{
|
||||||
|
if (!root )
|
||||||
|
root = new_kbnode (pkt);
|
||||||
|
else
|
||||||
|
add_kbnode (root, new_kbnode (pkt));
|
||||||
|
pkt = xmalloc (sizeof *pkt);
|
||||||
|
}
|
||||||
|
init_packet(pkt);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ready:
|
ready:
|
||||||
@ -1312,6 +1345,16 @@ impex_filter_getval (void *cookie, const char *propname)
|
|||||||
{
|
{
|
||||||
result = pk_is_disabled (pk)? "1":"0";
|
result = pk_is_disabled (pk)? "1":"0";
|
||||||
}
|
}
|
||||||
|
else if (!strcmp (propname, "usage"))
|
||||||
|
{
|
||||||
|
snprintf (numbuf, sizeof numbuf, "%s%s%s%s%s",
|
||||||
|
(pk->pubkey_usage & PUBKEY_USAGE_ENC)?"e":"",
|
||||||
|
(pk->pubkey_usage & PUBKEY_USAGE_SIG)?"s":"",
|
||||||
|
(pk->pubkey_usage & PUBKEY_USAGE_CERT)?"c":"",
|
||||||
|
(pk->pubkey_usage & PUBKEY_USAGE_AUTH)?"a":"",
|
||||||
|
(pk->pubkey_usage & PUBKEY_USAGE_UNKNOWN)?"?":"");
|
||||||
|
result = numbuf;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
result = NULL;
|
result = NULL;
|
||||||
}
|
}
|
||||||
@ -1653,6 +1696,10 @@ import_one (ctrl_t ctrl,
|
|||||||
int any_filter = 0;
|
int any_filter = 0;
|
||||||
KEYDB_HANDLE hd = NULL;
|
KEYDB_HANDLE hd = NULL;
|
||||||
|
|
||||||
|
/* If show-only is active we don't won't any extra output. */
|
||||||
|
if ((options & (IMPORT_SHOW | IMPORT_DRY_RUN)))
|
||||||
|
silent = 1;
|
||||||
|
|
||||||
/* Get the key and print some info about it. */
|
/* Get the key and print some info about it. */
|
||||||
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
||||||
if (!node )
|
if (!node )
|
||||||
@ -1712,9 +1759,14 @@ import_one (ctrl_t ctrl,
|
|||||||
that we have to clean later. This has no practical impact on the
|
that we have to clean later. This has no practical impact on the
|
||||||
end result, but does result in less logging which might confuse
|
end result, but does result in less logging which might confuse
|
||||||
the user. */
|
the user. */
|
||||||
if (options&IMPORT_CLEAN)
|
if ((options & IMPORT_CLEAN))
|
||||||
clean_key (ctrl, keyblock,
|
{
|
||||||
opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL);
|
merge_keys_and_selfsig (ctrl, keyblock);
|
||||||
|
clean_all_uids (ctrl, keyblock,
|
||||||
|
opt.verbose, (options&IMPORT_MINIMAL), NULL, NULL);
|
||||||
|
clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
clear_kbnode_flags( keyblock );
|
clear_kbnode_flags( keyblock );
|
||||||
|
|
||||||
@ -1855,8 +1907,13 @@ import_one (ctrl_t ctrl,
|
|||||||
log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) );
|
log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) );
|
||||||
|
|
||||||
if ((options & IMPORT_CLEAN))
|
if ((options & IMPORT_CLEAN))
|
||||||
clean_key (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL),
|
{
|
||||||
&n_uids_cleaned,&n_sigs_cleaned);
|
merge_keys_and_selfsig (ctrl, keyblock);
|
||||||
|
clean_all_uids (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL),
|
||||||
|
&n_uids_cleaned,&n_sigs_cleaned);
|
||||||
|
clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Unless we are in restore mode apply meta data to the
|
/* Unless we are in restore mode apply meta data to the
|
||||||
* keyblock. Note that this will never change the first packet
|
* keyblock. Note that this will never change the first packet
|
||||||
@ -1941,8 +1998,14 @@ import_one (ctrl_t ctrl,
|
|||||||
goto leave;
|
goto leave;
|
||||||
|
|
||||||
if ((options & IMPORT_CLEAN))
|
if ((options & IMPORT_CLEAN))
|
||||||
clean_key (ctrl, keyblock_orig, opt.verbose, (options&IMPORT_MINIMAL),
|
{
|
||||||
&n_uids_cleaned,&n_sigs_cleaned);
|
merge_keys_and_selfsig (ctrl, keyblock_orig);
|
||||||
|
clean_all_uids (ctrl, keyblock_orig, opt.verbose,
|
||||||
|
(options&IMPORT_MINIMAL),
|
||||||
|
&n_uids_cleaned,&n_sigs_cleaned);
|
||||||
|
clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, KEY_CLEAN_NONE,
|
||||||
|
NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned)
|
if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned)
|
||||||
{
|
{
|
||||||
@ -2616,11 +2679,216 @@ import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Return the recocation reason from signature SIG. If no revocation
|
||||||
|
* reason is availabale 0 is returned, in other cases the reason
|
||||||
|
* (0..255). If R_REASON is not NULL a malloced textual
|
||||||
|
* representation of the code is stored there. If R_COMMENT is not
|
||||||
|
* NULL the comment from the reason is stored there and its length at
|
||||||
|
* R_COMMENTLEN. Note that the value at R_COMMENT is not filtered but
|
||||||
|
* user supplied data in UTF8; thus it needs to be escaped for display
|
||||||
|
* purposes. Both return values are either NULL or a malloced
|
||||||
|
* string/buffer. */
|
||||||
|
int
|
||||||
|
get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||||
|
char **r_comment, size_t *r_commentlen)
|
||||||
|
{
|
||||||
|
int reason_seq = 0;
|
||||||
|
size_t reason_n;
|
||||||
|
const byte *reason_p;
|
||||||
|
char reason_code_buf[20];
|
||||||
|
const char *reason_text = NULL;
|
||||||
|
int reason_code = 0;
|
||||||
|
|
||||||
|
if (r_reason)
|
||||||
|
*r_reason = NULL;
|
||||||
|
if (r_comment)
|
||||||
|
*r_comment = NULL;
|
||||||
|
|
||||||
|
/* Skip over empty reason packets. */
|
||||||
|
while ((reason_p = enum_sig_subpkt (sig->hashed, SIGSUBPKT_REVOC_REASON,
|
||||||
|
&reason_n, &reason_seq, NULL))
|
||||||
|
&& !reason_n)
|
||||||
|
;
|
||||||
|
if (reason_p)
|
||||||
|
{
|
||||||
|
reason_code = *reason_p;
|
||||||
|
reason_n--; reason_p++;
|
||||||
|
switch (reason_code)
|
||||||
|
{
|
||||||
|
case 0x00: reason_text = _("No reason specified"); break;
|
||||||
|
case 0x01: reason_text = _("Key is superseded"); break;
|
||||||
|
case 0x02: reason_text = _("Key has been compromised"); break;
|
||||||
|
case 0x03: reason_text = _("Key is no longer used"); break;
|
||||||
|
case 0x20: reason_text = _("User ID is no longer valid"); break;
|
||||||
|
default:
|
||||||
|
snprintf (reason_code_buf, sizeof reason_code_buf,
|
||||||
|
"code=%02x", reason_code);
|
||||||
|
reason_text = reason_code_buf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (r_reason)
|
||||||
|
*r_reason = xstrdup (reason_text);
|
||||||
|
|
||||||
|
if (r_comment && reason_n)
|
||||||
|
{
|
||||||
|
*r_comment = xmalloc (reason_n);
|
||||||
|
memcpy (*r_comment, reason_p, reason_n);
|
||||||
|
*r_commentlen = reason_n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reason_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* List the recocation signature as a "rvs" record. SIGRC shows the
|
||||||
|
* character from the signature verification or 0 if no public key was
|
||||||
|
* found. */
|
||||||
|
static void
|
||||||
|
list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc)
|
||||||
|
{
|
||||||
|
char *siguid = NULL;
|
||||||
|
size_t siguidlen = 0;
|
||||||
|
char *issuer_fpr = NULL;
|
||||||
|
int reason_code = 0;
|
||||||
|
char *reason_text = NULL;
|
||||||
|
char *reason_comment = NULL;
|
||||||
|
size_t reason_commentlen;
|
||||||
|
|
||||||
|
if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode)
|
||||||
|
{
|
||||||
|
int nouid;
|
||||||
|
siguid = get_user_id (ctrl, sig->keyid, &siguidlen, &nouid);
|
||||||
|
if (nouid)
|
||||||
|
sigrc = '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
reason_code = get_revocation_reason (sig, &reason_text,
|
||||||
|
&reason_comment, &reason_commentlen);
|
||||||
|
|
||||||
|
if (opt.with_colons)
|
||||||
|
{
|
||||||
|
es_fputs ("rvs:", es_stdout);
|
||||||
|
if (sigrc)
|
||||||
|
es_putc (sigrc, es_stdout);
|
||||||
|
es_fprintf (es_stdout, "::%d:%08lX%08lX:%s:%s:::",
|
||||||
|
sig->pubkey_algo,
|
||||||
|
(ulong) sig->keyid[0], (ulong) sig->keyid[1],
|
||||||
|
colon_datestr_from_sig (sig),
|
||||||
|
colon_expirestr_from_sig (sig));
|
||||||
|
|
||||||
|
if (siguid)
|
||||||
|
es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL);
|
||||||
|
|
||||||
|
es_fprintf (es_stdout, ":%02x%c", sig->sig_class,
|
||||||
|
sig->flags.exportable ? 'x' : 'l');
|
||||||
|
if (reason_text)
|
||||||
|
es_fprintf (es_stdout, ",%02x", reason_code);
|
||||||
|
es_fputs ("::", es_stdout);
|
||||||
|
|
||||||
|
if ((issuer_fpr = issuer_fpr_string (sig)))
|
||||||
|
es_fputs (issuer_fpr, es_stdout);
|
||||||
|
|
||||||
|
es_fprintf (es_stdout, ":::%d:", sig->digest_algo);
|
||||||
|
|
||||||
|
if (reason_comment)
|
||||||
|
{
|
||||||
|
es_fputs ("::::", es_stdout);
|
||||||
|
es_write_sanitized (es_stdout, reason_comment, reason_commentlen,
|
||||||
|
":", NULL);
|
||||||
|
es_putc (':', es_stdout);
|
||||||
|
}
|
||||||
|
es_putc ('\n', es_stdout);
|
||||||
|
|
||||||
|
if (opt.show_subpackets)
|
||||||
|
print_subpackets_colon (sig);
|
||||||
|
}
|
||||||
|
else /* Human readable. */
|
||||||
|
{
|
||||||
|
es_fputs ("rvs", es_stdout);
|
||||||
|
es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s",
|
||||||
|
sigrc, (sig->sig_class - 0x10 > 0 &&
|
||||||
|
sig->sig_class - 0x10 <
|
||||||
|
4) ? '0' + sig->sig_class - 0x10 : ' ',
|
||||||
|
sig->flags.exportable ? ' ' : 'L',
|
||||||
|
sig->flags.revocable ? ' ' : 'R',
|
||||||
|
sig->flags.policy_url ? 'P' : ' ',
|
||||||
|
sig->flags.notation ? 'N' : ' ',
|
||||||
|
sig->flags.expired ? 'X' : ' ',
|
||||||
|
(sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
|
||||||
|
0) ? '0' +
|
||||||
|
sig->trust_depth : ' ', keystr (sig->keyid),
|
||||||
|
datestr_from_sig (sig));
|
||||||
|
if (siguid)
|
||||||
|
{
|
||||||
|
es_fprintf (es_stdout, " ");
|
||||||
|
print_utf8_buffer (es_stdout, siguid, siguidlen);
|
||||||
|
}
|
||||||
|
es_putc ('\n', es_stdout);
|
||||||
|
|
||||||
|
if (sig->flags.policy_url
|
||||||
|
&& (opt.list_options & LIST_SHOW_POLICY_URLS))
|
||||||
|
show_policy_url (sig, 3, 0);
|
||||||
|
|
||||||
|
if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
|
||||||
|
show_notation (sig, 3, 0,
|
||||||
|
((opt.list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0)
|
||||||
|
+
|
||||||
|
((opt.list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0));
|
||||||
|
|
||||||
|
if (sig->flags.pref_ks
|
||||||
|
&& (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
||||||
|
show_keyserver_url (sig, 3, 0);
|
||||||
|
|
||||||
|
if (reason_text)
|
||||||
|
{
|
||||||
|
es_fprintf (es_stdout, " %s%s\n",
|
||||||
|
_("reason for revocation: "), reason_text);
|
||||||
|
if (reason_comment)
|
||||||
|
{
|
||||||
|
const byte *s, *s_lf;
|
||||||
|
size_t n, n_lf;
|
||||||
|
|
||||||
|
s = reason_comment;
|
||||||
|
n = reason_commentlen;
|
||||||
|
s_lf = NULL;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* We don't want any empty lines, so we skip them. */
|
||||||
|
for (;n && *s == '\n'; s++, n--)
|
||||||
|
;
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
s_lf = memchr (s, '\n', n);
|
||||||
|
n_lf = s_lf? s_lf - s : n;
|
||||||
|
es_fprintf (es_stdout, " %s",
|
||||||
|
_("revocation comment: "));
|
||||||
|
es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
|
||||||
|
es_putc ('\n', es_stdout);
|
||||||
|
s += n_lf; n -= n_lf;
|
||||||
|
}
|
||||||
|
} while (s_lf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
es_fflush (es_stdout);
|
||||||
|
|
||||||
|
xfree (reason_text);
|
||||||
|
xfree (reason_comment);
|
||||||
|
xfree (siguid);
|
||||||
|
xfree (issuer_fpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************
|
/****************
|
||||||
* Import a revocation certificate; this is a single signature packet.
|
* Import a revocation certificate; this is a single signature packet.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
|
||||||
|
struct import_stats_s *stats)
|
||||||
{
|
{
|
||||||
PKT_public_key *pk = NULL;
|
PKT_public_key *pk = NULL;
|
||||||
kbnode_t onode;
|
kbnode_t onode;
|
||||||
@ -2628,6 +2896,11 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||||||
KEYDB_HANDLE hd = NULL;
|
KEYDB_HANDLE hd = NULL;
|
||||||
u32 keyid[2];
|
u32 keyid[2];
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
|
int sigrc = 0;
|
||||||
|
int silent;
|
||||||
|
|
||||||
|
/* No error output for --show-keys. */
|
||||||
|
silent = (options & (IMPORT_SHOW | IMPORT_DRY_RUN));
|
||||||
|
|
||||||
log_assert (!node->next );
|
log_assert (!node->next );
|
||||||
log_assert (node->pkt->pkttype == PKT_SIGNATURE );
|
log_assert (node->pkt->pkttype == PKT_SIGNATURE );
|
||||||
@ -2640,15 +2913,16 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||||||
rc = get_pubkey (ctrl, pk, keyid );
|
rc = get_pubkey (ctrl, pk, keyid );
|
||||||
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY )
|
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY )
|
||||||
{
|
{
|
||||||
log_error(_("key %s: no public key -"
|
if (!silent)
|
||||||
" can't apply revocation certificate\n"), keystr(keyid));
|
log_error (_("key %s: no public key -"
|
||||||
|
" can't apply revocation certificate\n"), keystr(keyid));
|
||||||
rc = 0;
|
rc = 0;
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
else if (rc )
|
else if (rc )
|
||||||
{
|
{
|
||||||
log_error(_("key %s: public key not found: %s\n"),
|
log_error (_("key %s: public key not found: %s\n"),
|
||||||
keystr(keyid), gpg_strerror (rc));
|
keystr(keyid), gpg_strerror (rc));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2685,12 +2959,21 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||||||
|
|
||||||
/* it is okay, that node is not in keyblock because
|
/* it is okay, that node is not in keyblock because
|
||||||
* check_key_signature works fine for sig_class 0x20 (KEY_REV) in
|
* check_key_signature works fine for sig_class 0x20 (KEY_REV) in
|
||||||
* this special case. */
|
* this special case. SIGRC is only used for IMPORT_SHOW. */
|
||||||
rc = check_key_signature (ctrl, keyblock, node, NULL);
|
rc = check_key_signature (ctrl, keyblock, node, NULL);
|
||||||
|
switch (gpg_err_code (rc))
|
||||||
|
{
|
||||||
|
case 0: sigrc = '!'; break;
|
||||||
|
case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break;
|
||||||
|
case GPG_ERR_NO_PUBKEY: sigrc = '?'; break;
|
||||||
|
case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break;
|
||||||
|
default: sigrc = '%'; break;
|
||||||
|
}
|
||||||
if (rc )
|
if (rc )
|
||||||
{
|
{
|
||||||
log_error( _("key %s: invalid revocation certificate"
|
if (!silent)
|
||||||
": %s - rejected\n"), keystr(keyid), gpg_strerror (rc));
|
log_error (_("key %s: invalid revocation certificate"
|
||||||
|
": %s - rejected\n"), keystr(keyid), gpg_strerror (rc));
|
||||||
goto leave;
|
goto leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2710,33 +2993,39 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||||||
/* insert it */
|
/* insert it */
|
||||||
insert_kbnode( keyblock, clone_kbnode(node), 0 );
|
insert_kbnode( keyblock, clone_kbnode(node), 0 );
|
||||||
|
|
||||||
/* and write the keyblock back */
|
/* and write the keyblock back unless in dry run mode. */
|
||||||
rc = keydb_update_keyblock (ctrl, hd, keyblock );
|
if (!(opt.dry_run || (options & IMPORT_DRY_RUN)))
|
||||||
if (rc)
|
|
||||||
log_error (_("error writing keyring '%s': %s\n"),
|
|
||||||
keydb_get_resource_name (hd), gpg_strerror (rc) );
|
|
||||||
keydb_release (hd);
|
|
||||||
hd = NULL;
|
|
||||||
|
|
||||||
/* we are ready */
|
|
||||||
if (!opt.quiet )
|
|
||||||
{
|
{
|
||||||
char *p=get_user_id_native (ctrl, keyid);
|
rc = keydb_update_keyblock (ctrl, hd, keyblock );
|
||||||
log_info( _("key %s: \"%s\" revocation certificate imported\n"),
|
if (rc)
|
||||||
keystr(keyid),p);
|
log_error (_("error writing keyring '%s': %s\n"),
|
||||||
xfree(p);
|
keydb_get_resource_name (hd), gpg_strerror (rc) );
|
||||||
|
keydb_release (hd);
|
||||||
|
hd = NULL;
|
||||||
|
|
||||||
|
/* we are ready */
|
||||||
|
if (!opt.quiet )
|
||||||
|
{
|
||||||
|
char *p=get_user_id_native (ctrl, keyid);
|
||||||
|
log_info( _("key %s: \"%s\" revocation certificate imported\n"),
|
||||||
|
keystr(keyid),p);
|
||||||
|
xfree(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the key we just revoked was ultimately trusted, remove its
|
||||||
|
* ultimate trust. This doesn't stop the user from putting the
|
||||||
|
* ultimate trust back, but is a reasonable solution for now. */
|
||||||
|
if (get_ownertrust (ctrl, pk) == TRUST_ULTIMATE)
|
||||||
|
clear_ownertrusts (ctrl, pk);
|
||||||
|
|
||||||
|
revalidation_mark (ctrl);
|
||||||
}
|
}
|
||||||
stats->n_revoc++;
|
stats->n_revoc++;
|
||||||
|
|
||||||
/* If the key we just revoked was ultimately trusted, remove its
|
|
||||||
ultimate trust. This doesn't stop the user from putting the
|
|
||||||
ultimate trust back, but is a reasonable solution for now. */
|
|
||||||
if (get_ownertrust (ctrl, pk) == TRUST_ULTIMATE)
|
|
||||||
clear_ownertrusts (ctrl, pk);
|
|
||||||
|
|
||||||
revalidation_mark (ctrl);
|
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
|
if ((options & IMPORT_SHOW))
|
||||||
|
list_standalone_revocation (ctrl, node->pkt->pkt.signature, sigrc);
|
||||||
|
|
||||||
keydb_release (hd);
|
keydb_release (hd);
|
||||||
release_kbnode( keyblock );
|
release_kbnode( keyblock );
|
||||||
free_public_key( pk );
|
free_public_key( pk );
|
||||||
@ -2744,8 +3033,9 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Loop over the keyblock and check all self signatures. On return
|
/* Loop over the KEYBLOCK and check all self signatures. KEYID is the
|
||||||
* the following bis in the node flags are set:
|
* keyid of the primary key for reporting purposes. On return the
|
||||||
|
* following bits in the node flags are set:
|
||||||
*
|
*
|
||||||
* - NODE_GOOD_SELFSIG :: User ID or subkey has a self-signature
|
* - NODE_GOOD_SELFSIG :: User ID or subkey has a self-signature
|
||||||
* - NODE_BAD_SELFSIG :: Used ID or subkey has an invalid self-signature
|
* - NODE_BAD_SELFSIG :: Used ID or subkey has an invalid self-signature
|
||||||
@ -2760,17 +3050,22 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, struct import_stats_s *stats)
|
|||||||
static int
|
static int
|
||||||
chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
|
chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
|
||||||
{
|
{
|
||||||
kbnode_t n, knode = NULL;
|
kbnode_t knode = NULL; /* The node of the current subkey. */
|
||||||
|
PKT_public_key *subpk = NULL; /* and its packet. */
|
||||||
|
kbnode_t bsnode = NULL; /* Subkey binding signature node. */
|
||||||
|
u32 bsdate = 0; /* Timestamp of that node. */
|
||||||
|
kbnode_t rsnode = NULL; /* Subkey recocation signature node. */
|
||||||
|
u32 rsdate = 0; /* Timestamp of tha node. */
|
||||||
PKT_signature *sig;
|
PKT_signature *sig;
|
||||||
int rc;
|
int rc;
|
||||||
u32 bsdate=0, rsdate=0;
|
kbnode_t n;
|
||||||
kbnode_t bsnode = NULL, rsnode = NULL;
|
|
||||||
|
|
||||||
for (n=keyblock; (n = find_next_kbnode (n, 0)); )
|
for (n=keyblock; (n = find_next_kbnode (n, 0)); )
|
||||||
{
|
{
|
||||||
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
||||||
{
|
{
|
||||||
knode = n;
|
knode = n;
|
||||||
|
subpk = knode->pkt->pkt.public_key;
|
||||||
bsdate = 0;
|
bsdate = 0;
|
||||||
rsdate = 0;
|
rsdate = 0;
|
||||||
bsnode = NULL;
|
bsnode = NULL;
|
||||||
@ -2859,11 +3154,14 @@ chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
|
|||||||
if ( rc )
|
if ( rc )
|
||||||
{
|
{
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ?
|
{
|
||||||
_("key %s: unsupported public key"
|
keyid_from_pk (subpk, NULL);
|
||||||
" algorithm\n"):
|
log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ?
|
||||||
_("key %s: invalid subkey binding\n"),
|
_("key %s: unsupported public key"
|
||||||
keystr (keyid));
|
" algorithm\n"):
|
||||||
|
_("key %s: invalid subkey binding\n"),
|
||||||
|
keystr_with_sub (keyid, subpk->keyid));
|
||||||
|
}
|
||||||
n->flag |= NODE_DELETION_MARK;
|
n->flag |= NODE_DELETION_MARK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -2878,8 +3176,12 @@ chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
|
|||||||
one is newer */
|
one is newer */
|
||||||
bsnode->flag |= NODE_DELETION_MARK;
|
bsnode->flag |= NODE_DELETION_MARK;
|
||||||
if (opt.verbose)
|
if (opt.verbose)
|
||||||
log_info (_("key %s: removed multiple subkey"
|
{
|
||||||
" binding\n"),keystr(keyid));
|
keyid_from_pk (subpk, NULL);
|
||||||
|
log_info (_("key %s: removed multiple subkey"
|
||||||
|
" binding\n"),
|
||||||
|
keystr_with_sub (keyid, subpk->keyid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bsnode = n;
|
bsnode = n;
|
||||||
@ -2958,6 +3260,7 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
|||||||
{
|
{
|
||||||
kbnode_t node;
|
kbnode_t node;
|
||||||
int nvalid=0, uid_seen=0, subkey_seen=0;
|
int nvalid=0, uid_seen=0, subkey_seen=0;
|
||||||
|
PKT_public_key *pk;
|
||||||
|
|
||||||
for (node=keyblock->next; node; node = node->next )
|
for (node=keyblock->next; node; node = node->next )
|
||||||
{
|
{
|
||||||
@ -2995,7 +3298,12 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
|||||||
|| !(node->flag & NODE_GOOD_SELFSIG))
|
|| !(node->flag & NODE_GOOD_SELFSIG))
|
||||||
{
|
{
|
||||||
if (opt.verbose )
|
if (opt.verbose )
|
||||||
log_info( _("key %s: skipped subkey\n"),keystr(keyid));
|
{
|
||||||
|
pk = node->pkt->pkt.public_key;
|
||||||
|
keyid_from_pk (pk, NULL);
|
||||||
|
log_info (_("key %s: skipped subkey\n"),
|
||||||
|
keystr_with_sub (keyid, pk->keyid));
|
||||||
|
}
|
||||||
|
|
||||||
delete_kbnode( node ); /* the subkey */
|
delete_kbnode( node ); /* the subkey */
|
||||||
/* and all following signature packets */
|
/* and all following signature packets */
|
||||||
|
241
g10/key-check.c
241
g10/key-check.c
@ -1,7 +1,7 @@
|
|||||||
/* key-check.c - Detect and fix various problems with keys
|
/* key-check.c - Detect and fix various problems with keys
|
||||||
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 1998-2017 Werner Koch
|
* Copyright (C) 1998-2017 Werner Koch
|
||||||
* Copyright (C) 2015-2017 g10 Code GmbH
|
* Copyright (C) 2015-2018 g10 Code GmbH
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -72,6 +72,13 @@ sig_comparison (const void *av, const void *bv)
|
|||||||
a = an->pkt->pkt.signature;
|
a = an->pkt->pkt.signature;
|
||||||
b = bn->pkt->pkt.signature;
|
b = bn->pkt->pkt.signature;
|
||||||
|
|
||||||
|
/* Signatures with a different help counter are not identical for
|
||||||
|
* our purpose. */
|
||||||
|
if (a->help_counter < b->help_counter)
|
||||||
|
return -1;
|
||||||
|
if (a->help_counter > b->help_counter)
|
||||||
|
return 1;
|
||||||
|
|
||||||
if (a->digest_algo < b->digest_algo)
|
if (a->digest_algo < b->digest_algo)
|
||||||
return -1;
|
return -1;
|
||||||
if (a->digest_algo > b->digest_algo)
|
if (a->digest_algo > b->digest_algo)
|
||||||
@ -94,6 +101,125 @@ sig_comparison (const void *av, const void *bv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static gpg_error_t
|
||||||
|
remove_duplicate_sigs (kbnode_t kb, int *dups, int *modified)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
kbnode_t n;
|
||||||
|
int nsigs;
|
||||||
|
kbnode_t *sigs; /* Allocated array with the signature packet. */
|
||||||
|
int i;
|
||||||
|
int last_i;
|
||||||
|
int block;
|
||||||
|
PKT_signature *sig;
|
||||||
|
|
||||||
|
/* Count the sigs. */
|
||||||
|
for (nsigs = 0, n = kb; n; n = n->next)
|
||||||
|
{
|
||||||
|
if (is_deleted_kbnode (n))
|
||||||
|
continue;
|
||||||
|
else if (n->pkt->pkttype == PKT_SIGNATURE)
|
||||||
|
nsigs ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nsigs)
|
||||||
|
return 0; /* No signatures at all. */
|
||||||
|
|
||||||
|
/* Add them all to the SIGS array. */
|
||||||
|
sigs = xtrycalloc (nsigs, sizeof *sigs);
|
||||||
|
if (!sigs)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
log_error (_("error allocating memory: %s\n"), gpg_strerror (err));
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
block = 0;
|
||||||
|
i = 0;
|
||||||
|
for (n = kb; n; n = n->next)
|
||||||
|
{
|
||||||
|
if (is_deleted_kbnode (n))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (n->pkt->pkttype != PKT_SIGNATURE)
|
||||||
|
{
|
||||||
|
switch (n->pkt->pkttype)
|
||||||
|
{
|
||||||
|
case PKT_PUBLIC_SUBKEY:
|
||||||
|
case PKT_SECRET_SUBKEY:
|
||||||
|
case PKT_USER_ID:
|
||||||
|
case PKT_ATTRIBUTE:
|
||||||
|
/* Bump the block number so that we only consider
|
||||||
|
* signatures below the same object as duplicates. */
|
||||||
|
block++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sig = n->pkt->pkt.signature;
|
||||||
|
sig->help_counter = block;
|
||||||
|
sigs[i++] = n;
|
||||||
|
}
|
||||||
|
log_assert (i == nsigs);
|
||||||
|
|
||||||
|
qsort (sigs, nsigs, sizeof (sigs[0]), sig_comparison);
|
||||||
|
|
||||||
|
last_i = 0;
|
||||||
|
for (i = 1; i < nsigs; i ++)
|
||||||
|
{
|
||||||
|
log_assert (sigs[last_i]);
|
||||||
|
log_assert (sigs[last_i]->pkt->pkttype == PKT_SIGNATURE);
|
||||||
|
log_assert (sigs[i]);
|
||||||
|
log_assert (sigs[i]->pkt->pkttype == PKT_SIGNATURE);
|
||||||
|
|
||||||
|
if (sig_comparison (&sigs[last_i], &sigs[i]) == 0)
|
||||||
|
{
|
||||||
|
/* They are the same. Kill the latter. */
|
||||||
|
if (DBG_PACKET)
|
||||||
|
{
|
||||||
|
sig = sigs[i]->pkt->pkt.signature;
|
||||||
|
|
||||||
|
log_debug ("Signature appears multiple times, "
|
||||||
|
"deleting duplicate:\n");
|
||||||
|
log_debug (" sig: class 0x%x, issuer: %s,"
|
||||||
|
" timestamp: %s (%lld), digest: %02x %02x\n",
|
||||||
|
sig->sig_class, keystr (sig->keyid),
|
||||||
|
isotimestamp (sig->timestamp),
|
||||||
|
(long long) sig->timestamp,
|
||||||
|
sig->digest_start[0], sig->digest_start[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove sigs[i] from the keyblock. */
|
||||||
|
{
|
||||||
|
kbnode_t z, *prevp;
|
||||||
|
int to_kill = last_i;
|
||||||
|
last_i = i;
|
||||||
|
|
||||||
|
for (prevp = &kb, z = kb; z; prevp = &z->next, z = z->next)
|
||||||
|
if (z == sigs[to_kill])
|
||||||
|
break;
|
||||||
|
|
||||||
|
*prevp = sigs[to_kill]->next;
|
||||||
|
|
||||||
|
sigs[to_kill]->next = NULL;
|
||||||
|
release_kbnode (sigs[to_kill]);
|
||||||
|
sigs[to_kill] = NULL;
|
||||||
|
|
||||||
|
++*dups;
|
||||||
|
*modified = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
last_i = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (sigs);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Perform a few sanity checks on a keyblock is okay and possibly
|
/* Perform a few sanity checks on a keyblock is okay and possibly
|
||||||
* repair some damage. Concretely:
|
* repair some damage. Concretely:
|
||||||
*
|
*
|
||||||
@ -133,108 +259,17 @@ key_check_all_keysigs (ctrl_t ctrl, int mode, kbnode_t kb,
|
|||||||
int bad_signature = 0;
|
int bad_signature = 0;
|
||||||
int missing_selfsig = 0;
|
int missing_selfsig = 0;
|
||||||
int modified = 0;
|
int modified = 0;
|
||||||
|
PKT_signature *sig;
|
||||||
|
|
||||||
log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
|
log_assert (kb->pkt->pkttype == PKT_PUBLIC_KEY);
|
||||||
pk = kb->pkt->pkt.public_key;
|
pk = kb->pkt->pkt.public_key;
|
||||||
|
|
||||||
/* First we look for duplicates. */
|
/* First we look for duplicates. */
|
||||||
{
|
if (remove_duplicate_sigs (kb, &dups, &modified))
|
||||||
int nsigs;
|
goto leave; /* Error */
|
||||||
kbnode_t *sigs;
|
|
||||||
int i;
|
|
||||||
int last_i;
|
|
||||||
|
|
||||||
/* Count the sigs. */
|
/* Now make sure the sigs occur after the component (aka block)
|
||||||
for (nsigs = 0, n = kb; n; n = n->next)
|
* (public key, subkey, user id) that they sign. */
|
||||||
{
|
|
||||||
if (is_deleted_kbnode (n))
|
|
||||||
continue;
|
|
||||||
else if (n->pkt->pkttype == PKT_SIGNATURE)
|
|
||||||
nsigs ++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!nsigs)
|
|
||||||
return 0; /* No signatures at all. */
|
|
||||||
|
|
||||||
/* Add them all to the SIGS array. */
|
|
||||||
sigs = xtrycalloc (nsigs, sizeof *sigs);
|
|
||||||
if (!sigs)
|
|
||||||
{
|
|
||||||
log_error (_("error allocating memory: %s\n"),
|
|
||||||
gpg_strerror (gpg_error_from_syserror ()));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
i = 0;
|
|
||||||
for (n = kb; n; n = n->next)
|
|
||||||
{
|
|
||||||
if (is_deleted_kbnode (n))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (n->pkt->pkttype != PKT_SIGNATURE)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
sigs[i] = n;
|
|
||||||
i ++;
|
|
||||||
}
|
|
||||||
log_assert (i == nsigs);
|
|
||||||
|
|
||||||
qsort (sigs, nsigs, sizeof (sigs[0]), sig_comparison);
|
|
||||||
|
|
||||||
last_i = 0;
|
|
||||||
for (i = 1; i < nsigs; i ++)
|
|
||||||
{
|
|
||||||
log_assert (sigs[last_i]);
|
|
||||||
log_assert (sigs[last_i]->pkt->pkttype == PKT_SIGNATURE);
|
|
||||||
log_assert (sigs[i]);
|
|
||||||
log_assert (sigs[i]->pkt->pkttype == PKT_SIGNATURE);
|
|
||||||
|
|
||||||
if (sig_comparison (&sigs[last_i], &sigs[i]) == 0)
|
|
||||||
/* They are the same. Kill the latter. */
|
|
||||||
{
|
|
||||||
if (DBG_PACKET)
|
|
||||||
{
|
|
||||||
PKT_signature *sig = sigs[i]->pkt->pkt.signature;
|
|
||||||
|
|
||||||
log_debug ("Signature appears multiple times, "
|
|
||||||
"deleting duplicate:\n");
|
|
||||||
log_debug (" sig: class 0x%x, issuer: %s,"
|
|
||||||
" timestamp: %s (%lld), digest: %02x %02x\n",
|
|
||||||
sig->sig_class, keystr (sig->keyid),
|
|
||||||
isotimestamp (sig->timestamp),
|
|
||||||
(long long) sig->timestamp,
|
|
||||||
sig->digest_start[0], sig->digest_start[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove sigs[i] from the keyblock. */
|
|
||||||
{
|
|
||||||
KBNODE z, *prevp;
|
|
||||||
int to_kill = last_i;
|
|
||||||
last_i = i;
|
|
||||||
|
|
||||||
for (prevp = &kb, z = kb; z; prevp = &z->next, z = z->next)
|
|
||||||
if (z == sigs[to_kill])
|
|
||||||
break;
|
|
||||||
|
|
||||||
*prevp = sigs[to_kill]->next;
|
|
||||||
|
|
||||||
sigs[to_kill]->next = NULL;
|
|
||||||
release_kbnode (sigs[to_kill]);
|
|
||||||
sigs[to_kill] = NULL;
|
|
||||||
|
|
||||||
dups ++;
|
|
||||||
modified = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
last_i = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
xfree (sigs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure the sigs occur after the component (public key, subkey,
|
|
||||||
user id) that they sign. */
|
|
||||||
issuer = NULL;
|
issuer = NULL;
|
||||||
last_printed_component = NULL;
|
last_printed_component = NULL;
|
||||||
for (n_prevp = &kb, n = kb;
|
for (n_prevp = &kb, n = kb;
|
||||||
@ -244,7 +279,6 @@ key_check_all_keysigs (ctrl_t ctrl, int mode, kbnode_t kb,
|
|||||||
{
|
{
|
||||||
PACKET *p;
|
PACKET *p;
|
||||||
int processed_current_component;
|
int processed_current_component;
|
||||||
PKT_signature *sig;
|
|
||||||
int rc;
|
int rc;
|
||||||
int dump_sig_params = 0;
|
int dump_sig_params = 0;
|
||||||
|
|
||||||
@ -573,11 +607,18 @@ key_check_all_keysigs (ctrl_t ctrl, int mode, kbnode_t kb,
|
|||||||
free_public_key (issuer);
|
free_public_key (issuer);
|
||||||
issuer = NULL;
|
issuer = NULL;
|
||||||
|
|
||||||
|
/* If we reordered signatures we need to de-duplicate again because
|
||||||
|
* a signature can now be a duplicate in another block. */
|
||||||
|
if (reordered)
|
||||||
|
{
|
||||||
|
if (remove_duplicate_sigs (kb, &dups, &modified))
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
/* Identify keys / uids that don't have a self-sig. */
|
/* Identify keys / uids that don't have a self-sig. */
|
||||||
{
|
{
|
||||||
int has_selfsig = 0;
|
int has_selfsig = 0;
|
||||||
PACKET *p;
|
PACKET *p;
|
||||||
PKT_signature *sig;
|
|
||||||
|
|
||||||
current_component = NULL;
|
current_component = NULL;
|
||||||
for (n = kb; n; n = n->next)
|
for (n = kb; n; n = n->next)
|
||||||
@ -643,6 +684,8 @@ key_check_all_keysigs (ctrl_t ctrl, int mode, kbnode_t kb,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
leave:
|
||||||
if (!opt.quiet)
|
if (!opt.quiet)
|
||||||
{
|
{
|
||||||
char prefix[100];
|
char prefix[100];
|
||||||
|
614
g10/key-clean.c
Normal file
614
g10/key-clean.c
Normal file
@ -0,0 +1,614 @@
|
|||||||
|
/* key-clean.c - Functions to clean a keyblock
|
||||||
|
* Copyright (C) 1998-2008, 2010-2011 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2014, 2016-2018 Werner Koch
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "gpg.h"
|
||||||
|
#include "keydb.h"
|
||||||
|
#include "../common/util.h"
|
||||||
|
#include "../common/host2net.h"
|
||||||
|
#include "../common/i18n.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "packet.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "key-clean.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mark the signature of the given UID which are used to certify it.
|
||||||
|
* To do this, we first revmove all signatures which are not valid and
|
||||||
|
* from the remain ones we look for the latest one. If this is not a
|
||||||
|
* certification revocation signature we mark the signature by setting
|
||||||
|
* node flag bit 8. Revocations are marked with flag 11, and sigs
|
||||||
|
* from unavailable keys are marked with flag 12. Note that flag bits
|
||||||
|
* 9 and 10 are used for internal purposes.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||||
|
u32 *main_kid, struct key_item *klist,
|
||||||
|
u32 curtime, u32 *next_expire)
|
||||||
|
{
|
||||||
|
kbnode_t node;
|
||||||
|
PKT_signature *sig;
|
||||||
|
|
||||||
|
/* First check all signatures. */
|
||||||
|
for (node=uidnode->next; node; node = node->next)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
|
||||||
|
if (node->pkt->pkttype == PKT_USER_ID
|
||||||
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||||
|
break; /* ready */
|
||||||
|
if (node->pkt->pkttype != PKT_SIGNATURE)
|
||||||
|
continue;
|
||||||
|
sig = node->pkt->pkt.signature;
|
||||||
|
if (main_kid
|
||||||
|
&& sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
|
||||||
|
continue; /* ignore self-signatures if we pass in a main_kid */
|
||||||
|
if (!IS_UID_SIG(sig) && !IS_UID_REV(sig))
|
||||||
|
continue; /* we only look at these signature classes */
|
||||||
|
if(sig->sig_class>=0x11 && sig->sig_class<=0x13 &&
|
||||||
|
sig->sig_class-0x10<opt.min_cert_level)
|
||||||
|
continue; /* treat anything under our min_cert_level as an
|
||||||
|
invalid signature */
|
||||||
|
if (klist && !is_in_klist (klist, sig))
|
||||||
|
continue; /* no need to check it then */
|
||||||
|
if ((rc=check_key_signature (ctrl, keyblock, node, NULL)))
|
||||||
|
{
|
||||||
|
/* we ignore anything that won't verify, but tag the
|
||||||
|
no_pubkey case */
|
||||||
|
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
|
||||||
|
node->flag |= 1<<12;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
node->flag |= 1<<9;
|
||||||
|
}
|
||||||
|
/* Reset the remaining flags. */
|
||||||
|
for (; node; node = node->next)
|
||||||
|
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
|
||||||
|
|
||||||
|
/* kbnode flag usage: bit 9 is here set for signatures to consider,
|
||||||
|
* bit 10 will be set by the loop to keep track of keyIDs already
|
||||||
|
* processed, bit 8 will be set for the usable signatures, and bit
|
||||||
|
* 11 will be set for usable revocations. */
|
||||||
|
|
||||||
|
/* For each cert figure out the latest valid one. */
|
||||||
|
for (node=uidnode->next; node; node = node->next)
|
||||||
|
{
|
||||||
|
KBNODE n, signode;
|
||||||
|
u32 kid[2];
|
||||||
|
u32 sigdate;
|
||||||
|
|
||||||
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||||
|
break;
|
||||||
|
if ( !(node->flag & (1<<9)) )
|
||||||
|
continue; /* not a node to look at */
|
||||||
|
if ( (node->flag & (1<<10)) )
|
||||||
|
continue; /* signature with a keyID already processed */
|
||||||
|
node->flag |= (1<<10); /* mark this node as processed */
|
||||||
|
sig = node->pkt->pkt.signature;
|
||||||
|
signode = node;
|
||||||
|
sigdate = sig->timestamp;
|
||||||
|
kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1];
|
||||||
|
|
||||||
|
/* Now find the latest and greatest signature */
|
||||||
|
for (n=uidnode->next; n; n = n->next)
|
||||||
|
{
|
||||||
|
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| n->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||||
|
break;
|
||||||
|
if ( !(n->flag & (1<<9)) )
|
||||||
|
continue;
|
||||||
|
if ( (n->flag & (1<<10)) )
|
||||||
|
continue; /* shortcut already processed signatures */
|
||||||
|
sig = n->pkt->pkt.signature;
|
||||||
|
if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1])
|
||||||
|
continue;
|
||||||
|
n->flag |= (1<<10); /* mark this node as processed */
|
||||||
|
|
||||||
|
/* If signode is nonrevocable and unexpired and n isn't,
|
||||||
|
then take signode (skip). It doesn't matter which is
|
||||||
|
older: if signode was older then we don't want to take n
|
||||||
|
as signode is nonrevocable. If n was older then we're
|
||||||
|
automatically fine. */
|
||||||
|
|
||||||
|
if(((IS_UID_SIG(signode->pkt->pkt.signature) &&
|
||||||
|
!signode->pkt->pkt.signature->flags.revocable &&
|
||||||
|
(signode->pkt->pkt.signature->expiredate==0 ||
|
||||||
|
signode->pkt->pkt.signature->expiredate>curtime))) &&
|
||||||
|
(!(IS_UID_SIG(n->pkt->pkt.signature) &&
|
||||||
|
!n->pkt->pkt.signature->flags.revocable &&
|
||||||
|
(n->pkt->pkt.signature->expiredate==0 ||
|
||||||
|
n->pkt->pkt.signature->expiredate>curtime))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If n is nonrevocable and unexpired and signode isn't,
|
||||||
|
then take n. Again, it doesn't matter which is older: if
|
||||||
|
n was older then we don't want to take signode as n is
|
||||||
|
nonrevocable. If signode was older then we're
|
||||||
|
automatically fine. */
|
||||||
|
|
||||||
|
if((!(IS_UID_SIG(signode->pkt->pkt.signature) &&
|
||||||
|
!signode->pkt->pkt.signature->flags.revocable &&
|
||||||
|
(signode->pkt->pkt.signature->expiredate==0 ||
|
||||||
|
signode->pkt->pkt.signature->expiredate>curtime))) &&
|
||||||
|
((IS_UID_SIG(n->pkt->pkt.signature) &&
|
||||||
|
!n->pkt->pkt.signature->flags.revocable &&
|
||||||
|
(n->pkt->pkt.signature->expiredate==0 ||
|
||||||
|
n->pkt->pkt.signature->expiredate>curtime))))
|
||||||
|
{
|
||||||
|
signode = n;
|
||||||
|
sigdate = sig->timestamp;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* At this point, if it's newer, it goes in as the only
|
||||||
|
remaining possibilities are signode and n are both either
|
||||||
|
revocable or expired or both nonrevocable and unexpired.
|
||||||
|
If the timestamps are equal take the later ordered
|
||||||
|
packet, presuming that the key packets are hopefully in
|
||||||
|
their original order. */
|
||||||
|
|
||||||
|
if (sig->timestamp >= sigdate)
|
||||||
|
{
|
||||||
|
signode = n;
|
||||||
|
sigdate = sig->timestamp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sig = signode->pkt->pkt.signature;
|
||||||
|
if (IS_UID_SIG (sig))
|
||||||
|
{ /* this seems to be a usable one which is not revoked.
|
||||||
|
* Just need to check whether there is an expiration time,
|
||||||
|
* We do the expired certification after finding a suitable
|
||||||
|
* certification, the assumption is that a signator does not
|
||||||
|
* want that after the expiration of his certificate the
|
||||||
|
* system falls back to an older certification which has a
|
||||||
|
* different expiration time */
|
||||||
|
const byte *p;
|
||||||
|
u32 expire;
|
||||||
|
|
||||||
|
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
|
||||||
|
expire = p? sig->timestamp + buf32_to_u32(p) : 0;
|
||||||
|
|
||||||
|
if (expire==0 || expire > curtime )
|
||||||
|
{
|
||||||
|
signode->flag |= (1<<8); /* yeah, found a good cert */
|
||||||
|
if (next_expire && expire && expire < *next_expire)
|
||||||
|
*next_expire = expire;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
signode->flag |= (1<<11);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||||
|
int noisy, int self_only)
|
||||||
|
{
|
||||||
|
int deleted = 0;
|
||||||
|
kbnode_t node;
|
||||||
|
u32 keyid[2];
|
||||||
|
|
||||||
|
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
|
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||||
|
|
||||||
|
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
|
||||||
|
|
||||||
|
/* Passing in a 0 for current time here means that we'll never weed
|
||||||
|
out an expired sig. This is correct behavior since we want to
|
||||||
|
keep the most recent expired sig in a series. */
|
||||||
|
mark_usable_uid_certs (ctrl, keyblock, uidnode, NULL, NULL, 0, NULL);
|
||||||
|
|
||||||
|
/* What we want to do here is remove signatures that are not
|
||||||
|
considered as part of the trust calculations. Thus, all invalid
|
||||||
|
signatures are out, as are any signatures that aren't the last of
|
||||||
|
a series of uid sigs or revocations It breaks down like this:
|
||||||
|
coming out of mark_usable_uid_certs, if a sig is unflagged, it is
|
||||||
|
not even a candidate. If a sig has flag 9 or 10, that means it
|
||||||
|
was selected as a candidate and vetted. If a sig has flag 8 it
|
||||||
|
is a usable signature. If a sig has flag 11 it is a usable
|
||||||
|
revocation. If a sig has flag 12 it was issued by an unavailable
|
||||||
|
key. "Usable" here means the most recent valid
|
||||||
|
signature/revocation in a series from a particular signer.
|
||||||
|
|
||||||
|
Delete everything that isn't a usable uid sig (which might be
|
||||||
|
expired), a usable revocation, or a sig from an unavailable
|
||||||
|
key. */
|
||||||
|
|
||||||
|
for (node=uidnode->next;
|
||||||
|
node && node->pkt->pkttype==PKT_SIGNATURE;
|
||||||
|
node=node->next)
|
||||||
|
{
|
||||||
|
int keep;
|
||||||
|
|
||||||
|
keep = self_only? (node->pkt->pkt.signature->keyid[0] == keyid[0]
|
||||||
|
&& node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1;
|
||||||
|
|
||||||
|
/* Keep usable uid sigs ... */
|
||||||
|
if ((node->flag & (1<<8)) && keep)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* ... and usable revocations... */
|
||||||
|
if ((node->flag & (1<<11)) && keep)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* ... and sigs from unavailable keys. */
|
||||||
|
/* disabled for now since more people seem to want sigs from
|
||||||
|
unavailable keys removed altogether. */
|
||||||
|
/*
|
||||||
|
if(node->flag & (1<<12))
|
||||||
|
continue;
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Everything else we delete */
|
||||||
|
|
||||||
|
/* At this point, if 12 is set, the signing key was unavailable.
|
||||||
|
If 9 or 10 is set, it's superseded. Otherwise, it's
|
||||||
|
invalid. */
|
||||||
|
|
||||||
|
if (noisy)
|
||||||
|
log_info ("removing signature from key %s on user ID \"%s\": %s\n",
|
||||||
|
keystr (node->pkt->pkt.signature->keyid),
|
||||||
|
uidnode->pkt->pkt.user_id->name,
|
||||||
|
node->flag&(1<<12)? "key unavailable":
|
||||||
|
node->flag&(1<<9)? "signature superseded"
|
||||||
|
/* */ :"invalid signature" );
|
||||||
|
|
||||||
|
delete_kbnode (node);
|
||||||
|
deleted++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This is substantially easier than clean_sigs_from_uid since we just
|
||||||
|
have to establish if the uid has a valid self-sig, is not revoked,
|
||||||
|
and is not expired. Note that this does not take into account
|
||||||
|
whether the uid has a trust path to it - just whether the keyholder
|
||||||
|
themselves has certified the uid. Returns true if the uid was
|
||||||
|
compacted. To "compact" a user ID, we simply remove ALL signatures
|
||||||
|
except the self-sig that caused the user ID to be remove-worthy.
|
||||||
|
We don't actually remove the user ID packet itself since it might
|
||||||
|
be resurrected in a later merge. Note that this function requires
|
||||||
|
that the caller has already done a merge_keys_and_selfsig().
|
||||||
|
|
||||||
|
TODO: change the import code to allow importing a uid with only a
|
||||||
|
revocation if the uid already exists on the keyring. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
|
||||||
|
{
|
||||||
|
kbnode_t node;
|
||||||
|
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
|
||||||
|
int deleted = 0;
|
||||||
|
|
||||||
|
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
|
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||||
|
log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
|
||||||
|
|
||||||
|
/* Skip valid user IDs, compacted user IDs, and non-self-signed user
|
||||||
|
IDs if --allow-non-selfsigned-uid is set. */
|
||||||
|
if (uid->created
|
||||||
|
|| uid->flags.compacted
|
||||||
|
|| (!uid->flags.expired && !uid->flags.revoked && opt.allow_non_selfsigned_uid))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (node=uidnode->next;
|
||||||
|
node && node->pkt->pkttype == PKT_SIGNATURE;
|
||||||
|
node=node->next)
|
||||||
|
{
|
||||||
|
if (!node->pkt->pkt.signature->flags.chosen_selfsig)
|
||||||
|
{
|
||||||
|
delete_kbnode (node);
|
||||||
|
deleted = 1;
|
||||||
|
uidnode->pkt->pkt.user_id->flags.compacted = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noisy)
|
||||||
|
{
|
||||||
|
const char *reason;
|
||||||
|
char *user = utf8_to_native (uid->name, uid->len, 0);
|
||||||
|
|
||||||
|
if (uid->flags.revoked)
|
||||||
|
reason = _("revoked");
|
||||||
|
else if (uid->flags.expired)
|
||||||
|
reason = _("expired");
|
||||||
|
else
|
||||||
|
reason = _("invalid");
|
||||||
|
|
||||||
|
log_info ("compacting user ID \"%s\" on key %s: %s\n",
|
||||||
|
user, keystr_from_pk (keyblock->pkt->pkt.public_key),
|
||||||
|
reason);
|
||||||
|
|
||||||
|
xfree (user);
|
||||||
|
}
|
||||||
|
|
||||||
|
return deleted;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Needs to be called after a merge_keys_and_selfsig() */
|
||||||
|
void
|
||||||
|
clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||||
|
int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned)
|
||||||
|
{
|
||||||
|
int dummy = 0;
|
||||||
|
|
||||||
|
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
||||||
|
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
||||||
|
log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
|
||||||
|
|
||||||
|
if (!uids_cleaned)
|
||||||
|
uids_cleaned = &dummy;
|
||||||
|
|
||||||
|
if (!sigs_cleaned)
|
||||||
|
sigs_cleaned = &dummy;
|
||||||
|
|
||||||
|
/* Do clean_uid_from_key first since if it fires off, we don't have
|
||||||
|
to bother with the other. */
|
||||||
|
*uids_cleaned += clean_uid_from_key (keyblock, uidnode, noisy);
|
||||||
|
if (!uidnode->pkt->pkt.user_id->flags.compacted)
|
||||||
|
*sigs_cleaned += clean_sigs_from_uid (ctrl, keyblock, uidnode,
|
||||||
|
noisy, self_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* NB: This function marks the deleted nodes only and the caller is
|
||||||
|
* responsible to skip or remove them. Needs to be called after a
|
||||||
|
* merge_keys_and_selfsig(). */
|
||||||
|
void
|
||||||
|
clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
|
||||||
|
int *uids_cleaned, int *sigs_cleaned)
|
||||||
|
{
|
||||||
|
kbnode_t node;
|
||||||
|
|
||||||
|
for (node = keyblock->next;
|
||||||
|
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||||
|
node = node->next)
|
||||||
|
{
|
||||||
|
if (node->pkt->pkttype == PKT_USER_ID)
|
||||||
|
clean_one_uid (ctrl, keyblock, node, noisy, self_only,
|
||||||
|
uids_cleaned, sigs_cleaned);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove bogus subkey binding signatures: The only signatures
|
||||||
|
* allowed are of class 0x18 and 0x28. */
|
||||||
|
log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for clean_all_subkeys. */
|
||||||
|
static int
|
||||||
|
clean_one_subkey (ctrl_t ctrl, kbnode_t subkeynode, int noisy, int clean_level)
|
||||||
|
{
|
||||||
|
kbnode_t node;
|
||||||
|
PKT_public_key *pk = subkeynode->pkt->pkt.public_key;
|
||||||
|
unsigned int use = pk->pubkey_usage;
|
||||||
|
int do_clean = 0;
|
||||||
|
|
||||||
|
(void)ctrl;
|
||||||
|
(void)noisy;
|
||||||
|
|
||||||
|
log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||||
|
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("\tchecking subkey %08lX [%c%c%c%c%c]\n",
|
||||||
|
(ulong) keyid_from_pk (pk, NULL),
|
||||||
|
(use & PUBKEY_USAGE_ENC)? 'e':'-',
|
||||||
|
(use & PUBKEY_USAGE_SIG)? 's':'-',
|
||||||
|
(use & PUBKEY_USAGE_CERT)? 'c':'-',
|
||||||
|
(use & PUBKEY_USAGE_AUTH)? 'a':'-',
|
||||||
|
(use & PUBKEY_USAGE_UNKNOWN)? '?':'-');
|
||||||
|
|
||||||
|
if (!pk->flags.valid)
|
||||||
|
{
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("\tsubkey not valid\n");
|
||||||
|
if (clean_level == KEY_CLEAN_INVALID)
|
||||||
|
do_clean = 1;
|
||||||
|
}
|
||||||
|
if (pk->has_expired)
|
||||||
|
{
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("\tsubkey has expired\n");
|
||||||
|
if (clean_level == KEY_CLEAN_ALL)
|
||||||
|
do_clean = 1;
|
||||||
|
else if (clean_level == KEY_CLEAN_AUTHENCR
|
||||||
|
&& (use & (PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH))
|
||||||
|
&& !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT)))
|
||||||
|
do_clean = 1;
|
||||||
|
else if (clean_level == KEY_CLEAN_ENCR
|
||||||
|
&& (use & PUBKEY_USAGE_ENC)
|
||||||
|
&& !(use & (PUBKEY_USAGE_SIG | PUBKEY_USAGE_CERT
|
||||||
|
| PUBKEY_USAGE_AUTH)))
|
||||||
|
do_clean = 1;
|
||||||
|
}
|
||||||
|
if (pk->flags.revoked)
|
||||||
|
{
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("\tsubkey has been revoked (keeping)\n");
|
||||||
|
/* Avoid any cleaning because revocations are important. */
|
||||||
|
do_clean = 0;
|
||||||
|
}
|
||||||
|
if (!do_clean)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("\t=> removing this subkey\n");
|
||||||
|
|
||||||
|
delete_kbnode (subkeynode);
|
||||||
|
for (node = subkeynode->next;
|
||||||
|
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||||
|
node = node->next)
|
||||||
|
delete_kbnode (node);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for clean_all_subkeys. Here duplicate signatures from a
|
||||||
|
* subkey are removed. This should in general not happen because
|
||||||
|
* import takes care of that. However, sometimes other tools are used
|
||||||
|
* to manage a keyring or key has been imported a long time ago. */
|
||||||
|
static int
|
||||||
|
clean_one_subkey_dupsigs (ctrl_t ctrl, kbnode_t subkeynode)
|
||||||
|
{
|
||||||
|
kbnode_t node;
|
||||||
|
PKT_public_key *pk = subkeynode->pkt->pkt.public_key;
|
||||||
|
int any_choosen = 0;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
(void)ctrl;
|
||||||
|
|
||||||
|
log_assert (subkeynode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| subkeynode->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||||
|
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("\tchecking subkey %08lX for dupsigs\n",
|
||||||
|
(ulong) keyid_from_pk (pk, NULL));
|
||||||
|
|
||||||
|
/* First check that the choosen flag has been set. Note that we
|
||||||
|
* only look at plain signatures so to keep all revocation
|
||||||
|
* signatures which may carry important information. */
|
||||||
|
for (node = subkeynode->next;
|
||||||
|
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||||
|
node = node->next)
|
||||||
|
{
|
||||||
|
if (!is_deleted_kbnode (node)
|
||||||
|
&& node->pkt->pkttype == PKT_SIGNATURE
|
||||||
|
&& IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
||||||
|
&& node->pkt->pkt.signature->flags.chosen_selfsig)
|
||||||
|
{
|
||||||
|
any_choosen = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!any_choosen)
|
||||||
|
return 0; /* Ooops no choosen flag set - we can't decide. */
|
||||||
|
|
||||||
|
for (node = subkeynode->next;
|
||||||
|
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
||||||
|
node = node->next)
|
||||||
|
{
|
||||||
|
if (!is_deleted_kbnode (node)
|
||||||
|
&& node->pkt->pkttype == PKT_SIGNATURE
|
||||||
|
&& IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
||||||
|
&& !node->pkt->pkt.signature->flags.chosen_selfsig)
|
||||||
|
{
|
||||||
|
delete_kbnode (node);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* This function only marks the deleted nodes and the caller is
|
||||||
|
* responsible to skip or remove them. Needs to be called after a
|
||||||
|
* merge_keys_and_selfsig. CLEAN_LEVEL is one of the KEY_CLEAN_*
|
||||||
|
* values. */
|
||||||
|
void
|
||||||
|
clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock, int noisy, int clean_level,
|
||||||
|
int *subkeys_cleaned, int *sigs_cleaned)
|
||||||
|
{
|
||||||
|
kbnode_t first_subkey, node;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if (DBG_LOOKUP)
|
||||||
|
log_debug ("clean_all_subkeys: checking key %08lX\n",
|
||||||
|
(ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL));
|
||||||
|
|
||||||
|
for (node = keyblock->next; node; node = node->next)
|
||||||
|
if (!is_deleted_kbnode (node)
|
||||||
|
&& (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY))
|
||||||
|
break;
|
||||||
|
first_subkey = node;
|
||||||
|
|
||||||
|
/* Remove bogus subkey binding signatures: The only signatures
|
||||||
|
* allowed are of class 0x18 and 0x28. */
|
||||||
|
for (node = first_subkey; node; node = node->next)
|
||||||
|
{
|
||||||
|
if (is_deleted_kbnode (node))
|
||||||
|
continue;
|
||||||
|
if (node->pkt->pkttype == PKT_SIGNATURE
|
||||||
|
&& !(IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
||||||
|
|| IS_SUBKEY_REV (node->pkt->pkt.signature)))
|
||||||
|
{
|
||||||
|
delete_kbnode (node);
|
||||||
|
if (sigs_cleaned)
|
||||||
|
++*sigs_cleaned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do the selected cleaning. */
|
||||||
|
if (clean_level > KEY_CLEAN_NONE)
|
||||||
|
{
|
||||||
|
/* Clean enitre subkeys. */
|
||||||
|
for (node = first_subkey; node; node = node->next)
|
||||||
|
{
|
||||||
|
if (is_deleted_kbnode (node))
|
||||||
|
continue;
|
||||||
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||||
|
{
|
||||||
|
if (clean_one_subkey (ctrl, node, noisy, clean_level))
|
||||||
|
{
|
||||||
|
if (subkeys_cleaned)
|
||||||
|
++*subkeys_cleaned;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Clean duplicate signatures from a subkey. */
|
||||||
|
for (node = first_subkey; node; node = node->next)
|
||||||
|
{
|
||||||
|
if (is_deleted_kbnode (node))
|
||||||
|
continue;
|
||||||
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
||||||
|
{
|
||||||
|
n = clean_one_subkey_dupsigs (ctrl, node);
|
||||||
|
if (sigs_cleaned)
|
||||||
|
*sigs_cleaned += n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
g10/key-clean.h
Normal file
52
g10/key-clean.h
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/* key-clean.h - Functions to clean a keyblock
|
||||||
|
* Copyright (C) 2018 Werner Koch
|
||||||
|
*
|
||||||
|
* This file is part of GnuPG.
|
||||||
|
*
|
||||||
|
* GnuPG is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* GnuPG is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
||||||
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef GNUPG_G10_KEY_CLEAN_H
|
||||||
|
#define GNUPG_G10_KEY_CLEAN_H
|
||||||
|
|
||||||
|
#include "gpg.h"
|
||||||
|
|
||||||
|
/* No explict cleaning. */
|
||||||
|
#define KEY_CLEAN_NONE 0
|
||||||
|
/* Remove only invalid subkeys (ie. missing key-bindings) */
|
||||||
|
#define KEY_CLEAN_INVALID 1
|
||||||
|
/* Remove expired encryption keys */
|
||||||
|
#define KEY_CLEAN_ENCR 2
|
||||||
|
/* Remove expired authentication and encryption keys. */
|
||||||
|
#define KEY_CLEAN_AUTHENCR 3
|
||||||
|
/* Remove all expired subkeys. */
|
||||||
|
#define KEY_CLEAN_ALL 4
|
||||||
|
|
||||||
|
|
||||||
|
void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||||
|
u32 *main_kid, struct key_item *klist,
|
||||||
|
u32 curtime, u32 *next_expire);
|
||||||
|
|
||||||
|
void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
||||||
|
int noisy, int self_only,
|
||||||
|
int *uids_cleaned, int *sigs_cleaned);
|
||||||
|
void clean_all_uids (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
|
||||||
|
int *uids_cleaned,int *sigs_cleaned);
|
||||||
|
void clean_all_subkeys (ctrl_t ctrl, kbnode_t keyblock,
|
||||||
|
int noisy, int clean_level,
|
||||||
|
int *subkeys_cleaned, int *sigs_cleaned);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /*GNUPG_G10_KEY_CLEAN_H*/
|
38
g10/keydb.h
38
g10/keydb.h
@ -64,6 +64,20 @@ struct kbnode_struct {
|
|||||||
#define is_cloned_kbnode(a) ((a)->private_flag & 2)
|
#define is_cloned_kbnode(a) ((a)->private_flag & 2)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A structure to store key identification as well as some stuff
|
||||||
|
* needed for key validation.
|
||||||
|
*/
|
||||||
|
struct key_item {
|
||||||
|
struct key_item *next;
|
||||||
|
unsigned int ownertrust,min_ownertrust;
|
||||||
|
byte trust_depth;
|
||||||
|
byte trust_value;
|
||||||
|
char *trust_regexp;
|
||||||
|
u32 kid[2];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* Bit flags used with build_pk_list. */
|
/* Bit flags used with build_pk_list. */
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
@ -133,6 +147,22 @@ enum
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check whether the signature SIG is in the klist K.
|
||||||
|
*/
|
||||||
|
static inline struct key_item *
|
||||||
|
is_in_klist (struct key_item *k, PKT_signature *sig)
|
||||||
|
{
|
||||||
|
for (; k; k = k->next)
|
||||||
|
{
|
||||||
|
if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1])
|
||||||
|
return k;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-- keydb.c --*/
|
/*-- keydb.c --*/
|
||||||
|
|
||||||
#define KEYDB_RESOURCE_FLAG_PRIMARY 2 /* The primary resource. */
|
#define KEYDB_RESOURCE_FLAG_PRIMARY 2 /* The primary resource. */
|
||||||
@ -283,6 +313,10 @@ void cache_public_key( PKT_public_key *pk );
|
|||||||
/* Disable and drop the public key cache. */
|
/* Disable and drop the public key cache. */
|
||||||
void getkey_disable_caches(void);
|
void getkey_disable_caches(void);
|
||||||
|
|
||||||
|
/* Return the public key used for signature SIG and store it at PK. */
|
||||||
|
gpg_error_t get_pubkey_for_sig (ctrl_t ctrl,
|
||||||
|
PKT_public_key *pk, PKT_signature *sig);
|
||||||
|
|
||||||
/* Return the public key with the key id KEYID and store it at PK. */
|
/* Return the public key with the key id KEYID and store it at PK. */
|
||||||
int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
|
int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
|
||||||
|
|
||||||
@ -291,6 +325,10 @@ int get_pubkey (ctrl_t ctrl, PKT_public_key *pk, u32 *keyid);
|
|||||||
also only considers primary keys. */
|
also only considers primary keys. */
|
||||||
int get_pubkey_fast (PKT_public_key *pk, u32 *keyid);
|
int get_pubkey_fast (PKT_public_key *pk, u32 *keyid);
|
||||||
|
|
||||||
|
/* Return the entire keyblock used to create SIG. This is a
|
||||||
|
* specialized version of get_pubkeyblock. */
|
||||||
|
kbnode_t get_pubkeyblock_for_sig (ctrl_t ctrl, PKT_signature *sig);
|
||||||
|
|
||||||
/* Return the key block for the key with KEYID. */
|
/* Return the key block for the key with KEYID. */
|
||||||
kbnode_t get_pubkeyblock (ctrl_t ctrl, u32 *keyid);
|
kbnode_t get_pubkeyblock (ctrl_t ctrl, u32 *keyid);
|
||||||
|
|
||||||
|
@ -49,6 +49,7 @@
|
|||||||
#include "../common/host2net.h"
|
#include "../common/host2net.h"
|
||||||
#include "tofu.h"
|
#include "tofu.h"
|
||||||
#include "key-check.h"
|
#include "key-check.h"
|
||||||
|
#include "key-clean.h"
|
||||||
#include "keyedit.h"
|
#include "keyedit.h"
|
||||||
|
|
||||||
static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
|
static void show_prefs (PKT_user_id * uid, PKT_signature * selfsig,
|
||||||
|
@ -3293,7 +3293,7 @@ parse_key_parameter_string (const char *string, int part,
|
|||||||
* part consider this to be the subkey algo. In case a
|
* part consider this to be the subkey algo. In case a
|
||||||
* SUGGESTED_USE has been given and the usage of the secondary
|
* SUGGESTED_USE has been given and the usage of the secondary
|
||||||
* part does not match SUGGESTED_USE try again using the primary
|
* part does not match SUGGESTED_USE try again using the primary
|
||||||
* part. Noet thar when falling back to the primary key we need
|
* part. Note that when falling back to the primary key we need
|
||||||
* to force clearing the cert usage. */
|
* to force clearing the cert usage. */
|
||||||
if (secondary)
|
if (secondary)
|
||||||
{
|
{
|
||||||
|
@ -1107,6 +1107,9 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||||||
PKT_signature *sig = node->pkt->pkt.signature;
|
PKT_signature *sig = node->pkt->pkt.signature;
|
||||||
int sigrc;
|
int sigrc;
|
||||||
char *sigstr;
|
char *sigstr;
|
||||||
|
char *reason_text = NULL;
|
||||||
|
char *reason_comment = NULL;
|
||||||
|
size_t reason_commentlen;
|
||||||
|
|
||||||
if (listctx->check_sigs)
|
if (listctx->check_sigs)
|
||||||
{
|
{
|
||||||
@ -1143,7 +1146,11 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||||||
|
|
||||||
if (sig->sig_class == 0x20 || sig->sig_class == 0x28
|
if (sig->sig_class == 0x20 || sig->sig_class == 0x28
|
||||||
|| sig->sig_class == 0x30)
|
|| sig->sig_class == 0x30)
|
||||||
sigstr = "rev";
|
{
|
||||||
|
sigstr = "rev";
|
||||||
|
get_revocation_reason (sig, &reason_text,
|
||||||
|
&reason_comment, &reason_commentlen);
|
||||||
|
}
|
||||||
else if ((sig->sig_class & ~3) == 0x10)
|
else if ((sig->sig_class & ~3) == 0x10)
|
||||||
sigstr = "sig";
|
sigstr = "sig";
|
||||||
else if (sig->sig_class == 0x18)
|
else if (sig->sig_class == 0x18)
|
||||||
@ -1205,6 +1212,40 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
|
|||||||
&& (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
&& (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
||||||
show_keyserver_url (sig, 3, 0);
|
show_keyserver_url (sig, 3, 0);
|
||||||
|
|
||||||
|
if (reason_text)
|
||||||
|
{
|
||||||
|
es_fprintf (es_stdout, " %s%s\n",
|
||||||
|
_("reason for revocation: "), reason_text);
|
||||||
|
if (reason_comment)
|
||||||
|
{
|
||||||
|
const byte *s, *s_lf;
|
||||||
|
size_t n, n_lf;
|
||||||
|
|
||||||
|
s = reason_comment;
|
||||||
|
n = reason_commentlen;
|
||||||
|
s_lf = NULL;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* We don't want any empty lines, so we skip them. */
|
||||||
|
for (;n && *s == '\n'; s++, n--)
|
||||||
|
;
|
||||||
|
if (n)
|
||||||
|
{
|
||||||
|
s_lf = memchr (s, '\n', n);
|
||||||
|
n_lf = s_lf? s_lf - s : n;
|
||||||
|
es_fprintf (es_stdout, " %s",
|
||||||
|
_("revocation comment: "));
|
||||||
|
es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
|
||||||
|
es_putc ('\n', es_stdout);
|
||||||
|
s += n_lf; n -= n_lf;
|
||||||
|
}
|
||||||
|
} while (s_lf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
xfree (reason_text);
|
||||||
|
xfree (reason_comment);
|
||||||
|
|
||||||
/* fixme: check or list other sigs here */
|
/* fixme: check or list other sigs here */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1554,10 +1595,19 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
|
|||||||
char *siguid;
|
char *siguid;
|
||||||
size_t siguidlen;
|
size_t siguidlen;
|
||||||
char *issuer_fpr = NULL;
|
char *issuer_fpr = NULL;
|
||||||
|
char *reason_text = NULL;
|
||||||
|
char *reason_comment = NULL;
|
||||||
|
size_t reason_commentlen;
|
||||||
|
int reason_code;
|
||||||
|
|
||||||
if (sig->sig_class == 0x20 || sig->sig_class == 0x28
|
if (sig->sig_class == 0x20 || sig->sig_class == 0x28
|
||||||
|| sig->sig_class == 0x30)
|
|| sig->sig_class == 0x30)
|
||||||
sigstr = "rev";
|
{
|
||||||
|
sigstr = "rev";
|
||||||
|
reason_code = get_revocation_reason (sig, &reason_text,
|
||||||
|
&reason_comment,
|
||||||
|
&reason_commentlen);
|
||||||
|
}
|
||||||
else if ((sig->sig_class & ~3) == 0x10)
|
else if ((sig->sig_class & ~3) == 0x10)
|
||||||
sigstr = "sig";
|
sigstr = "sig";
|
||||||
else if (sig->sig_class == 0x18)
|
else if (sig->sig_class == 0x18)
|
||||||
@ -1651,8 +1701,11 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
|
|||||||
else if (siguid)
|
else if (siguid)
|
||||||
es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL);
|
es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL);
|
||||||
|
|
||||||
es_fprintf (es_stdout, ":%02x%c::", sig->sig_class,
|
es_fprintf (es_stdout, ":%02x%c", sig->sig_class,
|
||||||
sig->flags.exportable ? 'x' : 'l');
|
sig->flags.exportable ? 'x' : 'l');
|
||||||
|
if (reason_text)
|
||||||
|
es_fprintf (es_stdout, ",%02x", reason_code);
|
||||||
|
es_fputs ("::", es_stdout);
|
||||||
|
|
||||||
if (opt.no_sig_cache && opt.check_sigs && fprokay)
|
if (opt.no_sig_cache && opt.check_sigs && fprokay)
|
||||||
{
|
{
|
||||||
@ -1662,12 +1715,23 @@ list_keyblock_colon (ctrl_t ctrl, kbnode_t keyblock,
|
|||||||
else if ((issuer_fpr = issuer_fpr_string (sig)))
|
else if ((issuer_fpr = issuer_fpr_string (sig)))
|
||||||
es_fputs (issuer_fpr, es_stdout);
|
es_fputs (issuer_fpr, es_stdout);
|
||||||
|
|
||||||
es_fprintf (es_stdout, ":::%d:\n", sig->digest_algo);
|
es_fprintf (es_stdout, ":::%d:", sig->digest_algo);
|
||||||
|
|
||||||
|
if (reason_comment)
|
||||||
|
{
|
||||||
|
es_fputs ("::::", es_stdout);
|
||||||
|
es_write_sanitized (es_stdout, reason_comment, reason_commentlen,
|
||||||
|
":", NULL);
|
||||||
|
es_putc (':', es_stdout);
|
||||||
|
}
|
||||||
|
es_putc ('\n', es_stdout);
|
||||||
|
|
||||||
if (opt.show_subpackets)
|
if (opt.show_subpackets)
|
||||||
print_subpackets_colon (sig);
|
print_subpackets_colon (sig);
|
||||||
|
|
||||||
/* fixme: check or list other sigs here */
|
/* fixme: check or list other sigs here */
|
||||||
|
xfree (reason_text);
|
||||||
|
xfree (reason_comment);
|
||||||
xfree (siguid);
|
xfree (siguid);
|
||||||
xfree (issuer_fpr);
|
xfree (issuer_fpr);
|
||||||
}
|
}
|
||||||
|
@ -396,6 +396,9 @@ gpg_error_t transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
|
|||||||
|
|
||||||
int collapse_uids( KBNODE *keyblock );
|
int collapse_uids( KBNODE *keyblock );
|
||||||
|
|
||||||
|
int get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||||
|
char **r_comment, size_t *r_commentlen);
|
||||||
|
|
||||||
|
|
||||||
/*-- export.c --*/
|
/*-- export.c --*/
|
||||||
struct export_stats_s;
|
struct export_stats_s;
|
||||||
|
@ -533,6 +533,14 @@ static void
|
|||||||
proc_encrypted (CTX c, PACKET *pkt)
|
proc_encrypted (CTX c, PACKET *pkt)
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
int early_plaintext = literals_seen;
|
||||||
|
|
||||||
|
if (early_plaintext)
|
||||||
|
{
|
||||||
|
log_info (_("WARNING: multiple plaintexts seen\n"));
|
||||||
|
write_status_errcode ("decryption.early_plaintext", GPG_ERR_BAD_DATA);
|
||||||
|
/* We fail only later so that we can print some more info first. */
|
||||||
|
}
|
||||||
|
|
||||||
if (!opt.quiet)
|
if (!opt.quiet)
|
||||||
{
|
{
|
||||||
@ -683,6 +691,10 @@ proc_encrypted (CTX c, PACKET *pkt)
|
|||||||
if (!result)
|
if (!result)
|
||||||
result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek );
|
result = decrypt_data (c->ctrl, c, pkt->pkt.encrypted, c->dek );
|
||||||
|
|
||||||
|
/* Trigger the deferred error. */
|
||||||
|
if (!result && early_plaintext)
|
||||||
|
result = gpg_error (GPG_ERR_BAD_DATA);
|
||||||
|
|
||||||
if (result == -1)
|
if (result == -1)
|
||||||
;
|
;
|
||||||
else if (!result
|
else if (!result
|
||||||
@ -788,7 +800,14 @@ proc_plaintext( CTX c, PACKET *pkt )
|
|||||||
if (pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8))
|
if (pt->namelen == 8 && !memcmp( pt->name, "_CONSOLE", 8))
|
||||||
log_info (_("Note: sender requested \"for-your-eyes-only\"\n"));
|
log_info (_("Note: sender requested \"for-your-eyes-only\"\n"));
|
||||||
else if (opt.verbose)
|
else if (opt.verbose)
|
||||||
log_info (_("original file name='%.*s'\n"), pt->namelen, pt->name);
|
{
|
||||||
|
/* We don't use print_utf8_buffer because that would require a
|
||||||
|
* string change which we don't want in 2.2. It is also not
|
||||||
|
* clear whether the filename is always utf-8 encoded. */
|
||||||
|
char *tmp = make_printable_string (pt->name, pt->namelen, 0);
|
||||||
|
log_info (_("original file name='%.*s'\n"), (int)strlen (tmp), tmp);
|
||||||
|
xfree (tmp);
|
||||||
|
}
|
||||||
|
|
||||||
free_md_filter_context (&c->mfx);
|
free_md_filter_context (&c->mfx);
|
||||||
if (gcry_md_open (&c->mfx.md, 0, 0))
|
if (gcry_md_open (&c->mfx.md, 0, 0))
|
||||||
@ -1681,7 +1700,7 @@ akl_has_wkd_method (void)
|
|||||||
/* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN.
|
/* Return the ISSUER fingerprint buffer and its lenbgth at R_LEN.
|
||||||
* Returns NULL if not available. The returned buffer is valid as
|
* Returns NULL if not available. The returned buffer is valid as
|
||||||
* long as SIG is not modified. */
|
* long as SIG is not modified. */
|
||||||
static const byte *
|
const byte *
|
||||||
issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
|
issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
|
||||||
{
|
{
|
||||||
const byte *p;
|
const byte *p;
|
||||||
@ -1698,7 +1717,7 @@ issuer_fpr_raw (PKT_signature *sig, size_t *r_len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return the ISSUER fingerprint string in human readbale format if
|
/* Return the ISSUER fingerprint string in human readable format if
|
||||||
* available. Caller must release the string. */
|
* available. Caller must release the string. */
|
||||||
/* FIXME: Move to another file. */
|
/* FIXME: Move to another file. */
|
||||||
char *
|
char *
|
||||||
@ -2064,7 +2083,7 @@ check_sig_and_print (CTX c, kbnode_t node)
|
|||||||
* keyblock has already been fetched. Thus we could use the
|
* keyblock has already been fetched. Thus we could use the
|
||||||
* fingerprint or PK itself to lookup the entire keyblock. That
|
* fingerprint or PK itself to lookup the entire keyblock. That
|
||||||
* would best be done with a cache. */
|
* would best be done with a cache. */
|
||||||
keyblock = get_pubkeyblock (c->ctrl, sig->keyid);
|
keyblock = get_pubkeyblock_for_sig (c->ctrl, sig);
|
||||||
|
|
||||||
snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ",
|
snprintf (keyid_str, sizeof keyid_str, "%08lX%08lX [uncertain] ",
|
||||||
(ulong)sig->keyid[0], (ulong)sig->keyid[1]);
|
(ulong)sig->keyid[0], (ulong)sig->keyid[1]);
|
||||||
|
@ -244,6 +244,7 @@ typedef struct
|
|||||||
const byte *trust_regexp;
|
const byte *trust_regexp;
|
||||||
struct revocation_key *revkey;
|
struct revocation_key *revkey;
|
||||||
int numrevkeys;
|
int numrevkeys;
|
||||||
|
int help_counter; /* Used internally bu some fucntions. */
|
||||||
pka_info_t *pka_info; /* Malloced PKA data or NULL if not
|
pka_info_t *pka_info; /* Malloced PKA data or NULL if not
|
||||||
available. See also flags.pka_tried. */
|
available. See also flags.pka_tried. */
|
||||||
char *signers_uid; /* Malloced value of the SIGNERS_UID
|
char *signers_uid; /* Malloced value of the SIGNERS_UID
|
||||||
@ -630,6 +631,7 @@ int proc_signature_packets_by_fd (ctrl_t ctrl,
|
|||||||
int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a);
|
int proc_encryption_packets (ctrl_t ctrl, void *ctx, iobuf_t a);
|
||||||
int list_packets( iobuf_t a );
|
int list_packets( iobuf_t a );
|
||||||
|
|
||||||
|
const byte *issuer_fpr_raw (PKT_signature *sig, size_t *r_len);
|
||||||
char *issuer_fpr_string (PKT_signature *sig);
|
char *issuer_fpr_string (PKT_signature *sig);
|
||||||
|
|
||||||
/*-- parse-packet.c --*/
|
/*-- parse-packet.c --*/
|
||||||
|
@ -113,7 +113,7 @@ void
|
|||||||
show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode)
|
show_revocation_reason (ctrl_t ctrl, PKT_public_key *pk, int mode)
|
||||||
{
|
{
|
||||||
/* Hmmm, this is not so easy because we have to duplicate the code
|
/* Hmmm, this is not so easy because we have to duplicate the code
|
||||||
* used in the trustbd to calculate the keyflags. We need to find
|
* used in the trustdb to calculate the keyflags. We need to find
|
||||||
* a clean way to check revocation certificates on keys and
|
* a clean way to check revocation certificates on keys and
|
||||||
* signatures. And there should be no duplicate code. Because we
|
* signatures. And there should be no duplicate code. Because we
|
||||||
* enter this function only when the trustdb told us that we have
|
* enter this function only when the trustdb told us that we have
|
||||||
@ -548,7 +548,7 @@ check_signatures_trust (ctrl_t ctrl, PKT_signature *sig)
|
|||||||
unsigned int trustlevel = TRUST_UNKNOWN;
|
unsigned int trustlevel = TRUST_UNKNOWN;
|
||||||
int rc=0;
|
int rc=0;
|
||||||
|
|
||||||
rc = get_pubkey (ctrl, pk, sig->keyid );
|
rc = get_pubkey_for_sig (ctrl, pk, sig);
|
||||||
if (rc)
|
if (rc)
|
||||||
{ /* this should not happen */
|
{ /* this should not happen */
|
||||||
log_error("Ooops; the key vanished - can't check the trust\n");
|
log_error("Ooops; the key vanished - can't check the trust\n");
|
||||||
|
@ -156,7 +156,7 @@ check_signature2 (ctrl_t ctrl,
|
|||||||
log_info(_("WARNING: signature digest conflict in message\n"));
|
log_info(_("WARNING: signature digest conflict in message\n"));
|
||||||
rc = gpg_error (GPG_ERR_GENERAL);
|
rc = gpg_error (GPG_ERR_GENERAL);
|
||||||
}
|
}
|
||||||
else if (get_pubkey (ctrl, pk, sig->keyid))
|
else if (get_pubkey_for_sig (ctrl, pk, sig))
|
||||||
rc = gpg_error (GPG_ERR_NO_PUBKEY);
|
rc = gpg_error (GPG_ERR_NO_PUBKEY);
|
||||||
else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
|
else if (!gnupg_pk_is_allowed (opt.compliance, PK_USE_VERIFICATION,
|
||||||
pk->pubkey_algo, pk->pkey,
|
pk->pubkey_algo, pk->pkey,
|
||||||
@ -478,8 +478,17 @@ check_signature_end_simple (PKT_public_key *pk, PKT_signature *sig,
|
|||||||
sig->sig_class, pk->pubkey_usage);
|
sig->sig_class, pk->pubkey_usage);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
/* Fixme: Should we also check the signing capability here for data
|
|
||||||
* signature? */
|
/* For data signatures check that the key has sign usage. */
|
||||||
|
if (IS_SIG (sig) && !(pk->pubkey_usage & PUBKEY_USAGE_SIG))
|
||||||
|
{
|
||||||
|
rc = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
|
||||||
|
if (!opt.quiet)
|
||||||
|
log_info (_("bad data signature from key %s: %s (0x%02x, 0x%x)\n"),
|
||||||
|
keystr_from_pk (pk), gpg_strerror (rc),
|
||||||
|
sig->sig_class, pk->pubkey_usage);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
/* Make sure the digest algo is enabled (in case of a detached
|
/* Make sure the digest algo is enabled (in case of a detached
|
||||||
* signature). */
|
* signature). */
|
||||||
@ -917,7 +926,7 @@ check_signature_over_key_or_uid (ctrl_t ctrl, PKT_public_key *signer,
|
|||||||
if (IS_CERT (sig))
|
if (IS_CERT (sig))
|
||||||
signer->req_usage = PUBKEY_USAGE_CERT;
|
signer->req_usage = PUBKEY_USAGE_CERT;
|
||||||
|
|
||||||
rc = get_pubkey (ctrl, signer, sig->keyid);
|
rc = get_pubkey_for_sig (ctrl, signer, sig);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
xfree (signer);
|
xfree (signer);
|
||||||
|
@ -772,7 +772,7 @@ write_signature_packets (ctrl_t ctrl,
|
|||||||
gpg_strerror (rc));
|
gpg_strerror (rc));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
xfree (sig);
|
free_seckey_enc (sig);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
|
@ -535,3 +535,17 @@ tofu_notice_key_changed (ctrl_t ctrl, kbnode_t kb)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
get_revocation_reason (PKT_signature *sig, char **r_reason,
|
||||||
|
char **r_comment, size_t *r_commentlen)
|
||||||
|
{
|
||||||
|
(void)sig;
|
||||||
|
(void)r_commentlen;
|
||||||
|
|
||||||
|
if (r_reason)
|
||||||
|
*r_reason = NULL;
|
||||||
|
if (r_comment)
|
||||||
|
*r_comment = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
388
g10/trust.c
388
g10/trust.c
@ -437,391 +437,3 @@ get_validity_string (ctrl_t ctrl, PKT_public_key *pk, PKT_user_id *uid)
|
|||||||
return _("revoked");
|
return _("revoked");
|
||||||
return trust_value_to_string (trustlevel);
|
return trust_value_to_string (trustlevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Mark the signature of the given UID which are used to certify it.
|
|
||||||
* To do this, we first revmove all signatures which are not valid and
|
|
||||||
* from the remain ones we look for the latest one. If this is not a
|
|
||||||
* certification revocation signature we mark the signature by setting
|
|
||||||
* node flag bit 8. Revocations are marked with flag 11, and sigs
|
|
||||||
* from unavailable keys are marked with flag 12. Note that flag bits
|
|
||||||
* 9 and 10 are used for internal purposes.
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
|
||||||
u32 *main_kid, struct key_item *klist,
|
|
||||||
u32 curtime, u32 *next_expire)
|
|
||||||
{
|
|
||||||
kbnode_t node;
|
|
||||||
PKT_signature *sig;
|
|
||||||
|
|
||||||
/* First check all signatures. */
|
|
||||||
for (node=uidnode->next; node; node = node->next)
|
|
||||||
{
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
|
|
||||||
if (node->pkt->pkttype == PKT_USER_ID
|
|
||||||
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
||||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
||||||
break; /* ready */
|
|
||||||
if (node->pkt->pkttype != PKT_SIGNATURE)
|
|
||||||
continue;
|
|
||||||
sig = node->pkt->pkt.signature;
|
|
||||||
if (main_kid
|
|
||||||
&& sig->keyid[0] == main_kid[0] && sig->keyid[1] == main_kid[1])
|
|
||||||
continue; /* ignore self-signatures if we pass in a main_kid */
|
|
||||||
if (!IS_UID_SIG(sig) && !IS_UID_REV(sig))
|
|
||||||
continue; /* we only look at these signature classes */
|
|
||||||
if(sig->sig_class>=0x11 && sig->sig_class<=0x13 &&
|
|
||||||
sig->sig_class-0x10<opt.min_cert_level)
|
|
||||||
continue; /* treat anything under our min_cert_level as an
|
|
||||||
invalid signature */
|
|
||||||
if (klist && !is_in_klist (klist, sig))
|
|
||||||
continue; /* no need to check it then */
|
|
||||||
if ((rc=check_key_signature (ctrl, keyblock, node, NULL)))
|
|
||||||
{
|
|
||||||
/* we ignore anything that won't verify, but tag the
|
|
||||||
no_pubkey case */
|
|
||||||
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
|
|
||||||
node->flag |= 1<<12;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
node->flag |= 1<<9;
|
|
||||||
}
|
|
||||||
/* Reset the remaining flags. */
|
|
||||||
for (; node; node = node->next)
|
|
||||||
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
|
|
||||||
|
|
||||||
/* kbnode flag usage: bit 9 is here set for signatures to consider,
|
|
||||||
* bit 10 will be set by the loop to keep track of keyIDs already
|
|
||||||
* processed, bit 8 will be set for the usable signatures, and bit
|
|
||||||
* 11 will be set for usable revocations. */
|
|
||||||
|
|
||||||
/* For each cert figure out the latest valid one. */
|
|
||||||
for (node=uidnode->next; node; node = node->next)
|
|
||||||
{
|
|
||||||
KBNODE n, signode;
|
|
||||||
u32 kid[2];
|
|
||||||
u32 sigdate;
|
|
||||||
|
|
||||||
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
||||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
||||||
break;
|
|
||||||
if ( !(node->flag & (1<<9)) )
|
|
||||||
continue; /* not a node to look at */
|
|
||||||
if ( (node->flag & (1<<10)) )
|
|
||||||
continue; /* signature with a keyID already processed */
|
|
||||||
node->flag |= (1<<10); /* mark this node as processed */
|
|
||||||
sig = node->pkt->pkt.signature;
|
|
||||||
signode = node;
|
|
||||||
sigdate = sig->timestamp;
|
|
||||||
kid[0] = sig->keyid[0]; kid[1] = sig->keyid[1];
|
|
||||||
|
|
||||||
/* Now find the latest and greatest signature */
|
|
||||||
for (n=uidnode->next; n; n = n->next)
|
|
||||||
{
|
|
||||||
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
||||||
|| n->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
||||||
break;
|
|
||||||
if ( !(n->flag & (1<<9)) )
|
|
||||||
continue;
|
|
||||||
if ( (n->flag & (1<<10)) )
|
|
||||||
continue; /* shortcut already processed signatures */
|
|
||||||
sig = n->pkt->pkt.signature;
|
|
||||||
if (kid[0] != sig->keyid[0] || kid[1] != sig->keyid[1])
|
|
||||||
continue;
|
|
||||||
n->flag |= (1<<10); /* mark this node as processed */
|
|
||||||
|
|
||||||
/* If signode is nonrevocable and unexpired and n isn't,
|
|
||||||
then take signode (skip). It doesn't matter which is
|
|
||||||
older: if signode was older then we don't want to take n
|
|
||||||
as signode is nonrevocable. If n was older then we're
|
|
||||||
automatically fine. */
|
|
||||||
|
|
||||||
if(((IS_UID_SIG(signode->pkt->pkt.signature) &&
|
|
||||||
!signode->pkt->pkt.signature->flags.revocable &&
|
|
||||||
(signode->pkt->pkt.signature->expiredate==0 ||
|
|
||||||
signode->pkt->pkt.signature->expiredate>curtime))) &&
|
|
||||||
(!(IS_UID_SIG(n->pkt->pkt.signature) &&
|
|
||||||
!n->pkt->pkt.signature->flags.revocable &&
|
|
||||||
(n->pkt->pkt.signature->expiredate==0 ||
|
|
||||||
n->pkt->pkt.signature->expiredate>curtime))))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* If n is nonrevocable and unexpired and signode isn't,
|
|
||||||
then take n. Again, it doesn't matter which is older: if
|
|
||||||
n was older then we don't want to take signode as n is
|
|
||||||
nonrevocable. If signode was older then we're
|
|
||||||
automatically fine. */
|
|
||||||
|
|
||||||
if((!(IS_UID_SIG(signode->pkt->pkt.signature) &&
|
|
||||||
!signode->pkt->pkt.signature->flags.revocable &&
|
|
||||||
(signode->pkt->pkt.signature->expiredate==0 ||
|
|
||||||
signode->pkt->pkt.signature->expiredate>curtime))) &&
|
|
||||||
((IS_UID_SIG(n->pkt->pkt.signature) &&
|
|
||||||
!n->pkt->pkt.signature->flags.revocable &&
|
|
||||||
(n->pkt->pkt.signature->expiredate==0 ||
|
|
||||||
n->pkt->pkt.signature->expiredate>curtime))))
|
|
||||||
{
|
|
||||||
signode = n;
|
|
||||||
sigdate = sig->timestamp;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* At this point, if it's newer, it goes in as the only
|
|
||||||
remaining possibilities are signode and n are both either
|
|
||||||
revocable or expired or both nonrevocable and unexpired.
|
|
||||||
If the timestamps are equal take the later ordered
|
|
||||||
packet, presuming that the key packets are hopefully in
|
|
||||||
their original order. */
|
|
||||||
|
|
||||||
if (sig->timestamp >= sigdate)
|
|
||||||
{
|
|
||||||
signode = n;
|
|
||||||
sigdate = sig->timestamp;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sig = signode->pkt->pkt.signature;
|
|
||||||
if (IS_UID_SIG (sig))
|
|
||||||
{ /* this seems to be a usable one which is not revoked.
|
|
||||||
* Just need to check whether there is an expiration time,
|
|
||||||
* We do the expired certification after finding a suitable
|
|
||||||
* certification, the assumption is that a signator does not
|
|
||||||
* want that after the expiration of his certificate the
|
|
||||||
* system falls back to an older certification which has a
|
|
||||||
* different expiration time */
|
|
||||||
const byte *p;
|
|
||||||
u32 expire;
|
|
||||||
|
|
||||||
p = parse_sig_subpkt (sig->hashed, SIGSUBPKT_SIG_EXPIRE, NULL );
|
|
||||||
expire = p? sig->timestamp + buf32_to_u32(p) : 0;
|
|
||||||
|
|
||||||
if (expire==0 || expire > curtime )
|
|
||||||
{
|
|
||||||
signode->flag |= (1<<8); /* yeah, found a good cert */
|
|
||||||
if (next_expire && expire && expire < *next_expire)
|
|
||||||
*next_expire = expire;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
signode->flag |= (1<<11);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static int
|
|
||||||
clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
|
||||||
int noisy, int self_only)
|
|
||||||
{
|
|
||||||
int deleted = 0;
|
|
||||||
kbnode_t node;
|
|
||||||
u32 keyid[2];
|
|
||||||
|
|
||||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
|
||||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
|
||||||
|
|
||||||
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
|
|
||||||
|
|
||||||
/* Passing in a 0 for current time here means that we'll never weed
|
|
||||||
out an expired sig. This is correct behavior since we want to
|
|
||||||
keep the most recent expired sig in a series. */
|
|
||||||
mark_usable_uid_certs (ctrl, keyblock, uidnode, NULL, NULL, 0, NULL);
|
|
||||||
|
|
||||||
/* What we want to do here is remove signatures that are not
|
|
||||||
considered as part of the trust calculations. Thus, all invalid
|
|
||||||
signatures are out, as are any signatures that aren't the last of
|
|
||||||
a series of uid sigs or revocations It breaks down like this:
|
|
||||||
coming out of mark_usable_uid_certs, if a sig is unflagged, it is
|
|
||||||
not even a candidate. If a sig has flag 9 or 10, that means it
|
|
||||||
was selected as a candidate and vetted. If a sig has flag 8 it
|
|
||||||
is a usable signature. If a sig has flag 11 it is a usable
|
|
||||||
revocation. If a sig has flag 12 it was issued by an unavailable
|
|
||||||
key. "Usable" here means the most recent valid
|
|
||||||
signature/revocation in a series from a particular signer.
|
|
||||||
|
|
||||||
Delete everything that isn't a usable uid sig (which might be
|
|
||||||
expired), a usable revocation, or a sig from an unavailable
|
|
||||||
key. */
|
|
||||||
|
|
||||||
for (node=uidnode->next;
|
|
||||||
node && node->pkt->pkttype==PKT_SIGNATURE;
|
|
||||||
node=node->next)
|
|
||||||
{
|
|
||||||
int keep;
|
|
||||||
|
|
||||||
keep = self_only? (node->pkt->pkt.signature->keyid[0] == keyid[0]
|
|
||||||
&& node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1;
|
|
||||||
|
|
||||||
/* Keep usable uid sigs ... */
|
|
||||||
if ((node->flag & (1<<8)) && keep)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* ... and usable revocations... */
|
|
||||||
if ((node->flag & (1<<11)) && keep)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* ... and sigs from unavailable keys. */
|
|
||||||
/* disabled for now since more people seem to want sigs from
|
|
||||||
unavailable keys removed altogether. */
|
|
||||||
/*
|
|
||||||
if(node->flag & (1<<12))
|
|
||||||
continue;
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Everything else we delete */
|
|
||||||
|
|
||||||
/* At this point, if 12 is set, the signing key was unavailable.
|
|
||||||
If 9 or 10 is set, it's superseded. Otherwise, it's
|
|
||||||
invalid. */
|
|
||||||
|
|
||||||
if (noisy)
|
|
||||||
log_info ("removing signature from key %s on user ID \"%s\": %s\n",
|
|
||||||
keystr (node->pkt->pkt.signature->keyid),
|
|
||||||
uidnode->pkt->pkt.user_id->name,
|
|
||||||
node->flag&(1<<12)? "key unavailable":
|
|
||||||
node->flag&(1<<9)? "signature superseded"
|
|
||||||
/* */ :"invalid signature" );
|
|
||||||
|
|
||||||
delete_kbnode (node);
|
|
||||||
deleted++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* This is substantially easier than clean_sigs_from_uid since we just
|
|
||||||
have to establish if the uid has a valid self-sig, is not revoked,
|
|
||||||
and is not expired. Note that this does not take into account
|
|
||||||
whether the uid has a trust path to it - just whether the keyholder
|
|
||||||
themselves has certified the uid. Returns true if the uid was
|
|
||||||
compacted. To "compact" a user ID, we simply remove ALL signatures
|
|
||||||
except the self-sig that caused the user ID to be remove-worthy.
|
|
||||||
We don't actually remove the user ID packet itself since it might
|
|
||||||
be resurrected in a later merge. Note that this function requires
|
|
||||||
that the caller has already done a merge_keys_and_selfsig().
|
|
||||||
|
|
||||||
TODO: change the import code to allow importing a uid with only a
|
|
||||||
revocation if the uid already exists on the keyring. */
|
|
||||||
|
|
||||||
static int
|
|
||||||
clean_uid_from_key (kbnode_t keyblock, kbnode_t uidnode, int noisy)
|
|
||||||
{
|
|
||||||
kbnode_t node;
|
|
||||||
PKT_user_id *uid = uidnode->pkt->pkt.user_id;
|
|
||||||
int deleted = 0;
|
|
||||||
|
|
||||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
|
||||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
|
||||||
log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
|
|
||||||
|
|
||||||
/* Skip valid user IDs, compacted user IDs, and non-self-signed user
|
|
||||||
IDs if --allow-non-selfsigned-uid is set. */
|
|
||||||
if (uid->created
|
|
||||||
|| uid->flags.compacted
|
|
||||||
|| (!uid->flags.expired && !uid->flags.revoked && opt.allow_non_selfsigned_uid))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
for (node=uidnode->next;
|
|
||||||
node && node->pkt->pkttype == PKT_SIGNATURE;
|
|
||||||
node=node->next)
|
|
||||||
{
|
|
||||||
if (!node->pkt->pkt.signature->flags.chosen_selfsig)
|
|
||||||
{
|
|
||||||
delete_kbnode (node);
|
|
||||||
deleted = 1;
|
|
||||||
uidnode->pkt->pkt.user_id->flags.compacted = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (noisy)
|
|
||||||
{
|
|
||||||
const char *reason;
|
|
||||||
char *user = utf8_to_native (uid->name, uid->len, 0);
|
|
||||||
|
|
||||||
if (uid->flags.revoked)
|
|
||||||
reason = _("revoked");
|
|
||||||
else if (uid->flags.expired)
|
|
||||||
reason = _("expired");
|
|
||||||
else
|
|
||||||
reason = _("invalid");
|
|
||||||
|
|
||||||
log_info ("compacting user ID \"%s\" on key %s: %s\n",
|
|
||||||
user, keystr_from_pk (keyblock->pkt->pkt.public_key),
|
|
||||||
reason);
|
|
||||||
|
|
||||||
xfree (user);
|
|
||||||
}
|
|
||||||
|
|
||||||
return deleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* Needs to be called after a merge_keys_and_selfsig() */
|
|
||||||
void
|
|
||||||
clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
|
||||||
int noisy, int self_only, int *uids_cleaned, int *sigs_cleaned)
|
|
||||||
{
|
|
||||||
int dummy = 0;
|
|
||||||
|
|
||||||
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY
|
|
||||||
|| keyblock->pkt->pkttype == PKT_SECRET_KEY);
|
|
||||||
log_assert (uidnode->pkt->pkttype==PKT_USER_ID);
|
|
||||||
|
|
||||||
if (!uids_cleaned)
|
|
||||||
uids_cleaned = &dummy;
|
|
||||||
|
|
||||||
if (!sigs_cleaned)
|
|
||||||
sigs_cleaned = &dummy;
|
|
||||||
|
|
||||||
/* Do clean_uid_from_key first since if it fires off, we don't have
|
|
||||||
to bother with the other. */
|
|
||||||
*uids_cleaned += clean_uid_from_key (keyblock, uidnode, noisy);
|
|
||||||
if (!uidnode->pkt->pkt.user_id->flags.compacted)
|
|
||||||
*sigs_cleaned += clean_sigs_from_uid (ctrl, keyblock, uidnode,
|
|
||||||
noisy, self_only);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* NB: This function marks the deleted nodes only and the caller is
|
|
||||||
* responsible to skip or remove them. */
|
|
||||||
void
|
|
||||||
clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
|
|
||||||
int *uids_cleaned, int *sigs_cleaned)
|
|
||||||
{
|
|
||||||
kbnode_t node;
|
|
||||||
|
|
||||||
merge_keys_and_selfsig (ctrl, keyblock);
|
|
||||||
|
|
||||||
for (node = keyblock->next;
|
|
||||||
node && !(node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
||||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
|
||||||
node = node->next)
|
|
||||||
{
|
|
||||||
if (node->pkt->pkttype == PKT_USER_ID)
|
|
||||||
clean_one_uid (ctrl, keyblock, node, noisy, self_only,
|
|
||||||
uids_cleaned, sigs_cleaned);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remove bogus subkey binding signatures: The only signatures
|
|
||||||
* allowed are of class 0x18 and 0x28. */
|
|
||||||
log_assert (!node || (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
||||||
|| node->pkt->pkttype == PKT_SECRET_SUBKEY));
|
|
||||||
for (; node; node = node->next)
|
|
||||||
{
|
|
||||||
if (is_deleted_kbnode (node))
|
|
||||||
continue;
|
|
||||||
if (node->pkt->pkttype == PKT_SIGNATURE
|
|
||||||
&& !(IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
|
||||||
|| IS_SUBKEY_REV (node->pkt->pkt.signature)))
|
|
||||||
{
|
|
||||||
delete_kbnode (node);
|
|
||||||
if (sigs_cleaned)
|
|
||||||
++*sigs_cleaned;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
#include "tdbio.h"
|
#include "tdbio.h"
|
||||||
#include "trustdb.h"
|
#include "trustdb.h"
|
||||||
#include "tofu.h"
|
#include "tofu.h"
|
||||||
|
#include "key-clean.h"
|
||||||
|
|
||||||
|
|
||||||
typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
|
typedef struct key_item **KeyHashTable; /* see new_key_hash_table() */
|
||||||
|
@ -46,36 +46,6 @@
|
|||||||
#define NAMEHASH_LEN 20
|
#define NAMEHASH_LEN 20
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* A structure to store key identification as well as some stuff needed
|
|
||||||
* for validation
|
|
||||||
*/
|
|
||||||
struct key_item {
|
|
||||||
struct key_item *next;
|
|
||||||
unsigned int ownertrust,min_ownertrust;
|
|
||||||
byte trust_depth;
|
|
||||||
byte trust_value;
|
|
||||||
char *trust_regexp;
|
|
||||||
u32 kid[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Check whether the signature SIG is in the klist K.
|
|
||||||
*/
|
|
||||||
static inline struct key_item *
|
|
||||||
is_in_klist (struct key_item *k, PKT_signature *sig)
|
|
||||||
{
|
|
||||||
for (; k; k = k->next)
|
|
||||||
{
|
|
||||||
if (k->kid[0] == sig->keyid[0] && k->kid[1] == sig->keyid[1])
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-- trust.c --*/
|
/*-- trust.c --*/
|
||||||
int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk);
|
int cache_disabled_value (ctrl_t ctrl, PKT_public_key *pk);
|
||||||
void register_trusted_keyid (u32 *keyid);
|
void register_trusted_keyid (u32 *keyid);
|
||||||
@ -103,17 +73,6 @@ int get_validity_info (ctrl_t ctrl, kbnode_t kb, PKT_public_key *pk,
|
|||||||
const char *get_validity_string (ctrl_t ctrl,
|
const char *get_validity_string (ctrl_t ctrl,
|
||||||
PKT_public_key *pk, PKT_user_id *uid);
|
PKT_public_key *pk, PKT_user_id *uid);
|
||||||
|
|
||||||
void mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
|
||||||
u32 *main_kid, struct key_item *klist,
|
|
||||||
u32 curtime, u32 *next_expire);
|
|
||||||
|
|
||||||
void clean_one_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
|
|
||||||
int noisy, int self_only,
|
|
||||||
int *uids_cleaned, int *sigs_cleaned);
|
|
||||||
void clean_key (ctrl_t ctrl, kbnode_t keyblock, int noisy, int self_only,
|
|
||||||
int *uids_cleaned,int *sigs_cleaned);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*-- trustdb.c --*/
|
/*-- trustdb.c --*/
|
||||||
void tdb_register_trusted_keyid (u32 *keyid);
|
void tdb_register_trusted_keyid (u32 *keyid);
|
||||||
|
58
po/Makevars
58
po/Makevars
@ -8,7 +8,63 @@ subdir = po
|
|||||||
top_builddir = ..
|
top_builddir = ..
|
||||||
|
|
||||||
# These options get passed to xgettext.
|
# These options get passed to xgettext.
|
||||||
XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ --keyword=L_
|
XGETTEXT_OPTIONS = \
|
||||||
|
--keyword=_ --keyword=N_ --keyword=L_ \
|
||||||
|
--flag=gcry_log_debug:1:c-format \
|
||||||
|
--flag=gpgrt_fprintf:2:c-format \
|
||||||
|
--flag=gpgrt_fprintf_unlocked:2:c-format \
|
||||||
|
--flag=gpgrt_printf:1:c-format \
|
||||||
|
--flag=gpgrt_printf_unlocked:1:c-format \
|
||||||
|
--flag=gpgrt_vfprintf:2:c-format \
|
||||||
|
--flag=gpgrt_vfprintf_unlocked:2:c-format \
|
||||||
|
--flag=gpgrt_asprintf:2:c-format \
|
||||||
|
--flag=gpgrt_vasprintf:2:c-format \
|
||||||
|
--flag=gpgrt_bsprintf:1:c-format \
|
||||||
|
--flag=gpgrt_vbsprintf:1:c-format \
|
||||||
|
--flag=gpgrt_snprintf:3:c-format \
|
||||||
|
--flag=gpgrt_vsnprintf:3:c-format \
|
||||||
|
--flag=gpgrt_log:2:c-format \
|
||||||
|
--flag=gpgrt_log_bug:1:c-format \
|
||||||
|
--flag=gpgrt_log_fatal:1:c-format \
|
||||||
|
--flag=gpgrt_log_error:1:c-format \
|
||||||
|
--flag=gpgrt_log_info:1:c-format \
|
||||||
|
--flag=gpgrt_log_debug:1:c-format \
|
||||||
|
--flag=gpgrt_log_debug_string:2:c-format \
|
||||||
|
--flag=gpgrt_log_printf:1:c-format \
|
||||||
|
--flag=gpgrt_log_printhex:3:c-format \
|
||||||
|
--flag=gpgrt_log_clock:1:c-format \
|
||||||
|
--flag=log_log:2:c-format \
|
||||||
|
--flag=log_bug:1:c-format \
|
||||||
|
--flag=log_fatal:1:c-format \
|
||||||
|
--flag=log_error:1:c-format \
|
||||||
|
--flag=log_info:1:c-format \
|
||||||
|
--flag=log_debug:1:c-format \
|
||||||
|
--flag=log_debug_string:2:c-format \
|
||||||
|
--flag=log_printf:1:c-format \
|
||||||
|
--flag=log_printhex:3:c-format \
|
||||||
|
--flag=log_clock:1:c-format
|
||||||
|
--flag=put_membuf_printf:2:c-format \
|
||||||
|
--flag=tty_printf:1:c-format \
|
||||||
|
--flag=tty_fprintf:2:c-format \
|
||||||
|
--flag=tty_getf:1:c-format \
|
||||||
|
--flag=writeout_para:2:c-format \
|
||||||
|
--flag=writeout_li:3:c-format \
|
||||||
|
--flag=writeout_rem:2:c-format \
|
||||||
|
--flag=xasprintf:1:c-format \
|
||||||
|
--flag=xtryasprintf:1:c-format \
|
||||||
|
--flag=log_debug_with_string:2:c-format \
|
||||||
|
--flag=print_assuan_status:3:c-format \
|
||||||
|
--flag=vprint_assuan_status:3:c-format \
|
||||||
|
--flag=agent_print_status:3:c-format \
|
||||||
|
--flag=dirmngr_status_helpf:2:c-format \
|
||||||
|
--flag=dirmngr_status_printf:3:c-format \
|
||||||
|
--flag=ks_printf_help:2:c-format \
|
||||||
|
--flag=print_further_info:1:c-format \
|
||||||
|
--flag=write_status_printf:2:c-format \
|
||||||
|
--flag=kbxd_print_status:3:c-format \
|
||||||
|
--flag=gpgconf_write_status:2:c-format \
|
||||||
|
--flag=wks_write_status:2:c-format
|
||||||
|
|
||||||
|
|
||||||
# This is the copyright holder that gets inserted into the header of the
|
# This is the copyright holder that gets inserted into the header of the
|
||||||
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
|
# $(DOMAIN).pot file. Set this to the copyright holder of the surrounding
|
||||||
|
@ -26,7 +26,6 @@ common/gettime.c
|
|||||||
common/ksba-io-support.c
|
common/ksba-io-support.c
|
||||||
|
|
||||||
common/argparse.c
|
common/argparse.c
|
||||||
common/logging.c
|
|
||||||
common/utf8conv.c
|
common/utf8conv.c
|
||||||
common/dotlock.c
|
common/dotlock.c
|
||||||
common/init.c
|
common/init.c
|
||||||
|
@ -33,7 +33,7 @@ static gpg_error_t
|
|||||||
run_sendmail (estream_t data)
|
run_sendmail (estream_t data)
|
||||||
{
|
{
|
||||||
gpg_error_t err;
|
gpg_error_t err;
|
||||||
const char pgmname[] = "/usr/lib/sendmail";
|
const char pgmname[] = NAME_OF_SENDMAIL;
|
||||||
const char *argv[3];
|
const char *argv[3];
|
||||||
|
|
||||||
argv[0] = "-oi";
|
argv[0] = "-oi";
|
||||||
|
@ -253,7 +253,7 @@ static void
|
|||||||
print_version (int with_help)
|
print_version (int with_help)
|
||||||
{
|
{
|
||||||
fputs (MYVERSION_LINE "\n"
|
fputs (MYVERSION_LINE "\n"
|
||||||
"Copyright (C) 2017 Free Software Foundation, Inc.\n"
|
GNUPG_DEF_COPYRIGHT_LINE "\n"
|
||||||
"License GPLv3+: "
|
"License GPLv3+: "
|
||||||
"GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\n"
|
"GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>\n"
|
||||||
"This is free software: you are free to change and redistribute it.\n"
|
"This is free software: you are free to change and redistribute it.\n"
|
||||||
|
Loading…
Reference in New Issue
Block a user