1
0
mirror of git://git.gnupg.org/gnupg.git synced 2024-06-16 00:29:50 +02:00

Merge branch 'master' into gniibe/t6275

This commit is contained in:
NIIBE Yutaka 2023-04-13 14:08:27 +09:00
commit 8dcfb5e4d0
No known key found for this signature in database
GPG Key ID: 640114AF89DE6054
111 changed files with 3600 additions and 1018 deletions

28
INSTALL
View File

@ -42,10 +42,12 @@ may remove or edit it.
you want to change it or regenerate `configure' using a newer version
of `autoconf'.
The simplest way to compile this package is:
The suggested way to compile this package is:
1. `cd' to the directory containing the package's source code and type
`./configure' to configure the package for your system.
1. `cd' to the directory containing the package's source code and
create a new directory named `build'. Then `cd' to that
directory and type `../configure' to configure the package for
your system.
Running `configure' might take a while. While running, it prints
some messages telling which features it is checking for.
@ -58,14 +60,17 @@ The simplest way to compile this package is:
4. Type `make install' to install the programs and any data files and
documentation.
5. You can remove the program binaries and object files from the
source code directory by typing `make clean'. To also remove the
files that `configure' created (so you can compile the package for
a different kind of computer), type `make distclean'. There is
also a `make maintainer-clean' target, but that is intended mainly
for the package's developers. If you use it, you may have to get
all sorts of other programs in order to regenerate files that came
with the distribution.
5. You can remove the program binaries and object files by deleting
all files from the `build' directory. In case you did not used a
dedicated build directory but build the software directly in the
source tree, you can remove the program binaries and object files
from the source code directory by typing `make clean'. To also
remove the files that `configure' created (so you can compile the
package for a different kind of computer), type `make distclean'.
There is also a `make maintainer-clean' target, but that is
intended mainly for the package's developers. If you use it, you
may have to get all sorts of other programs in order to
regenerate files that came with the distribution.
Compilers and Options
=====================
@ -231,4 +236,3 @@ an Autoconf bug. Until the bug is fixed you can use this workaround:
`configure' also accepts some other, not widely useful, options. Run
`configure --help' for more details.

28
NEWS
View File

@ -1,6 +1,34 @@
Noteworthy changes in version 2.4.1 (unreleased)
------------------------------------------------
* If the ~/.gnupg directory does not exist, the keyboxd is now
automagically enabled.
* gpg: New option --add-desig-revoker. [rG3d094e2bcf]
* gpg: New option --assert-signer.
* gpg: New list-option "show-unusable-sigs". Also show
"[self-signature]" instead of the user-id in key signature
listings. [rG103acfe9ca]
* gpg: For symmetric encryption the default S2K hash is now SHA256.
[T6367]
* gpgsm: Verification of detached signatures does now strip trailing
zeroes from the input if --assume-binary is used. [rG2a13f7f9dc]
* gpgsm: Non-armored detached signature are now created without
using indefinite form length octets. This improves compatibility
with some PDF signature verification software. [rG8996b0b655]
* dirmngr: The LDAP modifyTimestamp is now returned by some
keyserver commands. [rG56d309133f]
* gpg: Make list-options "show-sig-subpackets" work again.
Fixes regression in 2.4.0. [rG5a223303d7]
Noteworthy changes in version 2.4.0 (2022-12-16)
------------------------------------------------

10
README
View File

@ -53,7 +53,9 @@
As with all packages, you just have to do
./configure
mkdir build
cd build
../configure
make
make check
make install
@ -81,7 +83,8 @@
To quickly build all required software without installing it, the
Speedo method may be used:
make -f build-aux/speedo.mk native
cd build
make -f ../build-aux/speedo.mk native
This method downloads all required libraries and does a native build
of GnuPG to PLAY/inst/. GNU make is required and you need to set
@ -125,6 +128,9 @@
Only public keys and X.509 certificates are managed by the keyboxd;
private keys are still stored as separate files.
Since version 2.4.1 the keyboxd will be used by default for a fresh
install; i.e. if a ~/.gnupg directory did not yet exist.
Note that there is no automatic migration; if the use-keyboxd option
is enabled keys are not taken from pubring.kbx. To migrate existing
keys to the keyboxd do this:

View File

@ -141,13 +141,6 @@ struct
passphrase change. */
int enable_passphrase_history;
/* If set the extended key format is used for new keys. Note that
* this may have the value 2 in which case
* --disable-extended-key-format won't have any effect and thus
* effectivley locking it. This is required to support existing
* profiles which lock the use of --enable-extended-key-format. */
int enable_extended_key_format;
int running_detached; /* We are running detached from the tty. */
/* If this global option is true, the passphrase cache is ignored
@ -479,7 +472,7 @@ gpg_error_t agent_public_key_from_file (ctrl_t ctrl,
gcry_sexp_t *result);
gpg_error_t agent_ssh_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
gcry_sexp_t *result);
gcry_sexp_t *result, int *r_order);
int agent_pk_get_algo (gcry_sexp_t s_key);
int agent_is_tpm2_key(gcry_sexp_t s_key);
int agent_key_available (const unsigned char *grip);
@ -566,7 +559,7 @@ unsigned char get_standard_s2k_count_rfc4880 (void);
unsigned long get_standard_s2k_time (void);
int agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb);
unsigned long s2k_count);
gpg_error_t agent_unprotect (ctrl_t ctrl,
const unsigned char *protectedkey, const char *passphrase,
gnupg_isotime_t protected_at,

View File

@ -1543,6 +1543,17 @@ agent_askpin (ctrl_t ctrl,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
pininfo->with_repeat = 0; /* Pinentry does not support it. */
if (pininfo->with_repeat)
{
snprintf (line, DIM(line), "SETREPEATOK %s",
L_("Passphrases match."));
rc = assuan_transact (entry_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
rc = 0; /* Pinentry does not support it. */
}
}
pininfo->repeat_okay = 0;
pininfo->status = 0;
@ -1802,6 +1813,16 @@ agent_get_passphrase (ctrl_t ctrl,
if (rc)
pininfo->with_repeat = 0; /* Pinentry does not support it. */
if (pininfo->with_repeat)
{
snprintf (line, DIM(line), "SETREPEATOK %s",
L_("Passphrases match."));
rc = assuan_transact (entry_ctx, line,
NULL, NULL, NULL, NULL, NULL, NULL);
if (rc)
rc = 0; /* Pinentry does not support it. */
}
(void)setup_genpin (ctrl);
rc = setup_enforced_constraints (ctrl);

View File

@ -231,6 +231,22 @@ struct ssh_control_file_s
};
/* Two objects definition to hold keys for later sorting. */
struct key_collection_item_s
{
gcry_sexp_t key; /* Public key. (owned by us) */
char *cardsn; /* Serial number of a card or NULL. (owned by us) */
int order; /* Computed ordinal */
};
struct key_collection_s
{
struct key_collection_item_s *items;
size_t allocated;
size_t nitems;
};
/* Prototypes. */
static gpg_error_t ssh_handler_request_identities (ctrl_t ctrl,
estream_t request,
@ -1030,10 +1046,11 @@ read_control_file_item (ssh_control_file_t cf)
HEXGRIP is found; return success in this case and store true at
DISABLED if the found key has been disabled. If R_TTL is not NULL
a specified TTL for that key is stored there. If R_CONFIRM is not
NULL it is set to 1 if the key has the confirm flag set. */
NULL it is set to 1 if the key has the confirm flag set. The line
number where the item was found is stored at R_LNR. */
static gpg_error_t
search_control_file (ssh_control_file_t cf, const char *hexgrip,
int *r_disabled, int *r_ttl, int *r_confirm)
int *r_disabled, int *r_ttl, int *r_confirm, int *r_lnr)
{
gpg_error_t err;
@ -1045,6 +1062,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
*r_ttl = 0;
if (r_confirm)
*r_confirm = 0;
if (r_lnr)
*r_lnr = -1;
rewind_control_file (cf);
while (!(err=read_control_file_item (cf)))
@ -1062,6 +1081,8 @@ search_control_file (ssh_control_file_t cf, const char *hexgrip,
*r_ttl = cf->item.ttl;
if (r_confirm)
*r_confirm = cf->item.confirm;
if (r_lnr)
*r_lnr = cf->lnr;
}
return err;
}
@ -1090,7 +1111,7 @@ add_control_entry (ctrl_t ctrl, ssh_key_type_spec_t *spec,
if (err)
return err;
err = search_control_file (cf, hexgrip, &disabled, NULL, NULL);
err = search_control_file (cf, hexgrip, &disabled, NULL, NULL, NULL);
if (err && gpg_err_code(err) == GPG_ERR_EOF)
{
struct tm *tp;
@ -1141,7 +1162,7 @@ ttl_from_sshcontrol (const char *hexgrip)
if (open_control_file (&cf, 0))
return 0; /* Error: Use the global default TTL. */
if (search_control_file (cf, hexgrip, &disabled, &ttl, NULL)
if (search_control_file (cf, hexgrip, &disabled, &ttl, NULL, NULL)
|| disabled)
ttl = 0; /* Use the global default if not found or disabled. */
@ -1164,7 +1185,7 @@ confirm_flag_from_sshcontrol (const char *hexgrip)
if (open_control_file (&cf, 0))
return 1; /* Error: Better ask for confirmation. */
if (search_control_file (cf, hexgrip, &disabled, NULL, &confirm)
if (search_control_file (cf, hexgrip, &disabled, NULL, &confirm, NULL)
|| disabled)
confirm = 0; /* If not found or disabled, there is no reason to
ask for confirmation. */
@ -1250,7 +1271,8 @@ ssh_search_control_file (ssh_control_file_t cf,
if (i != 40)
err = gpg_error (GPG_ERR_INV_LENGTH);
else
err = search_control_file (cf, uphexgrip, r_disabled, r_ttl, r_confirm);
err = search_control_file (cf, uphexgrip, r_disabled, r_ttl, r_confirm,
NULL);
if (gpg_err_code (err) == GPG_ERR_EOF)
err = gpg_error (GPG_ERR_NOT_FOUND);
return err;
@ -2483,8 +2505,71 @@ get_ssh_keyinfo_on_cards (ctrl_t ctrl)
return keyinfo_on_cards;
}
/* Append (KEY,CARDSN,LNR,ORDER) to ARRAY. The array must initially
* be passed as a cleared struct. ARRAY takes ownership of KEY and
* CARDSN. */
static gpg_error_t
ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
add_to_key_array (struct key_collection_s *array, gcry_sexp_t key,
char *cardsn, int order)
{
if (array->nitems == array->allocated)
{
struct key_collection_item_s *newitems;
size_t newsize = ((array->allocated + 63)/64 + 1) * 64;
newitems = xtryreallocarray (array->items, array->allocated, newsize+1,
sizeof *newitems);
if (!newitems)
return gpg_error_from_syserror ();
array->allocated = newsize;
array->items = newitems;
}
array->items[array->nitems].key = key;
array->items[array->nitems].cardsn = cardsn;
array->items[array->nitems].order = order;
array->nitems++;
return 0;
}
/* Release the content of ARRAY. */
static void
free_key_array (struct key_collection_s *array)
{
if (array && array->items)
{
unsigned int n;
for (n = 0; n < array->nitems; n++)
{
gcry_sexp_release (array->items[n].key);
xfree (array->items[n].cardsn);
}
xfree (array->items);
}
}
/* Helper for the qsort in ssh_send_available_keys. */
static int
compare_key_collection_items (const void *arg_a, const void *arg_b)
{
const struct key_collection_item_s *a
= (const struct key_collection_item_s *)arg_a;
const struct key_collection_item_s *b
= (const struct key_collection_item_s *)arg_b;
int res;
res = a->order - b->order;
/* If we are comparing two cards we sort by serial number. */
if (!res && a->order == 1)
res = strcmp (a->cardsn?a->cardsn:"", b->cardsn?b->cardsn:"");
return res;
}
static gpg_error_t
ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *r_key_counter)
{
gpg_error_t err;
char *dirname;
@ -2495,6 +2580,8 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
struct card_key_info_s *keyinfo_on_cards, *l;
char *cardsn;
gcry_sexp_t key_public = NULL;
int count;
struct key_collection_s keyarray = { NULL };
err = open_control_file (&cf, 0);
if (err)
@ -2526,7 +2613,7 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
while ( (dir_entry = gnupg_readdir (dir)) )
{
struct card_key_info_s *l_prev = NULL;
int disabled, is_ssh;
int disabled, is_ssh, lnr, order;
unsigned char grip[20];
cardsn = NULL;
@ -2548,15 +2635,32 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
/* Check if it's listed in "ssh_control" file. */
disabled = is_ssh = 0;
err = search_control_file (cf, hexgrip, &disabled, NULL, NULL);
err = search_control_file (cf, hexgrip, &disabled, NULL, NULL, &lnr);
if (!err)
{
if (!disabled)
is_ssh = 1;
{
is_ssh = 1;
}
}
else if (gpg_err_code (err) != GPG_ERR_EOF)
break;
/* Clamp LNR value and set the ordinal.
* Current use of ordinals:
* 1..99999 - inserted cards (right now only 1)
* 100000..199999 - listed in sshcontrol
* 200000..299999 - order taken from Use-for-ssh
*/
if (is_ssh)
{
if (lnr < 1)
lnr = 0;
else if (lnr > 99999)
lnr = 99999;
order = lnr + 100000;
}
if (l)
{
err = card_key_available (ctrl, l, &key_public, &cardsn);
@ -2570,25 +2674,76 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
xfree (l->usage);
xfree (l);
l = NULL;
/* If we want to allow that the user to change the sorting
* order of card keys (which are sorted by their s/n), we
* would need to get the use-for-ssh: value from the stub
* file and set an appropriate ordinal. */
order = 1;
}
else if (is_ssh)
err = agent_public_key_from_file (ctrl, grip, &key_public);
else
/* Examine the file if it's suitable for SSH. */
err = agent_ssh_key_from_file (ctrl, grip, &key_public);
else /* Examine the file if it's suitable for SSH. */
{
err = agent_ssh_key_from_file (ctrl, grip, &key_public, &order);
if (order < 0 || err)
order = 0;
else if (order > 99999)
order = 99999;
order += 200000;
}
if (err)
{
/* Clear ERR, skiping the key in question. */
/* Clear ERR, skipping the key in question. */
err = 0;
continue;
}
err = ssh_send_key_public (key_blobs, key_public, cardsn);
xfree (cardsn);
err = add_to_key_array (&keyarray, key_public, cardsn, order);
if (err)
{
gcry_sexp_release (key_public);
xfree (cardsn);
goto leave;
}
}
gnupg_closedir (dir);
ssh_close_control_file (cf);
/* Lastly, handle remaining keys which don't have the stub files. */
for (l = keyinfo_on_cards, count=0; l; l = l->next, count++)
{
cardsn = NULL;
if (card_key_available (ctrl, l, &key_public, &cardsn))
continue;
err = add_to_key_array (&keyarray, key_public, cardsn, 300000+count);
if (err)
{
gcry_sexp_release (key_public);
xfree (cardsn);
goto leave;
}
}
/* Sort the array. */
qsort (keyarray.items, keyarray.nitems, sizeof *keyarray.items,
compare_key_collection_items);
if (opt.debug)
for (count=0; count < keyarray.nitems; count++)
log_debug ("sshkeys[%d]: order=%d, pubkey=%p sn=%s\n",
count, keyarray.items[count].order,
keyarray.items[count].key, keyarray.items[count].cardsn);
/* And print the keys. */
for (count=0; count < keyarray.nitems; count++)
{
err = ssh_send_key_public (key_blobs, keyarray.items[count].key,
keyarray.items[count].cardsn);
if (err)
{
if (opt.debug)
gcry_log_debugsxp ("pubkey", key_public);
gcry_log_debugsxp ("pubkey", keyarray.items[count].key);
if (gpg_err_code (err) == GPG_ERR_UNKNOWN_CURVE
|| gpg_err_code (err) == GPG_ERR_INV_CURVE)
{
@ -2597,54 +2752,14 @@ ssh_send_available_keys (ctrl_t ctrl, estream_t key_blobs, u32 *key_counter_p)
* We ignore them. */
}
else
{
gcry_sexp_release (key_public);
break; /* the readdir loop. */
}
goto leave;
}
else /* Success */
(*key_counter_p)++;
gcry_sexp_release (key_public);
}
*r_key_counter = count;
gnupg_closedir (dir);
ssh_close_control_file (cf);
/* Lastly, handle remaining keys which don't have the stub files. */
for (l = keyinfo_on_cards; l; l = l->next)
{
cardsn = NULL;
if (card_key_available (ctrl, l, &key_public, &cardsn))
continue;
err = ssh_send_key_public (key_blobs, key_public, cardsn);
xfree (cardsn);
if (err)
{
if (opt.debug)
gcry_log_debugsxp ("pubkey", key_public);
if (gpg_err_code (err) == GPG_ERR_UNKNOWN_CURVE
|| gpg_err_code (err) == GPG_ERR_INV_CURVE)
{
/* For example a Brainpool curve or a curve we don't
* support at all but a smartcard lists that curve.
* We ignore them. */
}
else
{
gcry_sexp_release (key_public);
break;
}
}
else /* Success. */
(*key_counter_p)++;
gcry_sexp_release (key_public);
}
leave:
agent_card_free_keyinfo (keyinfo_on_cards);
free_key_array (&keyarray);
return err;
}
@ -3027,7 +3142,7 @@ ssh_key_to_protected_buffer (gcry_sexp_t key, const char *passphrase,
buffer_new, buffer_new_n);
if (*passphrase)
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0, -1);
err = agent_protect (buffer_new, passphrase, buffer, buffer_n, 0);
else
{
/* The key derivation function does not support zero length

View File

@ -1218,12 +1218,6 @@ cmd_keyattr (assuan_context_t ctx, char *line)
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
if (!opt.enable_extended_key_format)
{
err = gpg_error (GPG_ERR_NOT_SUPPORTED);
goto leave;
}
opt_delete = has_option (line, "--delete");
line = skip_options (line);
@ -2497,14 +2491,17 @@ cmd_passwd (assuan_context_t ctx, char *line)
static const char hlp_preset_passphrase[] =
"PRESET_PASSPHRASE [--inquire] <string_or_keygrip> <timeout> [<hexstring>]\n"
"PRESET_PASSPHRASE [--inquire] [--restricted] \\\n"
" <string_or_keygrip> <timeout> [<hexstring>]\n"
"\n"
"Set the cached passphrase/PIN for the key identified by the keygrip\n"
"to passwd for the given time, where -1 means infinite and 0 means\n"
"the default (currently only a timeout of -1 is allowed, which means\n"
"to never expire it). If passwd is not provided, ask for it via the\n"
"pinentry module unless --inquire is passed in which case the passphrase\n"
"is retrieved from the client via a server inquire.\n";
"is retrieved from the client via a server inquire. The option\n"
"--restricted can be used to put the passphrase into the cache used\n"
"by restricted connections.";
static gpg_error_t
cmd_preset_passphrase (assuan_context_t ctx, char *line)
{
@ -2515,6 +2512,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line)
int ttl;
size_t len;
int opt_inquire;
int opt_restricted;
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
@ -2523,6 +2521,7 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line)
return set_error (GPG_ERR_NOT_SUPPORTED, "no --allow-preset-passphrase");
opt_inquire = has_option (line, "--inquire");
opt_restricted = has_option (line, "--restricted");
line = skip_options (line);
grip_clear = line;
while (*line && (*line != ' ' && *line != '\t'))
@ -2585,7 +2584,11 @@ cmd_preset_passphrase (assuan_context_t ctx, char *line)
if (!rc)
{
int save_restricted = ctrl->restricted;
if (opt_restricted)
ctrl->restricted = 1;
rc = agent_put_cache (ctrl, grip_clear, CACHE_MODE_ANY, passphrase, ttl);
ctrl->restricted = save_restricted;
if (opt_inquire)
{
wipememory (passphrase, len);
@ -2910,7 +2913,7 @@ cmd_import_key (assuan_context_t ctx, char *line)
if (passphrase)
{
err = agent_protect (key, passphrase, &finalkey, &finalkeylen,
ctrl->s2k_count, -1);
ctrl->s2k_count);
if (!err)
err = agent_write_private_key (grip, finalkey, finalkeylen, force,
NULL, NULL, opt_timestamp);

View File

@ -1146,7 +1146,7 @@ convert_from_openpgp_native (ctrl_t ctrl,
if (!agent_protect (*r_key, passphrase,
&protectedkey, &protectedkeylen,
ctrl->s2k_count, -1))
ctrl->s2k_count))
agent_write_private_key (grip, protectedkey, protectedkeylen, 1,
NULL, NULL, 0);
xfree (protectedkey);

View File

@ -2,6 +2,7 @@
* Copyright (C) 2001, 2002, 2003, 2004, 2005, 2007,
* 2010, 2011 Free Software Foundation, Inc.
* Copyright (C) 2014, 2019 Werner Koch
* Copyright (C) 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -79,19 +80,114 @@ linefeed_to_percent0A (const char *string)
}
/* Note: Ownership of FNAME and FP are moved to this function. */
static gpg_error_t
write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
const void *buf, size_t len,
const char *serialno, const char *keyref,
time_t timestamp)
/* Write the S-expression formatted key (BUFFER,LENGTH) to our key
* storage. With FORCE passed as true an existing key with the given
* GRIP will get overwritten. If SERIALNO and KEYREF are given a
* Token line is added to the key if the extended format is used. If
* TIMESTAMP is not zero and the key doies not yet exists it will be
* recorded as creation date. */
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref,
time_t timestamp)
{
gpg_error_t err;
char *fname;
estream_t fp;
char hexgrip[40+4+1];
int update, newkey;
nvc_t pk = NULL;
gcry_sexp_t key = NULL;
int remove = 0;
char *token = NULL;
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
hexgrip, NULL);
/* FIXME: Write to a temp file first so that write failures during
key updates won't lead to a key loss. */
if (!force && !gnupg_access (fname, F_OK))
{
log_error ("secret key file '%s' already exists\n", fname);
xfree (fname);
return gpg_error (GPG_ERR_EEXIST);
}
fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
if (!fp)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
{
fp = es_fopen (fname, "wbx,mode=-rw");
if (!fp)
tmperr = gpg_error_from_syserror ();
}
if (!fp)
{
log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
xfree (fname);
return tmperr;
}
update = 0;
newkey = 1;
}
else if (force)
{
gpg_error_t rc;
char first;
/* See if an existing key is in extended format. */
if (es_fread (&first, 1, 1, fp) != 1)
{
rc = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
rc = es_fseek (fp, 0, SEEK_SET);
if (rc)
{
log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
if (first == '(')
{
/* Key is still in the old format - force it into extended
* format. We do not request an update here because an
* existing key is not yet in extended key format and no
* extended infos are yet available. */
update = 0;
newkey = 0;
}
else
{
/* Key is already in the extended format. */
update = 1;
newkey = 0;
}
}
else
{
/* The key file did not exist: we assume this is a new key and
* write the Created: entry. */
update = 0;
newkey = 1;
}
if (update)
{
int line;
@ -115,10 +211,11 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
}
es_clearerr (fp);
err = gcry_sexp_sscan (&key, NULL, buf, len);
/* Turn (BUFFER,LENGTH) into a gcrypt s-expression and set it into
* our name value container. */
err = gcry_sexp_sscan (&key, NULL, buffer, length);
if (err)
goto leave;
err = nvc_set_private_key (pk, key);
if (err)
goto leave;
@ -153,7 +250,7 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
}
}
/* If a timestamp has been supplied and the key is new write a
/* If a timestamp has been supplied and the key is new, write a
* creation timestamp. (We douple check that there is no Created
* item yet.)*/
if (timestamp && newkey && !nvc_lookup (pk, "Created:"))
@ -166,7 +263,7 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
goto leave;
}
/* Back to start and write. */
err = es_fseek (fp, 0, SEEK_SET);
if (err)
goto leave;
@ -212,133 +309,6 @@ write_extended_private_key (char *fname, estream_t fp, int update, int newkey,
return err;
}
/* Write an S-expression formatted key to our key storage. With FORCE
* passed as true an existing key with the given GRIP will get
* overwritten. If SERIALNO and KEYREF are given a Token line is
* added to the key if the extended format is used. If TIMESTAMP is
* not zero and the key doies not yet exists it will be recorded as
* creation date. */
int
agent_write_private_key (const unsigned char *grip,
const void *buffer, size_t length, int force,
const char *serialno, const char *keyref,
time_t timestamp)
{
char *fname;
estream_t fp;
char hexgrip[40+4+1];
bin2hex (grip, 20, hexgrip);
strcpy (hexgrip+40, ".key");
fname = make_filename (gnupg_homedir (), GNUPG_PRIVATE_KEYS_DIR,
hexgrip, NULL);
/* FIXME: Write to a temp file first so that write failures during
key updates won't lead to a key loss. */
if (!force && !gnupg_access (fname, F_OK))
{
log_error ("secret key file '%s' already exists\n", fname);
xfree (fname);
return gpg_error (GPG_ERR_EEXIST);
}
fp = es_fopen (fname, force? "rb+,mode=-rw" : "wbx,mode=-rw");
if (!fp)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
if (force && gpg_err_code (tmperr) == GPG_ERR_ENOENT)
{
fp = es_fopen (fname, "wbx,mode=-rw");
if (!fp)
tmperr = gpg_error_from_syserror ();
}
if (!fp)
{
log_error ("can't create '%s': %s\n", fname, gpg_strerror (tmperr));
xfree (fname);
return tmperr;
}
}
else if (force)
{
gpg_error_t rc;
char first;
/* See if an existing key is in extended format. */
if (es_fread (&first, 1, 1, fp) != 1)
{
rc = gpg_error_from_syserror ();
log_error ("error reading first byte from '%s': %s\n",
fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
rc = es_fseek (fp, 0, SEEK_SET);
if (rc)
{
log_error ("error seeking in '%s': %s\n", fname, strerror (errno));
xfree (fname);
es_fclose (fp);
return rc;
}
if (first != '(')
{
/* Key is already in the extended format. */
return write_extended_private_key (fname, fp, 1, 0, buffer, length,
serialno, keyref, timestamp);
}
if (first == '(' && opt.enable_extended_key_format)
{
/* Key is in the old format - but we want the extended format. */
return write_extended_private_key (fname, fp, 0, 0, buffer, length,
serialno, keyref, timestamp);
}
}
if (opt.enable_extended_key_format)
return write_extended_private_key (fname, fp, 0, 1, buffer, length,
serialno, keyref, timestamp);
if (es_fwrite (buffer, length, 1, fp) != 1)
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error writing '%s': %s\n", fname, gpg_strerror (tmperr));
es_fclose (fp);
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
/* When force is given, the file might have to be truncated. */
if (force && ftruncate (es_fileno (fp), es_ftello (fp)))
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error truncating '%s': %s\n", fname, gpg_strerror (tmperr));
es_fclose (fp);
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
if (es_fclose (fp))
{
gpg_error_t tmperr = gpg_error_from_syserror ();
log_error ("error closing '%s': %s\n", fname, gpg_strerror (tmperr));
gnupg_remove (fname);
xfree (fname);
return tmperr;
}
bump_key_eventcounter ();
xfree (fname);
return 0;
}
gpg_error_t
agent_update_private_key (const unsigned char *grip, nvc_t pk)
@ -393,6 +363,7 @@ agent_update_private_key (const unsigned char *grip, nvc_t pk)
return err;
}
/* Callback function to try the unprotection from the passphrase query
code. */
static gpg_error_t
@ -1186,6 +1157,15 @@ agent_key_from_file (ctrl_t ctrl, const char *cache_nonce,
return gpg_error (GPG_ERR_NO_SECKEY);
err = read_key_file (grip? grip : ctrl->keygrip, &s_skey, &keymeta);
if (err)
{
if (gpg_err_code (err) == GPG_ERR_ENOENT)
err = gpg_error (GPG_ERR_NO_SECKEY);
else
log_error ("findkey: error reading key file: %s\n",
gpg_strerror (err));
return err;
}
/* For use with the protection functions we also need the key as an
canonical encoded S-expression in a buffer. Create this buffer
@ -1422,10 +1402,11 @@ agent_raw_key_from_file (ctrl_t ctrl, const unsigned char *grip,
/* Return the public key for the keygrip GRIP. The result is stored
at RESULT. This function extracts the public key from the private
key database. On failure an error code is returned and NULL stored
at RESULT. */
at RESULT. If R_SSHORDER is not NULL the ordinal from the
Use-for-ssh attribute is stored at that address. */
static gpg_error_t
public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
gcry_sexp_t *result, int for_ssh)
gcry_sexp_t *result, int for_ssh, int *r_sshorder)
{
gpg_error_t err;
int i, idx;
@ -1451,6 +1432,8 @@ public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
(void)ctrl;
*result = NULL;
if (r_sshorder)
*r_sshorder = 0;
err = read_key_file (grip, &s_skey, for_ssh? &keymeta : NULL);
if (err)
@ -1470,6 +1453,8 @@ public_key_from_file (ctrl_t ctrl, const unsigned char *grip,
if (!is_ssh)
return gpg_error (GPG_ERR_WRONG_KEY_USAGE);
if (r_sshorder)
*r_sshorder = is_ssh;
}
for (i=0; i < DIM (array); i++)
@ -1565,15 +1550,15 @@ agent_public_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
gcry_sexp_t *result)
{
return public_key_from_file (ctrl, grip, result, 0);
return public_key_from_file (ctrl, grip, result, 0, NULL);
}
gpg_error_t
agent_ssh_key_from_file (ctrl_t ctrl,
const unsigned char *grip,
gcry_sexp_t *result)
gcry_sexp_t *result, int *r_order)
{
return public_key_from_file (ctrl, grip, result, 1);
return public_key_from_file (ctrl, grip, result, 1, r_order);
}

View File

@ -57,7 +57,7 @@ store_key (gcry_sexp_t private, const char *passphrase, int force,
{
unsigned char *p;
rc = agent_protect (buf, passphrase, &p, &len, s2k_count, -1);
rc = agent_protect (buf, passphrase, &p, &len, s2k_count);
if (rc)
{
xfree (buf);

View File

@ -116,8 +116,6 @@ enum cmd_and_opt_values
oCheckSymPassphrasePattern,
oMaxPassphraseDays,
oEnablePassphraseHistory,
oDisableExtendedKeyFormat,
oEnableExtendedKeyFormat,
oStealSocket,
oUseStandardSocket,
oNoUseStandardSocket,
@ -147,6 +145,7 @@ enum cmd_and_opt_values
oS2KCalibration,
oAutoExpandSecmem,
oListenBacklog,
oInactivityTimeout,
oWriteEnvFile,
@ -185,7 +184,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oHomedir, "homedir", "@"),
ARGPARSE_conffile (oOptions, "options", N_("|FILE|read options from FILE")),
ARGPARSE_noconffile (oNoOptions, "no-options", "@"),
ARGPARSE_s_i (oInactivityTimeout, "inactivity-timeout", "@"),
ARGPARSE_header ("Monitor", N_("Options controlling the diagnostic output")),
@ -237,8 +236,6 @@ static gpgrt_opt_t opts[] = {
/* */ "@"
#endif
),
ARGPARSE_s_n (oDisableExtendedKeyFormat, "disable-extended-key-format", "@"),
ARGPARSE_s_n (oEnableExtendedKeyFormat, "enable-extended-key-format", "@"),
ARGPARSE_s_i (oListenBacklog, "listen-backlog", "@"),
ARGPARSE_op_u (oAutoExpandSecmem, "auto-expand-secmem", "@"),
ARGPARSE_s_s (oFakedSystemTime, "faked-system-time", "@"),
@ -314,7 +311,8 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_n (oNoUseStandardSocket, "no-use-standard-socket", "@"),
/* Dummy options. */
ARGPARSE_s_n (oNoop, "disable-extended-key-format", "@"),
ARGPARSE_s_n (oNoop, "enable-extended-key-format", "@"),
ARGPARSE_end () /* End of list */
};
@ -884,7 +882,6 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.check_sym_passphrase_pattern = NULL;
opt.max_passphrase_days = MAX_PASSPHRASE_DAYS;
opt.enable_passphrase_history = 0;
opt.enable_extended_key_format = 1;
opt.ignore_cache_for_signing = 0;
opt.allow_mark_trusted = 1;
opt.sys_trustlist_name = NULL;
@ -973,14 +970,6 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.enable_passphrase_history = 1;
break;
case oEnableExtendedKeyFormat:
opt.enable_extended_key_format = 2;
break;
case oDisableExtendedKeyFormat:
if (opt.enable_extended_key_format != 2)
opt.enable_extended_key_format = 0;
break;
case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break;
case oAllowMarkTrusted: opt.allow_mark_trusted = 1; break;

View File

@ -122,7 +122,9 @@ similar to the "shadow" parameter:
If given and the value is "yes" or "1" the key is allowed for use by
gpg-agent's ssh-agent implementation. This is thus the same as
putting the keygrip into the 'sshcontrol' file. Only one such item
should exist.
should exist. If another non-zero value between 1 and 99999 is used,
this is taken to establish the order in which the keys are returned to
ssh; lower numbers are returned first.
*** Use-for-p11
If given and the value is "yes" or "1" the key is allowed for use by

View File

@ -74,8 +74,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
no_shadow_info = 1;
else if (err)
{
if (gpg_err_code (err) != GPG_ERR_NO_SECKEY)
log_error ("failed to read the secret key\n");
log_error ("failed to read the secret key\n");
goto leave;
}
@ -88,7 +87,7 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
goto leave;
}
if (agent_is_tpm2_key (s_skey))
if (s_skey && agent_is_tpm2_key (s_skey))
err = divert_tpm2_pkdecrypt (ctrl, ciphertext, shadow_info,
&buf, &len, r_padding);
else
@ -96,7 +95,15 @@ agent_pkdecrypt (ctrl_t ctrl, const char *desc_text,
&buf, &len, r_padding);
if (err)
{
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
/* We restore the original error (ie. no seckey) is no card
* has been found and we have no shadow key. This avoids a
* surprising "card removed" error code. */
if ((gpg_err_code (err) == GPG_ERR_CARD_REMOVED
|| gpg_err_code (err) == GPG_ERR_CARD_NOT_PRESENT)
&& no_shadow_info)
err = gpg_error (GPG_ERR_NO_SECKEY);
else
log_error ("smartcard decryption failed: %s\n", gpg_strerror (err));
goto leave;
}

View File

@ -63,11 +63,13 @@ enum cmd_and_opt_values
oNoVerbose = 500,
oHomedir,
oRestricted,
aTest };
static const char *opt_passphrase;
static int opt_restricted;
static gpgrt_opt_t opts[] = {
@ -79,6 +81,7 @@ static gpgrt_opt_t opts[] = {
{ oForget, "forget", 256, "forget passphrase"},
{ oHomedir, "homedir", 2, "@" },
{ oRestricted, "restricted", 0, "put into the restricted cache"},
ARGPARSE_end ()
};
@ -156,7 +159,9 @@ preset_passphrase (const char *keygrip)
return;
}
rc = asprintf (&line, "PRESET_PASSPHRASE %s -1 %s\n", keygrip,
rc = asprintf (&line, "PRESET_PASSPHRASE %s%s -1 %s\n",
opt_restricted? "--restricted ":"",
keygrip,
passphrase_esc);
wipememory (passphrase_esc, strlen (passphrase_esc));
xfree (passphrase_esc);
@ -232,6 +237,8 @@ main (int argc, char **argv)
case oForget: cmd = oForget; break;
case oPassphrase: opt_passphrase = pargs.r.ret_str; break;
case oRestricted: opt_restricted = 1; break;
default : pargs.err = 2; break;
}
}

View File

@ -97,7 +97,6 @@ static const char *opt_passphrase;
static char *opt_prompt;
static int opt_status_msg;
static const char *opt_agent_program;
static int opt_debug_use_ocb;
static char *get_passphrase (int promptno);
static void release_passphrase (char *pw);
@ -343,8 +342,7 @@ read_and_protect (const char *fname)
return;
pw = get_passphrase (1);
rc = agent_protect (key, pw, &result, &resultlen, 0,
opt_debug_use_ocb? 1 : -1);
rc = agent_protect (key, pw, &result, &resultlen, 0);
release_passphrase (pw);
xfree (key);
if (rc)
@ -610,7 +608,7 @@ main (int argc, char **argv )
case oHaveCert: opt_have_cert = 1; break;
case oPrompt: opt_prompt = pargs.r.ret_str; break;
case oStatusMsg: opt_status_msg = 1; break;
case oDebugUseOCB: opt_debug_use_ocb = 1; break;
case oDebugUseOCB: /* dummy */; break;
default: pargs.err = ARGPARSE_PRINT_ERROR; break;
}

View File

@ -379,12 +379,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
const char *passphrase,
const char *timestamp_exp, size_t timestamp_exp_len,
unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb)
unsigned long s2k_count)
{
gcry_cipher_hd_t hd;
const char *modestr;
unsigned char hashvalue[20];
int blklen, enclen, outlen;
int enclen, outlen;
unsigned char *iv = NULL;
unsigned int ivsize; /* Size of the buffer allocated for IV. */
const unsigned char *s2ksalt; /* Points into IV. */
@ -398,44 +397,26 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*resultlen = 0;
*result = NULL;
modestr = (use_ocb? "openpgp-s2k3-ocb-aes"
/* */: "openpgp-s2k3-sha1-" PROT_CIPHER_STRING "-cbc");
modestr = "openpgp-s2k3-ocb-aes";
rc = gcry_cipher_open (&hd, PROT_CIPHER,
use_ocb? GCRY_CIPHER_MODE_OCB :
GCRY_CIPHER_MODE_CBC,
GCRY_CIPHER_MODE_OCB,
GCRY_CIPHER_SECURE);
if (rc)
return rc;
/* We need to work on a copy of the data because this makes it
* easier to add the trailer and the padding and more important we
* have to prefix the text with 2 parenthesis. In CBC mode we
* have to allocate enough space for:
*
* ((<parameter_list>)(4:hash4:sha120:<hashvalue>)) + padding
*
* we always append a full block of random bytes as padding but
* encrypt only what is needed for a full blocksize. In OCB mode we
* have to prefix the text with 2 parenthesis. Due to OCB mode we
* have to allocate enough space for just:
*
* ((<parameter_list>))
*/
blklen = gcry_cipher_get_algo_blklen (PROT_CIPHER);
if (use_ocb)
{
/* (( )) */
outlen = 2 + protlen + 2 ;
enclen = outlen + 16 /* taglen */;
outbuf = gcry_malloc_secure (enclen);
}
else
{
/* (( )( 4:hash 4:sha1 20:<hash> )) <padding> */
outlen = 2 + protlen + 2 + 6 + 6 + 23 + 2 + blklen;
enclen = outlen/blklen * blklen;
outbuf = gcry_malloc_secure (outlen);
}
/* (( )) */
outlen = 2 + protlen + 2 ;
enclen = outlen + 16 /* taglen */;
outbuf = gcry_malloc_secure (enclen);
if (!outbuf)
{
rc = out_of_core ();
@ -445,10 +426,10 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
/* Allocate a buffer for the nonce and the salt. */
if (!rc)
{
/* Allocate random bytes to be used as IV, padding and s2k salt
* or in OCB mode for a nonce and the s2k salt. The IV/nonce is
* set later because for OCB we need to set the key first. */
ivsize = (use_ocb? 12 : (blklen*2)) + 8;
/* Allocate random bytes to be used as nonce and s2k salt. The
* nonce is set later because for OCB we need to set the key
* first. */
ivsize = 12 + 8;
iv = xtrymalloc (ivsize);
if (!iv)
rc = gpg_error_from_syserror ();
@ -484,40 +465,17 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
goto leave;
/* Set the IV/nonce. */
rc = gcry_cipher_setiv (hd, iv, use_ocb? 12 : blklen);
rc = gcry_cipher_setiv (hd, iv, 12);
if (rc)
goto leave;
if (use_ocb)
{
/* In OCB Mode we use only the public key parameters as AAD. */
rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin);
if (!rc)
rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len);
if (!rc)
rc = gcry_cipher_authenticate
(hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
}
else
{
/* Hash the entire expression for CBC mode. Because
* TIMESTAMP_EXP won't get protected, we can't simply hash a
* continuous buffer but need to call md_write several times. */
gcry_md_hd_t md;
rc = gcry_md_open (&md, GCRY_MD_SHA1, 0 );
if (!rc)
{
gcry_md_write (md, hashbegin, protbegin - hashbegin);
gcry_md_write (md, protbegin, protlen);
gcry_md_write (md, timestamp_exp, timestamp_exp_len);
gcry_md_write (md, protbegin+protlen,
hashlen - (protbegin+protlen - hashbegin));
memcpy (hashvalue, gcry_md_read (md, GCRY_MD_SHA1), 20);
gcry_md_close (md);
}
}
/* In OCB Mode we use only the public key parameters as AAD. */
rc = gcry_cipher_authenticate (hd, hashbegin, protbegin - hashbegin);
if (!rc)
rc = gcry_cipher_authenticate (hd, timestamp_exp, timestamp_exp_len);
if (!rc)
rc = gcry_cipher_authenticate
(hd, protbegin+protlen, hashlen - (protbegin+protlen - hashbegin));
/* Encrypt. */
if (!rc)
@ -527,36 +485,15 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*p++ = '(';
memcpy (p, protbegin, protlen);
p += protlen;
if (use_ocb)
{
*p++ = ')';
*p++ = ')';
}
else
{
memcpy (p, ")(4:hash4:sha120:", 17);
p += 17;
memcpy (p, hashvalue, 20);
p += 20;
*p++ = ')';
*p++ = ')';
memcpy (p, iv+blklen, blklen); /* Add padding. */
p += blklen;
}
*p++ = ')';
*p++ = ')';
log_assert ( p - outbuf == outlen);
if (use_ocb)
gcry_cipher_final (hd);
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
if (!rc)
{
gcry_cipher_final (hd);
rc = gcry_cipher_encrypt (hd, outbuf, outlen, NULL, 0);
if (!rc)
{
log_assert (outlen + 16 == enclen);
rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
}
}
else
{
rc = gcry_cipher_encrypt (hd, outbuf, enclen, NULL, 0);
log_assert (outlen + 16 == enclen);
rc = gcry_cipher_gettag (hd, outbuf + outlen, 16);
}
}
@ -584,7 +521,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
(int)strlen (modestr), modestr,
&saltpos,
(unsigned int)strlen (countbuf), countbuf,
use_ocb? 12 : blklen, &ivpos, use_ocb? 12 : blklen, "",
12, &ivpos, 12, "",
enclen, &encpos, enclen, "");
if (!p)
{
@ -598,7 +535,7 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
*resultlen = strlen (p);
*result = (unsigned char*)p;
memcpy (p+saltpos, s2ksalt, 8);
memcpy (p+ivpos, iv, use_ocb? 12 : blklen);
memcpy (p+ivpos, iv, 12);
memcpy (p+encpos, outbuf, enclen);
xfree (iv);
xfree (outbuf);
@ -614,13 +551,11 @@ do_encryption (const unsigned char *hashbegin, size_t hashlen,
/* Protect the key encoded in canonical format in PLAINKEY. We assume
a valid S-Exp here. With USE_UCB set to -1 the default scheme is
used (ie. either CBC or OCB), set to 0 the old CBC mode is used,
and set to 1 OCB is used. */
* a valid S-Exp here. */
int
agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char **result, size_t *resultlen,
unsigned long s2k_count, int use_ocb)
unsigned long s2k_count)
{
int rc;
const char *parmlist;
@ -637,9 +572,6 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
unsigned char *p;
int have_curve = 0;
if (use_ocb == -1)
use_ocb = !!opt.enable_extended_key_format;
/* Create an S-expression with the protected-at timestamp. */
memcpy (timestamp_exp, "(12:protected-at15:", 19);
gnupg_get_isotime (timestamp_exp+19);
@ -743,7 +675,7 @@ agent_protect (const unsigned char *plainkey, const char *passphrase,
rc = do_encryption (hash_begin, hash_end - hash_begin + 1,
prot_begin, prot_end - prot_begin + 1,
passphrase, timestamp_exp, sizeof (timestamp_exp),
&protected, &protectedlen, s2k_count, use_ocb);
&protected, &protectedlen, s2k_count);
if (rc)
return rc;

View File

@ -196,7 +196,7 @@ test_agent_protect (void)
{
ret = agent_protect ((const unsigned char*)specs[i].key,
specs[i].passphrase,
&specs[i].result, &specs[i].resultlen, 0, -1);
&specs[i].result, &specs[i].resultlen, 0);
if (gpg_err_code (ret) != specs[i].ret_expected)
{
printf ("agent_protect(%d) returned '%i/%s'; expected '%i/%s'\n",

View File

@ -45,6 +45,7 @@ struct trustitem_s
constraints. */
int cm:1; /* Use chain model for validation. */
int qual:1; /* Root CA for qualified signatures. */
int de_vs:1; /* Root CA for de-vs compliant PKI. */
} flags;
unsigned char fpr[20]; /* The binary fingerprint. */
};
@ -324,6 +325,8 @@ read_one_trustfile (const char *fname, int systrust,
ti->flags.cm = 1;
else if (n == 4 && !memcmp (p, "qual", 4) && systrust)
ti->flags.qual = 1;
else if (n == 4 && !memcmp (p, "de-vs", 4) && systrust)
ti->flags.de_vs = 1;
else
log_error ("flag '%.*s' in '%s', line %d ignored\n",
n, p, fname, lnr);
@ -476,7 +479,8 @@ istrusted_internal (ctrl_t ctrl, const char *fpr, int *r_disabled,
in a locked state. */
if (already_locked)
;
else if (ti->flags.relax || ti->flags.cm || ti->flags.qual)
else if (ti->flags.relax || ti->flags.cm || ti->flags.qual
|| ti->flags.de_vs)
{
unlock_trusttable ();
locked = 0;
@ -487,6 +491,8 @@ istrusted_internal (ctrl_t ctrl, const char *fpr, int *r_disabled,
err = agent_write_status (ctrl,"TRUSTLISTFLAG", "cm", NULL);
if (!err && ti->flags.qual)
err = agent_write_status (ctrl,"TRUSTLISTFLAG", "qual",NULL);
if (!err && ti->flags.de_vs)
err = agent_write_status (ctrl,"TRUSTLISTFLAG", "de-vs",NULL);
}
if (!err)

View File

@ -699,9 +699,13 @@ speedo_pkg_w64_gpgex_configure = \
# External packages
#
# gcc 10.2 takes __udivdi3 from the exception handler DLL and thus
# requires it. This is a regression from gcc 8.3 and earlier. To fix
# this we need to pass -static-libgcc.
ifeq ($(TARGETOS),w32)
speedo_pkg_zlib_make_args = \
-fwin32/Makefile.gcc PREFIX=$(host)- IMPLIB=libz.dll.a
-fwin32/Makefile.gcc PREFIX=$(host)- IMPLIB=libz.dll.a \
LDFLAGS=-static-libgcc
speedo_pkg_zlib_make_args_inst = \
-fwin32/Makefile.gcc \

View File

@ -669,8 +669,6 @@ Section "GnuPG" SEC_gnupg
File "share/gnupg/sks-keyservers.netCA.pem"
SetOutPath "$INSTDIR\share\doc\gnupg\examples"
File "share/doc/gnupg/examples/VS-NfD.prf"
File "share/doc/gnupg/examples/Automatic.prf"
File "share/doc/gnupg/examples/pwpattern.list"
SetOutPath "$INSTDIR\share\locale\ca\LC_MESSAGES"
@ -1337,8 +1335,6 @@ Section "-un.gnupg"
Delete "$INSTDIR\bin\gpg-check-pattern.exe"
Delete "$INSTDIR\bin\gpg-wks-client.exe"
Delete "$INSTDIR\share\doc\gnupg\examples\VS-NfD.prf"
Delete "$INSTDIR\share\doc\gnupg\examples\Automatic.prf"
Delete "$INSTDIR\share\doc\gnupg\examples\pwpattern.list"
RMDir "$INSTDIR\share\doc\gnupg\examples"
@ -1466,7 +1462,8 @@ Function .onInit
;;!define MUI_LANGDLL_ALWAYSSHOW
!insertmacro MUI_LANGDLL_DISPLAY
Call G4wRunOnce
# Temporay disabled until we have fixed the DLL issue (wk 2023-04-05)
# Call G4wRunOnce
SetOutPath $TEMP
#!ifdef SOURCES

View File

@ -160,12 +160,6 @@ and then manually edited:
<Component Id="cmpB5509E83C14EE3080355A3EAF09D1C8D" Directory="dir6694D0A4AAD84EF827096DD86D1B4FA2" Guid="FEC81836-944E-4613-A498-E620B981EB04">
<File Id="fil0615847C26E386E0B892124531F2ABBC" KeyPath="yes" Source="$(var.SourceDir)\lib\libnpth.dll.a" Name="libnpth.imp"/>
</Component>
<Component Id="cmp909B0412FDFCFD5092D93932AF982A72" Directory="dirC2E6BF1CC65903EA3A1AD83349586122" Guid="D30E7138-0D1C-48F4-8F53-E1EC6333F610">
<File Id="fil322067E40CE41C36574A7CC520D75876" KeyPath="yes" Source="$(var.SourceDir)\share\doc\gnupg\examples\VS-NfD.prf" Name="VS-NfD.prf"/>
</Component>
<Component Id="cmp909B0412FDFCFD5092D93932AF982A73" Directory="dirC2E6BF1CC65903EA3A1AD83349586122" Guid="D30E7138-0D1C-48F4-8F53-E1EC6333F611">
<File Id="fil322067E40CE41C36574A7CC520D75877" KeyPath="yes" Source="$(var.SourceDir)\share\doc\gnupg\examples\Automatic.prf" Name="Automatic.prf"/>
</Component>
<Component Id="cmp909B0412FDFCFD5092D93932AF982A74" Directory="dirC2E6BF1CC65903EA3A1AD83349586122" Guid="D30E7138-0D1C-48F4-8F53-E1EC6333F612">
<File Id="fil322067E40CE41C36574A7CC520D75878" KeyPath="yes" Source="$(var.SourceDir)\share\doc\gnupg\examples\pwpattern.list" Name="pwpattern.list"/>
</Component>

View File

@ -1109,6 +1109,7 @@ proc_type_verify (audit_ctx_t ctx)
case GPG_ERR_CERT_REVOKED: ok = "bad"; break;
case GPG_ERR_NOT_ENABLED: ok = "disabled"; break;
case GPG_ERR_NO_CRL_KNOWN:
case GPG_ERR_INV_CRL_OBJ:
ok = _("no CRL found for certificate");
break;
case GPG_ERR_CRL_TOO_OLD:

View File

@ -60,6 +60,8 @@ static gpgrt_opt_t opts[] = {
};
struct gnupg_comopt_s comopt = {NULL};
/* Parse the common options in the homedir and etc. This needs to be
* called after the gpgrt config directories are set. MODULE_ID is one of

View File

@ -35,14 +35,16 @@
/* Common options for all GnuPG components. */
EXTERN_UNLESS_MAIN_MODULE
struct
struct gnupg_comopt_s
{
char *logfile; /* Socket used by daemons for logging. */
int use_keyboxd; /* Use the keyboxd as storage backend. */
int no_autostart; /* Do not start gpg-agent. */
char *keyboxd_program; /* Use this as keyboxd program. */
} comopt;
};
extern struct gnupg_comopt_s comopt;
gpg_error_t parse_comopt (int module_id, int verbose);

View File

@ -789,8 +789,42 @@ gnupg_maybe_make_homedir (const char *fname, int quiet)
if (gnupg_mkdir (fname, "-rwx"))
log_fatal ( _("can't create directory '%s': %s\n"),
fname, strerror(errno) );
else if (!quiet )
log_info ( _("directory '%s' created\n"), fname );
else
{
estream_t fp;
char *fcommon;
if (!quiet )
log_info ( _("directory '%s' created\n"), fname );
#ifdef BUILD_WITH_KEYBOXD
/* A new default homedir has been created. Now create a
* common.conf. */
fcommon = make_filename (fname, "common.conf", NULL);
fp = es_fopen (fcommon, "wx,mode=-rw-r");
if (!fp)
{
log_info (_("error creating '%s': %s\n"), fcommon,
gpg_strerror (gpg_error_from_syserror ()));
}
else
{
if (es_fputs ("use-keyboxd\n", fp) == EOF)
{
log_info (_("error writing to '%s': %s\n"), fcommon,
gpg_strerror (es_ferror (fp)
? gpg_error_from_syserror ()
: gpg_error (GPG_ERR_EOF)));
es_fclose (fp);
}
else if (es_fclose (fp))
{
log_info (_("error closing '%s': %s\n"), fcommon,
gpg_strerror (gpg_error_from_syserror ()));
}
}
#endif /* BUILD_WITH_KEYBOXD */
}
}
}

View File

@ -40,6 +40,7 @@
#include "util.h"
#include "i18n.h"
#include "tlv.h"
#include "ksba-io-support.h"
@ -65,6 +66,12 @@ struct reader_cb_parm_s
int autodetect; /* Try to detect the input encoding. */
int assume_pem; /* Assume input encoding is PEM. */
int assume_base64; /* Assume input is base64 encoded. */
int strip_zeroes; /* Expect a SEQUENCE followed by zero padding. */
/* 1 = check state; 2 = reading; 3 = checking */
/* for zeroes. */
int use_maxread; /* If true read not more than MAXREAD. */
unsigned int maxread; /* # of bytes left to read. */
off_t nzeroes; /* Number of padding zeroes red. */
int identified;
int is_pem;
@ -390,6 +397,55 @@ base64_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
}
/* Read up to 10 bytes to test whether the data consist of a sequence;
* if that is true, set the limited flag and record the length of the
* entire sequence in PARM. Unget everything then. Return true if we
* have a sequence with a fixed length. */
static int
starts_with_sequence (struct reader_cb_parm_s *parm)
{
gpg_error_t err;
unsigned char peekbuf[10];
int npeeked, c;
int found = 0;
const unsigned char *p;
size_t n, objlen, hdrlen;
int class, tag, constructed, ndef;
for (npeeked=0; npeeked < sizeof peekbuf; npeeked++)
{
c = es_getc (parm->fp);
if (c == EOF)
goto leave;
peekbuf[npeeked] = c;
}
/* Enough to check for a sequence. */
p = peekbuf;
n = npeeked;
err = parse_ber_header (&p, &n, &class, &tag, &constructed,
&ndef, &objlen, &hdrlen);
if (err)
{
log_debug ("%s: error parsing data: %s\n", __func__, gpg_strerror (err));
goto leave;
}
if (class == CLASS_UNIVERSAL && constructed && tag == TAG_SEQUENCE && !ndef)
{
/* We need to add 1 due to the way we implement the limit. */
parm->maxread = objlen + hdrlen + 1;
if (!(parm->maxread < objlen + hdrlen) && parm->maxread)
parm->use_maxread = 1;
found = 1;
}
leave:
while (npeeked)
es_ungetc (peekbuf[--npeeked], parm->fp);
return found;
}
static int
simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
@ -402,9 +458,55 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
if (!buffer)
return -1; /* not supported */
restart:
if (parm->strip_zeroes)
{
if (parm->strip_zeroes == 1)
{
if (starts_with_sequence (parm))
parm->strip_zeroes = 2; /* Found fixed length sequence. */
else
parm->strip_zeroes = 0; /* Disable zero padding check. */
}
else if (parm->strip_zeroes == 3)
{
/* Limit reached - check that only zeroes follow. */
while (!(c = es_getc (parm->fp)))
parm->nzeroes++;
if (c == EOF)
{ /* only zeroes found. Reset zero padding engine and
* return EOF. */
parm->strip_zeroes = 0;
parm->eof_seen = 1;
return -1;
}
/* Not only zeroes. Reset engine and continue. */
parm->strip_zeroes = 0;
}
}
for (n=0; n < count; n++)
{
c = es_getc (parm->fp);
if (parm->use_maxread && !--parm->maxread)
{
parm->use_maxread = 0;
if (parm->strip_zeroes)
{
parm->strip_zeroes = 3;
parm->nzeroes = 0;
if (n)
goto leave; /* Return what we already got. */
goto restart; /* Immediately check for trailing zeroes. */
}
}
if (parm->nzeroes)
{
parm->nzeroes--;
c = 0;
}
else
c = es_getc (parm->fp);
if (c == EOF)
{
parm->eof_seen = 1;
@ -417,6 +519,7 @@ simple_reader_cb (void *cb_value, char *buffer, size_t count, size_t *nread)
*(byte *)buffer++ = c;
}
leave:
*nread = n;
return 0;
}
@ -575,6 +678,7 @@ base64_finish_write (struct writer_cb_parm_s *parm)
* GNUPG_KSBA_IO_MULTIPEM - The reader expects that the caller uses
* ksba_reader_clear after EOF until no more
* objects were found.
* GNUPG_KSBA_IO_STRIP - Strip zero padding from some CMS objects.
*
* Note that the PEM flag has a higher priority than the BASE64 flag
* which in turn has a gight priority than the AUTODETECT flag.
@ -592,6 +696,7 @@ gnupg_ksba_create_reader (gnupg_ksba_io_t *ctx,
if (!*ctx)
return out_of_core ();
(*ctx)->u.rparm.allow_multi_pem = !!(flags & GNUPG_KSBA_IO_MULTIPEM);
(*ctx)->u.rparm.strip_zeroes = !!(flags & GNUPG_KSBA_IO_STRIP);
rc = ksba_reader_new (&r);
if (rc)

View File

@ -36,6 +36,7 @@
#define GNUPG_KSBA_IO_BASE64 2 /* Plain Base64 format. */
#define GNUPG_KSBA_IO_AUTODETECT 4 /* Try to autodetect the format. */
#define GNUPG_KSBA_IO_MULTIPEM 8 /* Allow more than one PEM chunk. */
#define GNUPG_KSBA_IO_STRIP 16 /* Strip off zero padding. */
/* Context object. */

View File

@ -608,13 +608,14 @@ nvc_get_string (nvc_t nvc, const char *name)
}
/* Return true if NAME exists and its value is true; that is either
* "yes", "true", or a decimal value unequal to 0. */
/* Return true (ie. a non-zero value) if NAME exists and its value is
* true; that is either "yes", "true", or a decimal value unequal to 0. */
int
nvc_get_boolean (nvc_t nvc, const char *name)
{
nve_t item;
const char *s;
int n;
if (!nvc)
return 0;
@ -622,9 +623,12 @@ nvc_get_boolean (nvc_t nvc, const char *name)
if (!item)
return 0;
s = nve_value (item);
if (s && (atoi (s)
|| !ascii_strcasecmp (s, "yes")
|| !ascii_strcasecmp (s, "true")))
if (!s)
return 0;
n = atoi (s);
if (n)
return n;
if (!ascii_strcasecmp (s, "yes") || !ascii_strcasecmp (s, "true"))
return 1;
return 0;
}

View File

@ -75,7 +75,8 @@ nve_t nve_next_value (nve_t entry, const char *name);
/* Return the string for the first entry in NVC with NAME or NULL. */
const char *nvc_get_string (nvc_t nvc, const char *name);
/* Return a boolean value for the first entry in NVC with NAME. */
/* Return a boolean value (zero or non-zero) for the first entry in
* NVC with NAME. */
int nvc_get_boolean (nvc_t nvc, const char *name);

View File

@ -48,6 +48,8 @@ static struct {
{ "Curve25519", "1.3.6.1.4.1.3029.1.5.1", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.6.1.4.1.11591.15.1", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "Curve25519", "1.3.101.110", 255, "cv25519", PUBKEY_ALGO_ECDH },
{ "Ed25519", "1.3.101.112", 255, "ed25519", PUBKEY_ALGO_EDDSA },
{ "X448", "1.3.101.111", 448, "cv448", PUBKEY_ALGO_ECDH },
{ "Ed448", "1.3.101.113", 456, "ed448", PUBKEY_ALGO_EDDSA },
@ -65,13 +67,17 @@ static struct {
};
/* The OID for Curve Ed25519 in OpenPGP format. */
/* The OID for Curve Ed25519 in OpenPGP format. The shorter v5
* variant may only be used with v5 keys. */
static const char oid_ed25519[] =
{ 0x09, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xda, 0x47, 0x0f, 0x01 };
static const char oid_ed25519_v5[] = { 0x03, 0x2b, 0x65, 0x70 };
/* The OID for Curve25519 in OpenPGP format. */
/* The OID for Curve25519 in OpenPGP format. The shorter v5
* variant may only be used with v5 keys. */
static const char oid_cv25519[] =
{ 0x0a, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x97, 0x55, 0x01, 0x05, 0x01 };
static const char oid_cv25519_v5[] = { 0x03, 0x2b, 0x65, 0x6e };
/* The OID for X448 in OpenPGP format. */
/*
@ -321,8 +327,12 @@ openpgp_oid_to_str (gcry_mpi_t a)
int
openpgp_oidbuf_is_ed25519 (const void *buf, size_t len)
{
return (buf && len == DIM (oid_ed25519)
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)));
if (!buf)
return 0;
return ((len == DIM (oid_ed25519)
&& !memcmp (buf, oid_ed25519, DIM (oid_ed25519)))
|| (len == DIM (oid_ed25519_v5)
&& !memcmp (buf, oid_ed25519_v5, DIM (oid_ed25519_v5))));
}
@ -345,8 +355,12 @@ openpgp_oid_is_ed25519 (gcry_mpi_t a)
int
openpgp_oidbuf_is_cv25519 (const void *buf, size_t len)
{
return (buf && len == DIM (oid_cv25519)
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519)));
if (!buf)
return 0;
return ((len == DIM (oid_cv25519)
&& !memcmp (buf, oid_cv25519, DIM (oid_cv25519)))
|| (len == DIM (oid_cv25519_v5)
&& !memcmp (buf, oid_cv25519_v5, DIM (oid_cv25519_v5))));
}
@ -430,8 +444,9 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo)
if (name)
{
for (i=0; oidtable[i].name; i++)
if (!strcmp (oidtable[i].name, name)
|| (oidtable[i].alias && !strcmp (oidtable[i].alias, name)))
if (!ascii_strcasecmp (oidtable[i].name, name)
|| (oidtable[i].alias
&& !ascii_strcasecmp (oidtable[i].alias, name)))
{
oidstr = oidtable[i].oidstr;
nbits = oidtable[i].nbits;
@ -443,7 +458,7 @@ openpgp_curve_to_oid (const char *name, unsigned int *r_nbits, int *r_algo)
/* If not found assume the input is already an OID and check
whether we support it. */
for (i=0; oidtable[i].name; i++)
if (!strcmp (name, oidtable[i].oidstr))
if (!ascii_strcasecmp (name, oidtable[i].oidstr))
{
oidstr = oidtable[i].oidstr;
nbits = oidtable[i].nbits;
@ -492,9 +507,10 @@ openpgp_oid_or_name_to_curve (const char *oidname, int canon)
return NULL;
for (i=0; oidtable[i].name; i++)
if (!strcmp (oidtable[i].oidstr, oidname)
|| !strcmp (oidtable[i].name, oidname)
|| (oidtable[i].alias &&!strcmp (oidtable[i].alias, oidname)))
if (!ascii_strcasecmp (oidtable[i].oidstr, oidname)
|| !ascii_strcasecmp (oidtable[i].name, oidname)
|| (oidtable[i].alias
&& !ascii_strcasecmp (oidtable[i].alias, oidname)))
return !canon && oidtable[i].alias? oidtable[i].alias : oidtable[i].name;
return NULL;
@ -556,8 +572,9 @@ openpgp_is_curve_supported (const char *name, int *r_algo,
*r_nbits = 0;
for (idx = 0; idx < DIM (oidtable) && oidtable[idx].name; idx++)
{
if ((!strcmp (name, oidtable[idx].name)
|| (oidtable[idx].alias && !strcmp (name, (oidtable[idx].alias))))
if ((!ascii_strcasecmp (name, oidtable[idx].name)
|| (oidtable[idx].alias
&& !ascii_strcasecmp (name, (oidtable[idx].alias))))
&& curve_supported_p (oidtable[idx].name))
{
if (r_algo)
@ -659,7 +676,7 @@ get_keyalgo_string (enum gcry_pk_algos algo,
{
if (keyalgo_strings[i].algo == algo
&& keyalgo_strings[i].curve && curve
&& !strcmp (keyalgo_strings[i].curve, curve))
&& !ascii_strcasecmp (keyalgo_strings[i].curve, curve))
return keyalgo_strings[i].name;
}

View File

@ -174,6 +174,7 @@ find_next_lc (char *string)
* -c The string match in this part is done case-sensitive.
* -t Do not trim leading and trailing spaces from VALUE.
* Note that a space after <op> is here required.
* -r RFU: String match uses a regular expression
*
* For example four calls to recsel_parse_expr() with these values for
* EXPR
@ -192,7 +193,7 @@ find_next_lc (char *string)
*
* The caller must pass the address of a selector variable to this
* function and initialize the value of the function to NULL before
* the first call. recset_release needs to be called to free the
* the first call. recsel_release needs to be called to free the
* selector.
*/
gpg_error_t

View File

@ -536,7 +536,8 @@ get_rsa_pk_from_canon_sexp (const unsigned char *keydata, size_t keydatalen,
return err;
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
return err;
if (!tok || toklen != 10 || memcmp ("public-key", tok, toklen))
if (!tok || !((toklen == 10 && !memcmp ("public-key", tok, toklen))
|| (toklen == 11 && !memcmp ("private-key", tok, toklen))))
return gpg_error (GPG_ERR_BAD_PUBKEY);
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
return err;
@ -1074,6 +1075,8 @@ pubkey_algo_string (gcry_sexp_t s_pkey, enum gcry_pk_algos *r_algoid)
*r_algoid = 0;
l1 = gcry_sexp_find_token (s_pkey, "public-key", 0);
if (!l1)
l1 = gcry_sexp_find_token (s_pkey, "private-key", 0);
if (!l1)
return xtrystrdup ("E_no_key");
{

View File

@ -158,7 +158,8 @@ get_inv_recpsgnr_code (gpg_error_t err)
case GPG_ERR_WRONG_KEY_USAGE: errstr = "3"; break;
case GPG_ERR_CERT_REVOKED: errstr = "4"; break;
case GPG_ERR_CERT_EXPIRED: errstr = "5"; break;
case GPG_ERR_NO_CRL_KNOWN: errstr = "6"; break;
case GPG_ERR_NO_CRL_KNOWN:
case GPG_ERR_INV_CRL_OBJ: errstr = "6"; break;
case GPG_ERR_CRL_TOO_OLD: errstr = "7"; break;
case GPG_ERR_NO_POLICY_MATCH: errstr = "8"; break;

View File

@ -53,6 +53,7 @@ enum
STATUS_NEED_PASSPHRASE,
STATUS_VALIDSIG,
STATUS_ASSERT_SIGNER,
STATUS_SIG_ID,
STATUS_ENC_TO,
STATUS_NODATA,

View File

@ -156,8 +156,7 @@ gpg_error_t
parse_ber_header (unsigned char const **buffer, size_t *size,
int *r_class, int *r_tag,
int *r_constructed, int *r_ndef,
size_t *r_length, size_t *r_nhdr)
{
size_t *r_length, size_t *r_nhdr){
int c;
unsigned long tag;
const unsigned char *buf = *buffer;

View File

@ -58,6 +58,7 @@ endif
noinst_HEADERS = dirmngr.h crlcache.h crlfetch.h misc.h
dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
fakecrl.c \
certcache.c certcache.h \
domaininfo.c \
workqueue.c \

View File

@ -768,7 +768,7 @@ cert_cache_init (strlist_t hkp_cacerts)
initialization_done = 1;
release_cache_lock ();
cert_cache_print_stats ();
cert_cache_print_stats (NULL);
}
/* Deinitialize the certificate cache. With FULL set to true even the
@ -811,7 +811,7 @@ cert_cache_deinit (int full)
/* Print some statistics to the log file. */
void
cert_cache_print_stats (void)
cert_cache_print_stats (ctrl_t ctrl)
{
cert_item_t ci;
int idx;
@ -848,16 +848,19 @@ cert_cache_print_stats (void)
release_cache_lock ();
log_info (_("permanently loaded certificates: %u\n"),
n_permanent);
log_info (_(" runtime cached certificates: %u\n"),
n_nonperm);
log_info (_(" trusted certificates: %u (%u,%u,%u,%u)\n"),
n_trusted,
n_trustclass_system,
n_trustclass_config,
n_trustclass_hkp,
n_trustclass_hkpspool);
dirmngr_status_helpf (ctrl,
_("permanently loaded certificates: %u\n"),
n_permanent);
dirmngr_status_helpf (ctrl,
_(" runtime cached certificates: %u\n"),
n_nonperm);
dirmngr_status_helpf (ctrl,
_(" trusted certificates: %u (%u,%u,%u,%u)\n"),
n_trusted,
n_trustclass_system,
n_trustclass_config,
n_trustclass_hkp,
n_trustclass_hkpspool);
}

View File

@ -37,7 +37,7 @@ void cert_cache_init (strlist_t hkp_cacerts);
void cert_cache_deinit (int full);
/* Print some statistics to the log file. */
void cert_cache_print_stats (void);
void cert_cache_print_stats (ctrl_t ctrl);
/* Return true if any cert of a class in MASK is permanently loaded. */
int cert_cache_any_in_class (unsigned int mask);

View File

@ -125,6 +125,13 @@
# define O_BINARY 0
#endif
/* Reason flags for an invalid CRL. */
#define INVCRL_TOO_OLD 1
#define INVCRL_UNKNOWN_EXTN 2
#define INVCRL_GENERAL 127
static const char oidstr_crlNumber[] = "2.5.29.20";
/* static const char oidstr_issuingDistributionPoint[] = "2.5.29.28"; */
static const char oidstr_authorityKeyIdentifier[] = "2.5.29.35";
@ -157,7 +164,7 @@ struct crl_cache_entry_s
unsigned int cdb_use_count; /* Current use count. */
unsigned int cdb_lru_count; /* Used for LRU purposes. */
int dbfile_checked; /* Set to true if the dbfile_hash value has
been checked one. */
been checked once. */
};
@ -569,8 +576,8 @@ open_dir (crl_cache_t *r_cache)
if (*line == 'i')
{
entry->invalid = atoi (line+1);
if (entry->invalid < 1)
entry->invalid = 1;
if (!entry->invalid)
entry->invalid = INVCRL_GENERAL;
}
else if (*line == 'u')
entry->user_trust_req = 1;
@ -1395,7 +1402,7 @@ cache_isvalid (ctrl_t ctrl, const char *issuer_hash,
{
if (opt.verbose)
log_info ("no system trust and client does not trust either\n");
retval = CRL_CACHE_CANTUSE;
retval = CRL_CACHE_NOTTRUSTED;
}
else
{
@ -1515,8 +1522,11 @@ crl_cache_cert_isvalid (ctrl_t ctrl, ksba_cert_t cert,
case CRL_CACHE_DONTKNOW:
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
break;
case CRL_CACHE_NOTTRUSTED:
err = gpg_error (GPG_ERR_NOT_TRUSTED);
break;
case CRL_CACHE_CANTUSE:
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
err = gpg_error (GPG_ERR_INV_CRL_OBJ);
break;
default:
log_fatal ("cache_isvalid returned invalid status code %d\n", result);
@ -2097,7 +2107,7 @@ crl_parse_insert (ctrl_t ctrl, ksba_crl_t crl,
}
}
while (stopreason != KSBA_SR_READY);
assert (!err);
log_assert (!err);
failure:
@ -2338,7 +2348,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
nextupdate);
if (!err2)
err2 = gpg_error (GPG_ERR_CRL_TOO_OLD);
invalidate_crl |= 1;
invalidate_crl |= INVCRL_TOO_OLD;
}
}
@ -2353,7 +2363,7 @@ crl_cache_insert (ctrl_t ctrl, const char *url, ksba_reader_t reader)
log_error (_("unknown critical CRL extension %s\n"), oid);
if (!err2)
err2 = gpg_error (GPG_ERR_INV_CRL);
invalidate_crl |= 2;
invalidate_crl |= INVCRL_UNKNOWN_EXTN;
}
if (gpg_err_code (err) == GPG_ERR_EOF
|| gpg_err_code (err) == GPG_ERR_NO_DATA )
@ -2492,6 +2502,7 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, estream_t fp)
int rc;
int warn = 0;
const unsigned char *s;
unsigned int invalid;
es_fputs ("--------------------------------------------------------\n", fp );
es_fprintf (fp, _("Begin CRL dump (retrieved via %s)\n"), e->url );
@ -2516,13 +2527,20 @@ list_one_crl_entry (crl_cache_t cache, crl_cache_entry_t e, estream_t fp)
!e->user_trust_req? "[system]" :
e->check_trust_anchor? e->check_trust_anchor:"[missing]");
if ((e->invalid & 1))
es_fprintf (fp, _(" ERROR: The CRL will not be used "
"because it was still too old after an update!\n"));
if ((e->invalid & 2))
es_fprintf (fp, _(" ERROR: The CRL will not be used "
invalid = e->invalid;
if ((invalid & INVCRL_TOO_OLD))
{
invalid &= ~INVCRL_TOO_OLD;
es_fprintf (fp, _(" ERROR: The CRL will not be used "
"because it was still too old after an update!\n"));
}
if ((invalid & INVCRL_UNKNOWN_EXTN))
{
invalid &= ~INVCRL_UNKNOWN_EXTN;
es_fprintf (fp, _(" ERROR: The CRL will not be used "
"due to an unknown critical extension!\n"));
if ((e->invalid & ~3))
}
if (invalid) /* INVCRL_GENERAL or some other bits are set. */
es_fprintf (fp, _(" ERROR: The CRL will not be used\n"));
cdb = lock_db_file (cache, e);
@ -2714,8 +2732,6 @@ crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert)
any_dist_point = 1;
if (opt.verbose)
log_info ("fetching CRL from '%s'\n", distpoint_uri);
crl_close_reader (reader);
err = crl_fetch (ctrl, distpoint_uri, &reader);
if (err)

View File

@ -27,6 +27,7 @@ typedef enum
CRL_CACHE_VALID = 0,
CRL_CACHE_INVALID,
CRL_CACHE_DONTKNOW,
CRL_CACHE_NOTTRUSTED,
CRL_CACHE_CANTUSE
}
crl_cache_result_t;
@ -44,6 +45,7 @@ crl_sig_result_t;
struct crl_cache_entry_s;
typedef struct crl_cache_entry_s *crl_cache_entry_t;
/*-- crlcache.c --*/
void crl_cache_init (void);
void crl_cache_deinit (void);
@ -67,4 +69,11 @@ gpg_error_t crl_cache_load (ctrl_t ctrl, const char *filename);
gpg_error_t crl_cache_reload_crl (ctrl_t ctrl, ksba_cert_t cert);
/*-- fakecrl.c --*/
crl_cache_result_t fakecrl_isvalid (ctrl_t ctrl,
const char *issuer_hash,
const char *cert_id);
#endif /* CRLCACHE_H */

View File

@ -175,6 +175,9 @@ crl_fetch (ctrl_t ctrl, const char *url, ksba_reader_t *reader)
if (!url)
return gpg_error (GPG_ERR_INV_ARG);
if (opt.verbose)
log_info ("fetching CRL from '%s'\n", url);
err = http_parse_uri (&uri, url, 0);
http_release_parsed_uri (uri);
if (!err) /* Yes, our HTTP code groks that. */

View File

@ -158,6 +158,7 @@ enum cmd_and_opt_values {
oConnectTimeout,
oConnectQuickTimeout,
oListenBacklog,
oFakeCRL,
aTest
};
@ -274,7 +275,7 @@ static gpgrt_opt_t opts[] = {
" points to serverlist")),
ARGPARSE_s_i (oLDAPTimeout, "ldaptimeout",
N_("|N|set LDAP timeout to N seconds")),
ARGPARSE_s_s (oFakeCRL, "fake-crl", "@"),
ARGPARSE_header ("OCSP", N_("Configuration for OCSP")),
@ -324,6 +325,7 @@ static struct debug_flags_s debug_flags [] =
{ DBG_NETWORK_VALUE, "network" },
{ DBG_LOOKUP_VALUE , "lookup" },
{ DBG_EXTPROG_VALUE, "extprog" },
{ DBG_KEEPTMP_VALUE, "keeptmp" },
{ 77, NULL } /* 77 := Do not exit on "help" or "?". */
};
@ -534,7 +536,7 @@ set_debug (void)
select the highest debug value and would then clutter their
disk with debug files which may reveal confidential data. */
if (numok)
opt.debug &= ~(DBG_HASHING_VALUE);
opt.debug &= ~(DBG_HASHING_VALUE|DBG_KEEPTMP_VALUE);
}
else
{
@ -708,6 +710,8 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.ldaptimeout = DEFAULT_LDAP_TIMEOUT;
ldapserver_list_needs_reset = 1;
opt.debug_cache_expired_certs = 0;
xfree (opt.fake_crl);
opt.fake_crl = NULL;
return 1;
}
@ -870,6 +874,11 @@ parse_rereadable_options (gpgrt_argparse_t *pargs, int reread)
opt.debug_cache_expired_certs = 0;
break;
case oFakeCRL:
xfree (opt.fake_crl);
opt.fake_crl = *pargs->r.ret_str? xstrdup (pargs->r.ret_str) : NULL;
break;
default:
return 0; /* Not handled. */
}
@ -1696,6 +1705,8 @@ dirmngr_deinit_default_ctrl (ctrl_t ctrl)
xfree (ctrl->http_proxy);
ctrl->http_proxy = NULL;
nvc_release (ctrl->rootdse);
ctrl->rootdse = NULL;
}
@ -2030,8 +2041,9 @@ handle_signal (int signo)
break;
case SIGUSR1:
cert_cache_print_stats ();
domaininfo_print_stats ();
/* See also cmd_getinfo:"stats". */
cert_cache_print_stats (NULL);
domaininfo_print_stats (NULL);
break;
case SIGUSR2:

View File

@ -36,6 +36,7 @@
#include "../common/sysutils.h" /* (gnupg_fd_t) */
#include "../common/asshelp.h" /* (assuan_context_t) */
#include "../common/i18n.h"
#include "../common/name-value.h"
#include "dirmngr-status.h"
#include "http.h" /* (parsed_uri_t) */
@ -104,6 +105,7 @@ struct
int force; /* Force loading outdated CRLs. */
char *fake_crl; /* Name of a file with faked CRL entries. */
unsigned int connect_timeout; /* Timeout for connect. */
unsigned int connect_quick_timeout; /* Shorter timeout for connect. */
@ -166,6 +168,7 @@ struct
#define DBG_NETWORK_VALUE 2048 /* debug network I/O. */
#define DBG_LOOKUP_VALUE 8192 /* debug lookup details */
#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
#define DBG_KEEPTMP_VALUE 32768 /* keep some temporary files */
#define DBG_X509 (opt.debug & DBG_X509_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
@ -177,6 +180,7 @@ struct
#define DBG_NETWORK (opt.debug & DBG_NETWORK_VALUE)
#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
#define DBG_KEEPTMP (opt.debug & DBG_KEEPTMP_VALUE)
/* A simple list of certificate references. FIXME: Better use
certlist_t also for references (Store NULL at .cert) */
@ -217,9 +221,12 @@ struct server_control_s
int audit_events; /* Send audit events to client. */
char *http_proxy; /* The used http_proxy or NULL. */
nvc_t rootdse; /* Container wit the rootDSE properties. */
unsigned int timeout; /* Timeout for connect calls in ms. */
unsigned int http_no_crl:1; /* Do not check CRLs for https. */
unsigned int rootdse_tried:1;/* Already tried to get the rootDSE. */
};
@ -238,6 +245,8 @@ void ks_hkp_reload (void);
void ks_hkp_init (void);
/*-- server.c --*/
void release_uri_item_list (uri_item_t list);
ldap_server_t get_ldapservers_from_ctrl (ctrl_t ctrl);
ksba_cert_t get_cert_local (ctrl_t ctrl, const char *issuer);
ksba_cert_t get_issuing_cert_local (ctrl_t ctrl, const char *issuer);
@ -264,7 +273,7 @@ gpg_error_t dirmngr_load_swdb (ctrl_t ctrl, int force);
/*-- domaininfo.c --*/
void domaininfo_print_stats (void);
void domaininfo_print_stats (ctrl_t ctrl);
int domaininfo_is_wkd_not_supported (const char *domain);
void domaininfo_set_no_name (const char *domain);
void domaininfo_set_wkd_supported (const char *domain);

View File

@ -823,7 +823,7 @@ fetch_ldap (LDAP *ld, const char *base, int scope, const char *filter)
/* Main processing. Take the filter and run the LDAP query. The
* result is printed to stdout, errors are logged to the log stream.
* To allow searching with a different base it is possible to extend
* the filer. For example:
* the filter. For example:
*
* ^CN=foo, OU=My Users&(objectClasses=*)
*

View File

@ -81,7 +81,7 @@ hash_domain (const char *domain)
void
domaininfo_print_stats (void)
domaininfo_print_stats (ctrl_t ctrl)
{
int bidx;
domaininfo_t di;
@ -112,11 +112,12 @@ domaininfo_print_stats (void)
if (minlen == -1 || len < minlen)
minlen = len;
}
log_info ("domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n",
count,
minlen > 0? minlen : 0,
maxlen,
no_name, wkd_not_found, wkd_not_supported, wkd_supported);
dirmngr_status_helpf
(ctrl, "domaininfo: items=%d chainlen=%d..%d nn=%d nf=%d ns=%d s=%d\n",
count,
minlen > 0? minlen : 0,
maxlen,
no_name, wkd_not_found, wkd_not_supported, wkd_supported);
}

63
dirmngr/fakecrl.c Normal file
View File

@ -0,0 +1,63 @@
/* fakecrl.c - Debug code to test revocations.
* Copyright (C) 2023 g10 Code GmbH
*
* 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
*/
/*
* For regression testing it is useful to have a way to claim that
* certain certificates are revoked. We achieve this with the
* --fake-crl option which takes a file name as argument. The format
* of the file is: empty lines and lines starting with a hash sign are
* ignored. A line with the issuer DN in brackets starts entries for
* this issuer. All following lines up to the next line with a
* bracket list revoked certificates. For each revoked certificate
* the hexadecimal encoded serial number is listed, followed by the
* revocation date in ISO 14 byte notation, optionally followed by a
* reason keyword. Example:
*---------------------
* # Sample Fake CRL
* [CN=Bayern-Softtoken-Issuing-CA-2019,OU=IT-DLZ,O=Freistaat Bayern,C=DE]
* 7FD62B1A9EA5BBC84971183080717004 20221125T074346
* 11223344556677 20230101T000000 key_compromise
* 0000000000000042 20221206T121200 certificate_hold
*
* [CN=CA IVBB Deutsche Telekom AG 18,OU=Bund,O=PKI-1-Verwaltung,C=DE]
* 735D1B97389F 20230210T083947
*---------------------
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include "dirmngr.h"
#include "crlcache.h"
/* Returns 0 if the given certificate is not listed in the faked CRL
* or no fake CRL is configured. It is expected that the caller then
* consults the real CRL. */
gpg_error_t
fakecrl_isvalid (ctrl_t ctrl, const char *issuer_hash, const char *cert_id)
{
(void)ctrl;
(void)issuer_hash;
(void)cert_id;
return 0;
}

View File

@ -34,6 +34,100 @@
# include "ldap-parse-uri.h"
#endif
/* Parse an URI and store it in a new parsed URI item object which is
* returned at R_PARSEDURI (with its next set to NULL). On error an
* error code is returned an NULL stored at R_PARSEDITEM. */
gpg_error_t
ks_action_parse_uri (const char *uri, uri_item_t *r_parseduri)
{
gpg_error_t err;
uri_item_t item;
char *tmpstr = NULL;
#if USE_LDAP
const char *s;
#endif
*r_parseduri = NULL;
if (!uri)
return gpg_error (GPG_ERR_INV_URI);
item = xtrymalloc (sizeof *item + strlen (uri));
if (!item)
return gpg_error_from_syserror ();
item->next = NULL;
item->parsed_uri = NULL;
strcpy (item->uri, uri);
#if USE_LDAP
if (!strncmp (uri, "ldap:", 5) && !(uri[5] == '/' && uri[6] == '/'))
{
/* Special ldap scheme given. This differs from a valid ldap
* scheme in that no double slash follows. We use
* http_parse_uri to put it as opaque value into parsed_uri. */
tmpstr = strconcat ("opaque:", uri+5, NULL);
if (!tmpstr)
err = gpg_error_from_syserror ();
else
err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
}
else if ((s=strchr (uri, ':')) && !(s[1] == '/' && s[2] == '/'))
{
/* No valid scheme given. We use http_parse_uri to put the
* string as opaque value into parsed_uri. */
tmpstr = strconcat ("opaque:", uri, NULL);
if (!tmpstr)
err = gpg_error_from_syserror ();
else
err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
}
else if (ldap_uri_p (uri))
{
int fixup = 0;
/* Fixme: We should get rid of that parser and replace it with
* our generic (http) URI parser. */
/* If no port has been specified and the scheme ist ldaps we use
* our idea of the default port because the standard LDAP URL
* parser would use 636 here. This is because we redefined
* ldaps to mean starttls. */
#ifdef HAVE_W32_SYSTEM
if (!strcmp (uri, "ldap:///"))
fixup = 1;
else
#endif
if (!http_parse_uri (&item->parsed_uri,uri,HTTP_PARSE_NO_SCHEME_CHECK))
{
if (!item->parsed_uri->port
&& !strcmp (item->parsed_uri->scheme, "ldaps"))
fixup = 2;
http_release_parsed_uri (item->parsed_uri);
item->parsed_uri = NULL;
}
err = ldap_parse_uri (&item->parsed_uri, uri);
if (!err && fixup == 1)
item->parsed_uri->ad_current = 1;
else if (!err && fixup == 2)
item->parsed_uri->port = 389;
}
else
#endif /* USE_LDAP */
{
err = http_parse_uri (&item->parsed_uri, uri, HTTP_PARSE_NO_SCHEME_CHECK);
}
xfree (tmpstr);
if (err)
xfree (item);
else
*r_parseduri = item;
return err;
}
/* Called by the engine's help functions to print the actual help. */
gpg_error_t
ks_print_help (ctrl_t ctrl, const char *text)
@ -243,7 +337,8 @@ ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
keyservers and write the result to the provided output stream. */
gpg_error_t
ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
strlist_t patterns, unsigned int ks_get_flags, estream_t outfp)
strlist_t patterns, unsigned int ks_get_flags,
gnupg_isotime_t newer, estream_t outfp)
{
gpg_error_t err = 0;
gpg_error_t first_err = 0;
@ -270,7 +365,7 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|| strcmp (uri->parsed_uri->scheme, "https") == 0);
int is_ldap = 0;
if ((ks_get_flags & KS_GET_FLAG_ONLY_LDAP))
if ((ks_get_flags & (KS_GET_FLAG_ONLY_LDAP|KS_GET_FLAG_ONLY_AD)))
is_hkp_s = is_http_s = 0;
#if USE_LDAP
@ -288,7 +383,7 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
#if USE_LDAP
if (is_ldap)
err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, ks_get_flags,
&infp);
newer, &infp);
else
#endif
if (is_hkp_s)
@ -448,3 +543,53 @@ ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
err = first_err;
return err;
}
/* Query the default LDAP server or the one given by URL using
* the filter expression FILTER. Write the result to OUTFP. */
gpg_error_t
ks_action_query (ctrl_t ctrl, const char *url, unsigned int ks_get_flags,
const char *filter, char **attrs,
gnupg_isotime_t newer, estream_t outfp)
{
#if USE_LDAP
gpg_error_t err;
estream_t infp = NULL;
uri_item_t puri; /* The broken down URI (only one item used). */
if (!url && (ks_get_flags & KS_GET_FLAG_ROOTDSE))
url = "ldap://";
err = ks_action_parse_uri (url, &puri);
if (err)
return err;
if ((ks_get_flags & KS_GET_FLAG_ROOTDSE))
{
/* Reset authentication for a serverless connection. */
puri->parsed_uri->ad_current = 0;
puri->parsed_uri->auth = NULL;
}
if (!strcmp (puri->parsed_uri->scheme, "ldap")
|| !strcmp (puri->parsed_uri->scheme, "ldaps")
|| !strcmp (puri->parsed_uri->scheme, "ldapi")
|| puri->parsed_uri->opaque)
{
err = ks_ldap_query (ctrl, puri->parsed_uri, ks_get_flags, filter,
attrs, newer, &infp);
if (!err)
err = copy_stream (infp, outfp);
}
else
err = gpg_error (GPG_ERR_CONFIGURATION); /* No LDAP server known. */
es_fclose (infp);
release_uri_item_list (puri);
return err;
#else /* !USE_LDAP */
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
#endif
}

View File

@ -21,17 +21,22 @@
#ifndef DIRMNGR_KS_ACTION_H
#define DIRMNGR_KS_ACTION_H 1
gpg_error_t ks_action_parse_uri (const char *uri, uri_item_t *r_parseduri);
gpg_error_t ks_action_help (ctrl_t ctrl, const char *url);
gpg_error_t ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers);
gpg_error_t ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
strlist_t patterns, estream_t outfp);
gpg_error_t ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
strlist_t patterns, unsigned int ks_get_flags,
estream_t outfp);
gnupg_isotime_t newer, estream_t outfp);
gpg_error_t ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp);
gpg_error_t ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
void *data, size_t datalen,
void *info, size_t infolen);
gpg_error_t ks_action_query (ctrl_t ctrl, const char *ldapserver,
unsigned int ks_get_flags,
const char *filter, char **attr,
gnupg_isotime_t newer, estream_t outfp);
#endif /*DIRMNGR_KS_ACTION_H*/

View File

@ -1,7 +1,7 @@
/* ks-engine-ldap.c - talk to a LDAP keyserver
* Copyright (C) 2001, 2002, 2004, 2005, 2006
* 2007 Free Software Foundation, Inc.
* Copyright (C) 2015, 2020 g10 Code GmbH
* Copyright (C) 2015, 2020, 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -32,6 +32,7 @@
#include "misc.h"
#include "../common/userids.h"
#include "../common/mbox-util.h"
#include "ks-action.h"
#include "ks-engine.h"
#include "ldap-misc.h"
#include "ldap-parse-uri.h"
@ -43,6 +44,7 @@
#define SERVERINFO_PGPKEYV2 2 /* Needs "pgpKeyV2" instead of "pgpKey"*/
#define SERVERINFO_SCHEMAV2 4 /* Version 2 of the Schema. */
#define SERVERINFO_NTDS 8 /* Server is an Active Directory. */
#define SERVERINFO_GENERIC 16 /* Connected in genric mode. */
/* The page size requested from the server. */
@ -61,6 +63,7 @@ struct ks_engine_ldap_local_s
LDAPMessage *message;
LDAPMessage *msg_iter; /* Iterator for message. */
unsigned int serverinfo;
int scope;
char *basedn;
char *keyspec;
char *filter;
@ -192,7 +195,12 @@ ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri)
static struct ks_engine_ldap_local_s *
ks_ldap_new_state (void)
{
return xtrycalloc (1, sizeof(struct ks_engine_ldap_local_s));
struct ks_engine_ldap_local_s *state;
state = xtrycalloc (1, sizeof(struct ks_engine_ldap_local_s));
if (state)
state->scope = LDAP_SCOPE_SUBTREE;
return state;
}
@ -217,6 +225,7 @@ ks_ldap_clear_state (struct ks_engine_ldap_local_s *state)
}
state->serverinfo = 0;
xfree (state->basedn);
state->scope = LDAP_SCOPE_SUBTREE;
state->basedn = NULL;
xfree (state->keyspec);
state->keyspec = NULL;
@ -240,6 +249,45 @@ ks_ldap_free_state (struct ks_engine_ldap_local_s *state)
}
/* Helper for ks_ldap_get and ks_ldap_query. On return first_mode and
* next_mode are set accordingly. */
static gpg_error_t
ks_ldap_prepare_my_state (ctrl_t ctrl, unsigned int ks_get_flags,
int *first_mode, int *next_mode)
{
*first_mode = *next_mode = 0;
if ((ks_get_flags & KS_GET_FLAG_FIRST))
{
if (ctrl->ks_get_state)
ks_ldap_clear_state (ctrl->ks_get_state);
else if (!(ctrl->ks_get_state = ks_ldap_new_state ()))
return gpg_error_from_syserror ();
*first_mode = 1;
}
if ((ks_get_flags & KS_GET_FLAG_NEXT))
{
if (!ctrl->ks_get_state || !ctrl->ks_get_state->ldap_conn
|| !ctrl->ks_get_state->message)
{
log_error ("ks-ldap: --next requested but no state\n");
return gpg_error (GPG_ERR_INV_STATE);
}
*next_mode = 1;
}
/* Do not keep an old state around if not needed. */
if (!(*first_mode || *next_mode))
{
ks_ldap_free_state (ctrl->ks_get_state);
ctrl->ks_get_state = NULL;
}
return 0;
}
/* Convert a keyspec to a filter. Return an error if the keyspec is
bad or is not supported. The filter is escaped and returned in
@ -437,7 +485,9 @@ interrogate_ldap_dn (LDAP *ldap_conn, const char *basedn_search,
*
* URI describes the server to connect to and various options
* including whether to use TLS and the username and password (see
* ldap_parse_uri for a description of the various fields).
* ldap_parse_uri for a description of the various fields). Be
* default a PGP keyserver is assumed; if GENERIC is true a generic
* ldap conenction is instead established.
*
* Returns: The ldap connection handle in *LDAP_CONNP, R_BASEDN is set
* to the base DN for the PGP key space, several flags will be stored
@ -450,7 +500,7 @@ interrogate_ldap_dn (LDAP *ldap_conn, const char *basedn_search,
* If it is NULL, then the server does not appear to be an OpenPGP
* keyserver. */
static gpg_error_t
my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
my_ldap_connect (parsed_uri_t uri, unsigned int generic, LDAP **ldap_connp,
char **r_basedn, char **r_host, int *r_use_tls,
unsigned int *r_serverinfo)
{
@ -519,15 +569,15 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
}
if (opt.verbose)
log_info ("ldap connect to '%s:%d:%s:%s:%s:%s%s%s'\n",
log_info ("ldap connect to '%s:%d:%s:%s:%s:%s%s%s'%s\n",
host, port,
basedn_arg ? basedn_arg : "",
bindname ? bindname : "",
password ? "*****" : "",
use_tls == 1? "starttls" : use_tls == 2? "ldaptls" : "plain",
use_ntds ? ",ntds":"",
use_areconly? ",areconly":"");
use_areconly? ",areconly":"",
generic? " (generic)":"");
/* If the uri specifies a secure connection and we don't support
TLS, then fail; don't silently revert to an insecure
@ -535,7 +585,7 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
if (use_tls)
{
#ifndef HAVE_LDAP_START_TLS_S
log_error ("ldap: can't connect to the server: no TLS support.");
log_error ("ks-ldap: can't connect to the server: no TLS support.");
err = GPG_ERR_LDAP_NOT_SUPPORTED;
goto out;
#endif
@ -607,6 +657,8 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
{
int ver = opt.ldaptimeout;
/* fixme: also use LDAP_OPT_SEND_TIMEOUT? */
lerr = ldap_set_option (ldap_conn, LDAP_OPT_TIMELIMIT, &ver);
if (lerr != LDAP_SUCCESS)
{
@ -699,7 +751,21 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
/* By default we don't bind as there is usually no need to. */
}
if (basedn_arg && *basedn_arg)
if (generic)
{
/* Generic use of this function for arbitrary LDAP servers. */
*r_serverinfo |= SERVERINFO_GENERIC;
if (basedn_arg && *basedn_arg)
{
basedn = xtrystrdup (basedn_arg);
if (!basedn)
{
err = gpg_error_from_syserror ();
goto out;
}
}
}
else if (basedn_arg && *basedn_arg)
{
/* User specified base DN. In this case we know the server is a
* real LDAP server. */
@ -819,11 +885,15 @@ my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
if (!err && opt.debug)
{
log_debug ("ldap_conn: %p\n", ldap_conn);
log_debug ("server_type: %s\n", ((*r_serverinfo & SERVERINFO_REALLDAP)
? "LDAP" : "PGP.com keyserver") );
log_debug ("server_type: %s\n",
((*r_serverinfo & SERVERINFO_GENERIC)
? "Generic" :
(*r_serverinfo & SERVERINFO_REALLDAP)
? "LDAP" : "PGP.com keyserver") );
log_debug ("basedn: %s\n", basedn);
log_debug ("pgpkeyattr: %s\n",
(*r_serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2":"pgpKey");
if (!(*r_serverinfo & SERVERINFO_GENERIC))
log_debug ("pgpkeyattr: %s\n",
(*r_serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2":"pgpKey");
}
ldapserver_list_free (server);
@ -934,6 +1004,15 @@ extract_keys (estream_t output,
}
my_ldap_value_free (vals);
vals = ldap_get_values (ldap_conn, message, "modifyTimestamp");
if (vals && vals[0])
{
gnupg_isotime_t atime;
if (!rfc4517toisotime (atime, vals[0]))
es_fprintf (output, "chg:%s:\n", atime);
}
my_ldap_value_free (vals);
es_fprintf (output, "INFO %s END\n", certid);
}
@ -1028,11 +1107,132 @@ return_one_keyblock (LDAP *ldap_conn, LDAPMessage *msg, unsigned int serverinfo,
}
/* Helper for ks_ldap_get. Note that KEYSPEC is only used for
* diagnostics. */
/* Helper for ks_ldap_query. Returns 0 if an attr was fetched and
* printed to FP. The error code GPG_ERR_NO_DATA is returned if no
* data was printed. Note that FP is updated by this function. */
static gpg_error_t
return_all_attributes (LDAP *ld, LDAPMessage *msg, estream_t *fp)
{
gpg_error_t err = 0;
BerElement *berctx = NULL;
char *attr = NULL;
const char *attrprefix;
struct berval **values = NULL;
int idx;
int any = 0;
const char *s;
const char *val;
size_t len;
char *mydn;
mydn = ldap_get_dn (ld, msg);
if (!*fp)
{
*fp = es_fopenmem(0, "rw");
if (!*fp)
{
err = gpg_error_from_syserror ();
goto leave;
}
}
/* Always print the DN - note that by using only unbkown attributes
* it is pissible to list just the DNs with out addiional
* linefeeds. */
es_fprintf (*fp, "Dn: %s\n", mydn? mydn : "[oops DN missing]");
for (npth_unprotect (), attr = ldap_first_attribute (ld, msg, &berctx),
npth_protect ();
attr;
npth_unprotect (), attr = ldap_next_attribute (ld, msg, berctx),
npth_protect ())
{
npth_unprotect ();
values = ldap_get_values_len (ld, msg, attr);
npth_protect ();
if (!values)
{
if (opt.verbose)
log_info ("attribute '%s' not found\n", attr);
ldap_memfree (attr);
attr = NULL;
continue;
}
any = 1;
if (opt.verbose > 1)
{
log_info ("found attribute '%s'\n", attr);
for (idx=0; values[idx]; idx++)
log_info (" length[%d]=%d\n",
idx, (int)values[0]->bv_len);
}
if (!ascii_strcasecmp (attr, "Dn"))
attrprefix = "X-";
else if (*attr == '#')
attrprefix = "X-hash-";
else if (*attr == ' ')
attrprefix = "X-blank-";
else
attrprefix = "";
/* FIXME: We should remap all invalid chars in ATTR. */
for (idx=0; values[idx]; idx++)
{
es_fprintf (*fp, "%s%s: ", attrprefix, attr);
val = values[idx]->bv_val;
len = values[idx]->bv_len;
while (len && (s = memchr (val, '\n', len)))
{
s++; /* We als want to print the LF. */
if (es_fwrite (val, s - val, 1, *fp) != 1)
goto fwrite_failed;
len -= (s-val);
val = s;
if (len && es_fwrite (" ", 1, 1, *fp) != 1)
goto fwrite_failed;
}
if (len && es_fwrite (val, len, 1, *fp) != 1)
goto fwrite_failed;
if (es_fwrite ("\n", 1, 1, *fp) != 1) /* Final LF. */
goto fwrite_failed;
}
ldap_value_free_len (values);
values = NULL;
ldap_memfree (attr);
attr = NULL;
}
/* One final linefeed to prettify the output. */
if (any && es_fwrite ("\n", 1, 1, *fp) != 1)
goto fwrite_failed;
leave:
if (values)
ldap_value_free_len (values);
ldap_memfree (attr);
if (mydn)
ldap_memfree (mydn);
ber_free (berctx, 0);
return err;
fwrite_failed:
err = gpg_error_from_syserror ();
log_error ("error writing to stdout: %s\n", gpg_strerror (err));
goto leave;
}
/* Helper for ks_ldap_get and ks_ldap_query. Note that KEYSPEC is
* only used for diagnostics. */
static gpg_error_t
search_and_parse (ctrl_t ctrl, const char *keyspec,
LDAP *ldap_conn, char *basedn, char *filter,
LDAP *ldap_conn, char *basedn, int scope, char *filter,
char **attrs, LDAPMessage **r_message)
{
gpg_error_t err = 0;
@ -1065,7 +1265,7 @@ search_and_parse (ctrl_t ctrl, const char *keyspec,
}
npth_unprotect ();
l_err = ldap_search_ext_s (ldap_conn, basedn, LDAP_SCOPE_SUBTREE,
l_err = ldap_search_ext_s (ldap_conn, basedn, scope,
filter, attrs, 0,
srvctrls[0]? srvctrls : NULL, NULL, NULL, 0,
r_message);
@ -1130,7 +1330,7 @@ search_and_parse (ctrl_t ctrl, const char *keyspec,
if (count < 1)
{
if (!ctrl->ks_get_state || ctrl->ks_get_state->pageno == 1)
log_info ("ks-ldap: key %s not found on keyserver\n", keyspec);
log_info ("ks-ldap: '%s' not found on LDAP server\n", keyspec);
if (count == -1)
err = ldap_to_gpg_err (ldap_conn);
@ -1150,20 +1350,92 @@ search_and_parse (ctrl_t ctrl, const char *keyspec,
}
/* Fetch all entries from the RootDSE and return them as a name value
* object. */
static nvc_t
fetch_rootdse (ctrl_t ctrl, parsed_uri_t uri)
{
gpg_error_t err;
estream_t infp = NULL;
uri_item_t puri; /* The broken down URI (only one item used). */
nvc_t nvc = NULL;
/* FIXME: We need the unparsed URI here - use uri_item_t instead
* of fix the parser to fill in original */
err = ks_action_parse_uri (uri && uri->original? uri->original : "ldap://",
&puri);
if (err)
return NULL;
/* Reset authentication for a serverless. */
puri->parsed_uri->ad_current = 0;
puri->parsed_uri->auth = NULL;
if (!strcmp (puri->parsed_uri->scheme, "ldap")
|| !strcmp (puri->parsed_uri->scheme, "ldaps")
|| !strcmp (puri->parsed_uri->scheme, "ldapi")
|| puri->parsed_uri->opaque)
{
err = ks_ldap_query (ctrl, puri->parsed_uri, KS_GET_FLAG_ROOTDSE,
"^&base&(objectclass=*)", NULL, NULL, &infp);
if (err)
log_error ("ldap: reading the rootDES failed: %s\n",
gpg_strerror (err));
else if ((err = nvc_parse (&nvc, NULL, infp)))
log_error ("parsing the rootDES failed: %s\n", gpg_strerror (err));
}
es_fclose (infp);
release_uri_item_list (puri);
if (err)
{
nvc_release (nvc);
nvc = NULL;
}
return nvc;
}
/* Return the baseDN for URI which might have already been cached for
* this session. */
static char *
basedn_from_rootdse (ctrl_t ctrl, parsed_uri_t uri)
{
const char *s;
if (!ctrl->rootdse && !ctrl->rootdse_tried)
{
ctrl->rootdse = fetch_rootdse (ctrl, uri);
ctrl->rootdse_tried = 1;
if (ctrl->rootdse)
{
log_debug ("Dump of all rootDSE attributes:\n");
nvc_write (ctrl->rootdse, log_get_stream ());
log_debug ("End of dump\n");
}
}
s = nvc_get_string (ctrl->rootdse, "defaultNamingContext:");
return s? xtrystrdup (s): NULL;
}
/* Get the key described key the KEYSPEC string from the keyserver
* identified by URI. On success R_FP has an open stream to read the
* data. KS_GET_FLAGS conveys flags from the client. */
gpg_error_t
ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
unsigned int ks_get_flags, estream_t *r_fp)
unsigned int ks_get_flags, gnupg_isotime_t newer, estream_t *r_fp)
{
gpg_error_t err = 0;
gpg_error_t err;
unsigned int serverinfo;
char *host = NULL;
int use_tls;
char *filter = NULL;
LDAP *ldap_conn = NULL;
char *basedn = NULL;
int scope = LDAP_SCOPE_SUBTREE;
estream_t fp = NULL;
LDAPMessage *message = NULL;
LDAPMessage *msg;
@ -1179,46 +1451,19 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
{
"dummy", /* (to be be replaced.) */
"pgpcertid", "pgpuserid", "pgpkeyid", "pgprevoked", "pgpdisabled",
"pgpkeycreatetime", "modifytimestamp", "pgpkeysize", "pgpkeytype",
"pgpkeycreatetime", "modifyTimestamp", "pgpkeysize", "pgpkeytype",
"gpgfingerprint",
NULL
};
(void) ctrl;
if (dirmngr_use_tor ())
{
return no_ldap_due_to_tor (ctrl);
}
/* Make sure we got a state. */
if ((ks_get_flags & KS_GET_FLAG_FIRST))
{
if (ctrl->ks_get_state)
ks_ldap_clear_state (ctrl->ks_get_state);
else if (!(ctrl->ks_get_state = ks_ldap_new_state ()))
return gpg_error_from_syserror ();
first_mode = 1;
}
if ((ks_get_flags & KS_GET_FLAG_NEXT))
{
if (!ctrl->ks_get_state || !ctrl->ks_get_state->ldap_conn
|| !ctrl->ks_get_state->message)
{
log_error ("ks_ldap: --next requested but no state\n");
return gpg_error (GPG_ERR_INV_STATE);
}
next_mode = 1;
}
/* Do not keep an old state around if not needed. */
if (!(first_mode || next_mode))
{
ks_ldap_free_state (ctrl->ks_get_state);
ctrl->ks_get_state = NULL;
}
err = ks_ldap_prepare_my_state (ctrl, ks_get_flags, &first_mode, &next_mode);
if (err)
return err;
if (next_mode)
{
@ -1236,6 +1481,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
err = search_and_parse (ctrl, ctrl->ks_get_state->keyspec,
ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->basedn,
ctrl->ks_get_state->scope,
ctrl->ks_get_state->filter,
attrs,
&ctrl->ks_get_state->message);
@ -1284,7 +1530,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
else /* Not in --next mode. */
{
/* Make sure we are talking to an OpenPGP LDAP server. */
err = my_ldap_connect (uri, &ldap_conn,
err = my_ldap_connect (uri, 0, &ldap_conn,
&basedn, &host, &use_tls, &serverinfo);
if (err || !basedn)
{
@ -1305,14 +1551,36 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
if (err)
goto leave;
if (*newer)
{
char *tstr, *fstr;
tstr = isotime2rfc4517 (newer);
if (!tstr)
{
err = gpg_error_from_syserror ();
goto leave;
}
fstr = strconcat ("(&", filter,
"(modifyTimestamp>=", tstr, "))", NULL);
xfree (tstr);
if (!fstr)
{
err = gpg_error_from_syserror ();
goto leave;
}
xfree (filter);
filter = fstr;
}
if (opt.debug)
log_debug ("ks-ldap: using filter: %s\n", filter);
/* Replace "dummy". */
attrs[0] = (serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2" : "pgpKey";
err = search_and_parse (ctrl, keyspec, ldap_conn, basedn, filter, attrs,
&message);
err = search_and_parse (ctrl, keyspec, ldap_conn, basedn, scope,
filter, attrs, &message);
if (err)
goto leave;
@ -1363,6 +1631,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
ctrl->ks_get_state->message = message;
message = NULL;
ctrl->ks_get_state->serverinfo = serverinfo;
ctrl->ks_get_state->scope = scope;
ctrl->ks_get_state->basedn = basedn;
basedn = NULL;
ctrl->ks_get_state->keyspec = keyspec? xtrystrdup (keyspec) : NULL;
@ -1423,7 +1692,7 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
}
/* Make sure we are talking to an OpenPGP LDAP server. */
err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
err = my_ldap_connect (uri, 0, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
if (err || !basedn)
{
if (!err)
@ -1459,7 +1728,7 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
char *attrs[] =
{
"pgpcertid", "pgpuserid", "pgprevoked", "pgpdisabled",
"pgpkeycreatetime", "pgpkeyexpiretime", "modifytimestamp",
"pgpkeycreatetime", "pgpkeyexpiretime", "modifyTimestamp",
"pgpkeysize", "pgpkeytype", "gpgfingerprint",
NULL
};
@ -1613,19 +1882,17 @@ ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
}
my_ldap_value_free (vals);
#if 0
/* This is not yet specified in the keyserver
protocol, but may be someday. */
es_fputc (':', fp);
vals = ldap_get_values (ldap_conn, each, "modifytimestamp");
if(vals && vals[0] strlen (vals[0]) == 15)
vals = ldap_get_values (ldap_conn, each, "modifyTimestamp");
if(vals && vals[0])
{
es_fprintf (fp, "%u",
(unsigned int) ldap2epochtime (vals[0]));
gnupg_isotime_t atime;
if (rfc4517toisotime (atime, vals[0]))
*atime = 0;
es_fprintf (fp, "%s", atime);
}
my_ldap_value_free (vals);
#endif
es_fprintf (fp, "\n");
@ -2312,7 +2579,7 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
return no_ldap_due_to_tor (ctrl);
}
err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
err = my_ldap_connect (uri, 0, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
if (err || !basedn)
{
if (!err)
@ -2538,3 +2805,249 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
return err;
}
/* Get the data described by FILTER_ARG from URI. On success R_FP has
* an open stream to read the data. KS_GET_FLAGS conveys flags from
* the client. ATTRS is a NULL terminated list of attributes to
* return or NULL for all. */
gpg_error_t
ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri, unsigned int ks_get_flags,
const char *filter_arg, char **attrs,
gnupg_isotime_t newer, estream_t *r_fp)
{
gpg_error_t err;
unsigned int serverinfo;
char *host = NULL;
int use_tls;
LDAP *ldap_conn = NULL;
char *basedn = NULL;
estream_t fp = NULL;
char *filter = NULL;
int scope = LDAP_SCOPE_SUBTREE;
LDAPMessage *message = NULL;
LDAPMessage *msg;
int anydata = 0;
int first_mode = 0;
int next_mode = 0;
int get_first;
if (dirmngr_use_tor ())
return no_ldap_due_to_tor (ctrl);
if ((!filter_arg || !*filter_arg) && (ks_get_flags & KS_GET_FLAG_ROOTDSE))
filter_arg = "^&base&(objectclass=*)";
err = ks_ldap_prepare_my_state (ctrl, ks_get_flags, &first_mode, &next_mode);
if (err)
goto leave;
if (!next_mode) /* (In --next mode the filter is ignored.) */
{
if (!filter_arg || !*filter_arg)
{
err = gpg_error (GPG_ERR_LDAP_FILTER);
goto leave;
}
err = ldap_parse_extfilter (filter_arg, 0, &basedn, &scope, &filter);
if (err)
goto leave;
if (newer && *newer)
{
char *tstr, *fstr;
tstr = isotime2rfc4517 (newer);
if (!tstr)
{
err = gpg_error_from_syserror ();
goto leave;
}
if (filter && *filter)
fstr = strconcat ("(&", filter,
"(modifyTimestamp>=", tstr, "))", NULL);
else
fstr = strconcat ("(modifyTimestamp>=", tstr, ")", NULL);
xfree (tstr);
if (!fstr)
{
err = gpg_error_from_syserror ();
goto leave;
}
xfree (filter);
filter = fstr;
}
}
if (next_mode)
{
next_again:
if (!ctrl->ks_get_state->msg_iter && ctrl->ks_get_state->more_pages)
{
/* Get the next page of results. */
if (ctrl->ks_get_state->message)
{
ldap_msgfree (ctrl->ks_get_state->message);
ctrl->ks_get_state->message = NULL;
}
err = search_and_parse (ctrl, ctrl->ks_get_state->keyspec,
ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->basedn,
ctrl->ks_get_state->scope,
ctrl->ks_get_state->filter,
attrs,
&ctrl->ks_get_state->message);
if (err)
goto leave;
ctrl->ks_get_state->msg_iter = ctrl->ks_get_state->message;
get_first = 1;
}
else
get_first = 0;
while (ctrl->ks_get_state->msg_iter)
{
npth_unprotect ();
ctrl->ks_get_state->msg_iter
= get_first? ldap_first_entry (ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->msg_iter)
/* */ : ldap_next_entry (ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->msg_iter);
npth_protect ();
get_first = 0;
if (ctrl->ks_get_state->msg_iter)
{
err = return_all_attributes (ctrl->ks_get_state->ldap_conn,
ctrl->ks_get_state->msg_iter,
&fp);
if (!err)
break; /* Found. */
else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
err = 0; /* Skip empty attributes. */
else
goto leave;
}
}
if (!ctrl->ks_get_state->msg_iter || !fp)
{
ctrl->ks_get_state->msg_iter = NULL;
if (ctrl->ks_get_state->more_pages)
goto next_again;
err = gpg_error (GPG_ERR_NO_DATA);
}
}
else /* Not in --next mode. */
{
/* Connect to the LDAP server in generic mode. */
char *tmpbasedn;
err = my_ldap_connect (uri, 1 /*generic*/, &ldap_conn,
&tmpbasedn, &host, &use_tls, &serverinfo);
if (err)
goto leave;
if (basedn)
xfree (tmpbasedn); /* Extended syntax overrides. */
else if (tmpbasedn)
basedn = tmpbasedn;
else if (!(ks_get_flags & KS_GET_FLAG_ROOTDSE))
{
/* No BaseDN known - get one. */
basedn = basedn_from_rootdse (ctrl, uri);
}
if (opt.debug)
{
log_debug ("ks-ldap: using basedn: %s\n", basedn);
log_debug ("ks-ldap: using filter: %s\n", filter);
}
err = search_and_parse (ctrl, filter, ldap_conn, basedn, scope, filter,
attrs, &message);
if (err)
goto leave;
for (npth_unprotect (),
msg = ldap_first_entry (ldap_conn, message),
npth_protect ();
msg;
npth_unprotect (),
msg = ldap_next_entry (ldap_conn, msg),
npth_protect ())
{
err = return_all_attributes (ldap_conn, msg, &fp);
if (!err)
{
anydata = 1;
if (first_mode)
break;
}
else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
err = 0; /* Skip empty/duplicate attributes. */
else
goto leave;
}
if (ctrl->ks_get_state) /* Save the iterator. */
ctrl->ks_get_state->msg_iter = msg;
if (!fp) /* Nothing was found. */
err = gpg_error (GPG_ERR_NO_DATA);
if (!err && anydata)
err = dirmngr_status_printf (ctrl, "SOURCE", "%s://%s",
use_tls? "ldaps" : "ldap",
host? host:"");
}
leave:
/* Store our state if needed. */
if (!err && (ks_get_flags & KS_GET_FLAG_FIRST))
{
log_assert (!ctrl->ks_get_state->ldap_conn);
ctrl->ks_get_state->ldap_conn = ldap_conn;
ldap_conn = NULL;
log_assert (!ctrl->ks_get_state->message);
ctrl->ks_get_state->message = message;
message = NULL;
ctrl->ks_get_state->serverinfo = serverinfo;
ctrl->ks_get_state->scope = scope;
ctrl->ks_get_state->basedn = basedn;
basedn = NULL;
ctrl->ks_get_state->keyspec = filter? xtrystrdup (filter) : NULL;
ctrl->ks_get_state->filter = filter;
filter = NULL;
}
if ((ks_get_flags & KS_GET_FLAG_NEXT))
{
/* Keep the state in --next mode even with errors. */
ldap_conn = NULL;
message = NULL;
}
if (message)
ldap_msgfree (message);
if (err)
es_fclose (fp);
else
{
if (fp)
es_fseek (fp, 0, SEEK_SET);
*r_fp = fp;
}
xfree (basedn);
xfree (host);
if (ldap_conn)
ldap_unbind (ldap_conn);
xfree (filter);
return err;
}

View File

@ -27,6 +27,8 @@
#define KS_GET_FLAG_ONLY_LDAP 1
#define KS_GET_FLAG_FIRST 2
#define KS_GET_FLAG_NEXT 4
#define KS_GET_FLAG_ONLY_AD 8 /* Do this only if we have an AD. */
#define KS_GET_FLAG_ROOTDSE 16 /* Get the rootDSE. */
/*-- ks-action.c --*/
@ -74,10 +76,14 @@ gpg_error_t ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
estream_t *r_fp);
gpg_error_t ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri,
const char *keyspec, unsigned int ks_get_flags,
estream_t *r_fp);
gnupg_isotime_t newer, estream_t *r_fp);
gpg_error_t ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
void *data, size_t datalen,
void *info, size_t infolen);
gpg_error_t ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri,
unsigned int ks_get_flags,
const char *filter, char **attrs,
gnupg_isotime_t newer, estream_t *r_fp);
#endif /*DIRMNGR_KS_ENGINE_H*/

View File

@ -332,3 +332,90 @@ ldap_parse_extfilter (const char *string, int silent,
}
return err;
}
/* Scan an ISO timestamp and return a Generalized Time according to
* RFC-4517. The only supported format is "yyyymmddThhmmss[Z]"
* delimited by white space, nul, a colon or a comma. Returns a
* malloced string or NULL for an invalid string or on memory
* error. */
char *
isotime2rfc4517 (const char *string)
{
int year, month, day, hour, minu, sec;
if (!isotime_p (string))
{
errno = 0;
return NULL;
}
year = atoi_4 (string);
month = atoi_2 (string + 4);
day = atoi_2 (string + 6);
hour = atoi_2 (string + 9);
minu = atoi_2 (string + 11);
sec = atoi_2 (string + 13);
/* Basic checks (1600 due to the LDAP time format base) */
if (year < 1600 || month < 1 || month > 12 || day < 1 || day > 31
|| hour > 23 || minu > 59 || sec > 61 )
{
errno = 0;
return NULL;
}
return gpgrt_bsprintf ("%04d%02d%02d%02d%02d%02d.0Z",
year, month, day, hour, minu, sec);
}
/* Parse an LDAP Generalized Time string and update the provided
* isotime buffer. On error return and error code. */
gpg_error_t
rfc4517toisotime (gnupg_isotime_t timebuf, const char *string)
{
int i;
int year, month, day, hour, minu, sec;
const char *s;
for (i=0, s=string; i < 10; i++, s++) /* Need yyyymmddhh */
if (!digitp (s))
return gpg_error (GPG_ERR_INV_TIME);
year = atoi_4 (string);
month = atoi_2 (string + 4);
day = atoi_2 (string + 6);
hour = atoi_2 (string + 9);
minu = 0;
sec = 0;
if (digitp (s) && digitp (s+1))
{
minu = atoi_2 (s);
s += 2;
if (digitp (s) && digitp (s+1))
{
sec = atoi_2 (s);
s += 2;
}
}
if (*s == '.' || *s == ',')
{
s++;
if (!digitp (s)) /* At least one digit of the fraction required. */
return gpg_error (GPG_ERR_INV_TIME);
s++;
while (digitp (s))
s++;
}
if (*s == 'Z' && (!s[1] || spacep (s+1)))
; /* stop here. */
else if (*s == '-' || *s == '+')
return gpg_error (GPG_ERR_NOT_IMPLEMENTED); /* FIXME */
else
return gpg_error (GPG_ERR_INV_TIME);
snprintf (timebuf, sizeof (gnupg_isotime_t), "%04d%02d%02dT%02d%02d%02d",
year, month, day, hour, minu, sec);
return 0;
}

View File

@ -38,6 +38,8 @@ gpg_err_code_t ldap_err_to_gpg_err (int code);
gpg_err_code_t ldap_to_gpg_err (LDAP *ld);
gpg_error_t ldap_parse_extfilter (const char *string, int silent,
char **r_base, int *r_scope, char **r_filter);
char *isotime2rfc4517 (const char *string);
gpg_error_t rfc4517toisotime (gnupg_isotime_t timebuf, const char *string);
#endif /*DIRMNGR_LDAP_MISC_H*/

View File

@ -525,7 +525,7 @@ make_one_filter (const char *pattern, char **r_result)
{
/* We need just the BaseDN. This assumes that the Subject
* is correcly stored in the DT. This is however not always
* the case and the actual DN is different ffrom the
* the case and the actual DN is different from the
* subject. In this case we won't find anything. */
if (extfilt_need_escape (pattern)
&& !(pattern = pattern_buffer = extfilt_escape (pattern)))

View File

@ -146,7 +146,7 @@ get_ldapservers_from_ctrl (ctrl_t ctrl)
}
/* Release an uri_item_t list. */
static void
void
release_uri_item_list (uri_item_t list)
{
while (list)
@ -1339,6 +1339,10 @@ cmd_isvalid (assuan_context_t ctx, char *line)
}
else if (only_ocsp)
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
else if (opt.fake_crl && (err = fakecrl_isvalid (ctrl, issuerhash, serialno)))
{
/* We already got the error code. */
}
else
{
switch (crl_cache_isvalid (ctrl,
@ -1360,8 +1364,11 @@ cmd_isvalid (assuan_context_t ctx, char *line)
goto again;
}
break;
case CRL_CACHE_NOTTRUSTED:
err = gpg_error (GPG_ERR_NOT_TRUSTED);
break;
case CRL_CACHE_CANTUSE:
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
err = gpg_error (GPG_ERR_INV_CRL_OBJ);
break;
default:
log_fatal ("crl_cache_isvalid returned invalid code\n");
@ -1374,7 +1381,7 @@ cmd_isvalid (assuan_context_t ctx, char *line)
/* If the line contains a SHA-1 fingerprint as the first argument,
return the FPR vuffer on success. The function checks that the
return the FPR buffer on success. The function checks that the
fingerprint consists of valid characters and prints and error
message if it does not and returns NULL. Fingerprints are
considered optional and thus no explicit error is returned. NULL is
@ -1469,7 +1476,7 @@ cmd_checkcrl (assuan_context_t ctx, char *line)
goto leave;
}
assert (cert);
log_assert (cert);
err = crl_cache_cert_isvalid (ctrl, cert, ctrl->force_crl_refresh);
if (gpg_err_code (err) == GPG_ERR_NO_CRL_KNOWN)
@ -2140,15 +2147,6 @@ cmd_validate (assuan_context_t ctx, char *line)
static gpg_error_t
make_keyserver_item (const char *uri, uri_item_t *r_item)
{
gpg_error_t err;
uri_item_t item;
char *tmpstr = NULL;
#if USE_LDAP
const char *s;
#endif
*r_item = NULL;
/* We used to have DNS CNAME redirection from the URLs below to
* sks-keyserver. pools. The idea was to allow for a quick way to
* switch to a different set of pools. The problem with that
@ -2180,78 +2178,7 @@ make_keyserver_item (const char *uri, uri_item_t *r_item)
else if (!strcmp (uri, "http://http-keys.gnupg.net"))
uri = "hkp://keyserver.ubuntu.com:80";
item = xtrymalloc (sizeof *item + strlen (uri));
if (!item)
return gpg_error_from_syserror ();
item->next = NULL;
item->parsed_uri = NULL;
strcpy (item->uri, uri);
#if USE_LDAP
if (!strncmp (uri, "ldap:", 5) && !(uri[5] == '/' && uri[6] == '/'))
{
/* Special ldap scheme given. This differs from a valid ldap
* scheme in that no double slash follows.. Use http_parse_uri
* to put it as opaque value into parsed_uri. */
tmpstr = strconcat ("opaque:", uri+5, NULL);
if (!tmpstr)
err = gpg_error_from_syserror ();
else
err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
}
else if ((s=strchr (uri, ':')) && !(s[1] == '/' && s[2] == '/'))
{
/* No valid scheme given. Use http_parse_uri to put the string
* as opaque value into parsed_uri. */
tmpstr = strconcat ("opaque:", uri, NULL);
if (!tmpstr)
err = gpg_error_from_syserror ();
else
err = http_parse_uri (&item->parsed_uri, tmpstr, 0);
}
else if (ldap_uri_p (uri))
{
int fixup = 0;
/* Fixme: We should get rid of that parser and replace it with
* our generic (http) URI parser. */
/* If no port has been specified and the scheme ist ldaps we use
* our idea of the default port because the standard LDAP URL
* parser would use 636 here. This is because we redefined
* ldaps to mean starttls. */
#ifdef HAVE_W32_SYSTEM
if (!strcmp (uri, "ldap:///"))
fixup = 1;
else
#endif
if (!http_parse_uri (&item->parsed_uri,uri,HTTP_PARSE_NO_SCHEME_CHECK))
{
if (!item->parsed_uri->port
&& !strcmp (item->parsed_uri->scheme, "ldaps"))
fixup = 2;
http_release_parsed_uri (item->parsed_uri);
item->parsed_uri = NULL;
}
err = ldap_parse_uri (&item->parsed_uri, uri);
if (!err && fixup == 1)
item->parsed_uri->ad_current = 1;
else if (!err && fixup == 2)
item->parsed_uri->port = 389;
}
else
#endif /* USE_LDAP */
{
err = http_parse_uri (&item->parsed_uri, uri, HTTP_PARSE_NO_SCHEME_CHECK);
}
xfree (tmpstr);
if (err)
xfree (item);
else
*r_item = item;
return err;
return ks_action_parse_uri (uri, r_item);
}
@ -2534,22 +2461,28 @@ cmd_ks_search (assuan_context_t ctx, char *line)
static const char hlp_ks_get[] =
"KS_GET [--quick] [--ldap] [--first|--next] {<pattern>}\n"
"KS_GET [--quick] [--newer=TIME] [--ldap] [--first|--next] {<pattern>}\n"
"\n"
"Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
"(see command KEYSERVER). Each pattern should be a keyid, a fingerprint,\n"
"or an exact name indicated by the '=' prefix. Option --quick uses a\n"
"shorter timeout; --ldap will use only ldap servers. With --first only\n"
"the first item is returned; --next is used to return the next item";
"the first item is returned; --next is used to return the next item\n"
"Option --newer works only with certain LDAP servers.";
static gpg_error_t
cmd_ks_get (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
strlist_t list, sl;
strlist_t list = NULL;
strlist_t sl;
const char *s;
char *p;
estream_t outfp;
unsigned int flags = 0;
gnupg_isotime_t opt_newer;
*opt_newer = 0;
if (has_option (line, "--quick"))
ctrl->timeout = opt.connect_quick_timeout;
@ -2559,13 +2492,18 @@ cmd_ks_get (assuan_context_t ctx, char *line)
flags |= KS_GET_FLAG_FIRST;
if (has_option (line, "--next"))
flags |= KS_GET_FLAG_NEXT;
if ((s = option_value (line, "--newer"))
&& !string2isotime (opt_newer, s))
{
err = set_error (GPG_ERR_SYNTAX, "invalid time format");
goto leave;
}
line = skip_options (line);
/* Break the line into a strlist. Each pattern is by
definition percent-plus escaped. However we only support keyids
and fingerprints and thus the client has no need to apply the
escaping. */
list = NULL;
for (p=line; *p; line = p)
{
while (*p && *p != ' ')
@ -2642,7 +2580,7 @@ cmd_ks_get (assuan_context_t ctx, char *line)
ctrl->server_local->inhibit_data_logging_now = 0;
ctrl->server_local->inhibit_data_logging_count = 0;
err = ks_action_get (ctrl, ctrl->server_local->keyservers,
list, flags, outfp);
list, flags, opt_newer, outfp);
es_fclose (outfp);
ctrl->server_local->inhibit_data_logging = 0;
}
@ -2761,6 +2699,96 @@ cmd_ks_put (assuan_context_t ctx, char *line)
}
static const char hlp_ad_query[] =
"AD_QUERY [--first|--next] [--] <filter_expression> \n"
"\n"
"Query properties from a Windows Active Directory.\n"
"Our extended filter syntax may be used for the filter\n"
"expression; see gnupg/dirmngr/ldap-misc.c. There are\n"
"a couple of other options available:\n\n"
" --rootdse - Query the root using serverless binding,\n"
" --attr=<attribs> - Comma delimited list of attributes\n"
" to return.\n"
;
static gpg_error_t
cmd_ad_query (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
unsigned int flags = 0;
const char *filter;
estream_t outfp = NULL;
char *p;
char **opt_attr = NULL;
const char *s;
gnupg_isotime_t opt_newer;
*opt_newer = 0;
/* No options for now. */
if (has_option (line, "--first"))
flags |= KS_GET_FLAG_FIRST;
if (has_option (line, "--next"))
flags |= KS_GET_FLAG_NEXT;
if (has_option (line, "--rootdse"))
flags |= KS_GET_FLAG_ROOTDSE;
if ((s = option_value (line, "--newer"))
&& !string2isotime (opt_newer, s))
{
err = set_error (GPG_ERR_SYNTAX, "invalid time format");
goto leave;
}
err = get_option_value (line, "--attr", &p);
if (err)
goto leave;
if (p)
{
opt_attr = strtokenize (p, ",");
if (!opt_attr)
{
err = gpg_error_from_syserror ();
xfree (p);
goto leave;
}
xfree (p);
}
line = skip_options (line);
filter = line;
if ((flags & KS_GET_FLAG_NEXT))
{
if (*filter || (flags & ~KS_GET_FLAG_NEXT))
{
err = PARM_ERROR ("No filter or other options allowed with --next");
goto leave;
}
}
/* Setup an output stream and perform the get. */
outfp = es_fopencookie (ctx, "w", data_line_cookie_functions);
if (!outfp)
{
err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
goto leave;
}
ctrl->server_local->inhibit_data_logging = 1;
ctrl->server_local->inhibit_data_logging_now = 0;
ctrl->server_local->inhibit_data_logging_count = 0;
err = ks_action_query (ctrl,
(flags & KS_GET_FLAG_ROOTDSE)? NULL : "ldap:///",
flags, filter, opt_attr, opt_newer, outfp);
leave:
es_fclose (outfp);
xfree (opt_attr);
ctrl->server_local->inhibit_data_logging = 0;
return leave_cmd (ctx, err);
}
static const char hlp_loadswdb[] =
"LOADSWDB [--force]\n"
@ -2785,13 +2813,14 @@ static const char hlp_getinfo[] =
"Multi purpose command to return certain information. \n"
"Supported values of WHAT are:\n"
"\n"
"version - Return the version of the program.\n"
"pid - Return the process id of the server.\n"
"version - Return the version of the program\n"
"pid - Return the process id of the server\n"
"tor - Return OK if running in Tor mode\n"
"dnsinfo - Return info about the DNS resolver\n"
"socket_name - Return the name of the socket.\n"
"session_id - Return the current session_id.\n"
"socket_name - Return the name of the socket\n"
"session_id - Return the current session_id\n"
"workqueue - Inspect the work queue\n"
"stats - Print stats\n"
"getenv NAME - Return value of envvar NAME\n";
static gpg_error_t
cmd_getinfo (assuan_context_t ctx, char *line)
@ -2860,6 +2889,12 @@ cmd_getinfo (assuan_context_t ctx, char *line)
workqueue_dump_queue (ctrl);
err = 0;
}
else if (!strcmp (line, "stats"))
{
cert_cache_print_stats (ctrl);
domaininfo_print_stats (ctrl);
err = 0;
}
else if (!strncmp (line, "getenv", 6)
&& (line[6] == ' ' || line[6] == '\t' || !line[6]))
{
@ -2959,6 +2994,7 @@ register_commands (assuan_context_t ctx)
{ "KS_GET", cmd_ks_get, hlp_ks_get },
{ "KS_FETCH", cmd_ks_fetch, hlp_ks_fetch },
{ "KS_PUT", cmd_ks_put, hlp_ks_put },
{ "AD_QUERY", cmd_ad_query, hlp_ad_query },
{ "GETINFO", cmd_getinfo, hlp_getinfo },
{ "LOADSWDB", cmd_loadswdb, hlp_loadswdb },
{ "KILLDIRMNGR",cmd_killdirmngr,hlp_killdirmngr },
@ -3218,7 +3254,8 @@ dirmngr_status_help (ctrl_t ctrl, const char *text)
/* Print a help status line using a printf like format. The function
* splits text at LFs. */
* splits text at LFs. With CTRL beeing NULL, the function behaves
* like log_info. */
gpg_error_t
dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
{
@ -3227,12 +3264,20 @@ dirmngr_status_helpf (ctrl_t ctrl, const char *format, ...)
char *buf;
va_start (arg_ptr, format);
buf = es_vbsprintf (format, arg_ptr);
err = buf? 0 : gpg_error_from_syserror ();
if (ctrl)
{
buf = es_vbsprintf (format, arg_ptr);
err = buf? 0 : gpg_error_from_syserror ();
if (!err)
err = dirmngr_status_help (ctrl, buf);
es_free (buf);
}
else
{
log_logv (GPGRT_LOGLVL_INFO, format, arg_ptr);
err = 0;
}
va_end (arg_ptr);
if (!err)
err = dirmngr_status_help (ctrl, buf);
es_free (buf);
return err;
}

View File

@ -255,6 +255,7 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
int any_revoked = 0;
int any_no_crl = 0;
int any_crl_too_old = 0;
int any_not_trusted = 0;
chain_item_t ci;
log_assert (ctrl->check_revocations_nest_level >= 0);
@ -266,7 +267,8 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
return gpg_error(GPG_ERR_BAD_CERT_CHAIN);
}
ctrl->check_revocations_nest_level++;
if (opt.verbose)
log_info ("[%d] start checking CRLs\n", ctrl->check_revocations_nest_level);
for (ci=chain; ci; ci = ci->next)
{
@ -293,17 +295,19 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
if (!err)
err = crl_cache_cert_isvalid (ctrl, ci->cert, 0);
}
if (opt.verbose)
log_info ("[%d] result of checking this CRL: %s\n",
ctrl->check_revocations_nest_level, gpg_strerror (err));
switch (gpg_err_code (err))
{
case 0: err = 0; break;
case GPG_ERR_CERT_REVOKED: any_revoked = 1; err = 0; break;
case GPG_ERR_NO_CRL_KNOWN: any_no_crl = 1; err = 0; break;
case GPG_ERR_NOT_TRUSTED: any_not_trusted = 1; err = 0; break;
case GPG_ERR_CRL_TOO_OLD: any_crl_too_old = 1; err = 0; break;
default: break;
}
}
ctrl->check_revocations_nest_level--;
if (err)
;
@ -311,10 +315,16 @@ check_revocations (ctrl_t ctrl, chain_item_t chain)
err = gpg_error (GPG_ERR_CERT_REVOKED);
else if (any_no_crl)
err = gpg_error (GPG_ERR_NO_CRL_KNOWN);
else if (any_not_trusted)
err = gpg_error (GPG_ERR_NOT_TRUSTED);
else if (any_crl_too_old)
err = gpg_error (GPG_ERR_CRL_TOO_OLD);
else
err = 0;
if (opt.verbose)
log_info ("[%d] result of checking all CRLs: %s\n",
ctrl->check_revocations_nest_level, gpg_strerror (err));
ctrl->check_revocations_nest_level--;
return err;
}

View File

@ -59,7 +59,7 @@ workqueue_dump_queue (ctrl_t ctrl)
wqitem_t item;
unsigned int count;
/* Temporarily detach the entiere workqueue so that other threads don't
/* Temporarily detach the entire workqueue so that other threads don't
* get into our way. */
saved_workqueue = workqueue;
workqueue = NULL;
@ -74,8 +74,8 @@ workqueue_dump_queue (ctrl_t ctrl)
item->func? item->func (NULL, NULL): "nop",
item->args, strlen (item->args) > 100? "[...]":"");
/* Restore then workqueue. Actually we append the saved queue do a
* possibly updated workqueue. */
/* Restore the workqueue. Actually we append the saved queue to
* handle a possibly updated workqueue. */
if (!(item=workqueue))
workqueue = saved_workqueue;
else

View File

@ -522,6 +522,11 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
Epoch or an ISO 8601 string which can be detected by the presence
of the letter 'T'.
*** ASSERT_SIGNER <fingerprint>
This is emitted for the matching <fingerprint> when option
--assert-signer is used. The fingerprint is printed with
uppercase hex digits.
*** SIG_ID <radix64_string> <sig_creation_date> <sig-timestamp>
This is emitted only for signatures of class 0 or 1 which have
been verified okay. The string is a signature id and may be used
@ -1151,7 +1156,13 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
- learncard :: Send by the agent and gpgsm while learing
the data of a smartcard.
- card_busy :: A smartcard is still working
- scd_locked :: Waiting for other clients to unlock the scdaemon
- scd_locked :: Waiting for other clients to unlock the
scdaemon
- gpgtar :: Here <char> has a special meaning: 's'
indicates total size and 'c' file count. A
<total> of zero indicates that gpgtar is in the
scanning phase. A positive <total> is used in
the writing phase.
When <what> refers to a file path, it may be truncated.
@ -1177,6 +1188,17 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
send to the client instead of this status line. Such an inquiry
may be used to sync with Pinentry
*** GPGTAR_EXTRACT <tot> <skp> <bad> <sus> <sym> <hrd> <oth>
This status line is emitted after gpgtar has extracted files.
- tot :: Total number of files extracted and stored
- skp :: Total number of files skipped during extraction
- bad :: Number of files skipped due to a bad file name
- sus :: Number of files skipped due to a suspicious file name
- sym :: Number of symlinks not restored
- hrd :: Number of hard links not restored
- oth :: Number of files not extracted due to other reasons.
** Obsolete status codes
*** SIGEXPIRED
Removed on 2011-02-04. This is deprecated in favor of KEYEXPIRED.
@ -1678,6 +1700,7 @@ Description of some debug flags:
- RFC-1750 :: Randomness Recommendations for Security
- RFC-1991 :: PGP Message Exchange Formats (obsolete)
- RFC-2144 :: The CAST-128 Encryption Algorithm
- RFC-2253 :: UTF-8 String Representation of Distinguished Names.
- RFC-2279 :: UTF-8, a transformation format of ISO 10646
- RFC-2440 :: OpenPGP (obsolete).
- RFC-3156 :: MIME Security with Pretty Good Privacy (PGP).
@ -1700,15 +1723,21 @@ Description of some debug flags:
- RFC-5915 :: ECC Private Key Structure
- RFC-5958 :: Asymmetric Key Packages
- RFC-6337 :: ECC in OpenPGP
- RFC-7748 :: Elliptic Curves for Security (X25519 and X448)
- RFC-8410 :: Algorithm Identifiers for Ed25519, Ed448, X25519, and X448
- RFC-7292 :: PKCS #12: Personal Information Exchange Syntax v1.1
- RFC-8351 :: The PKCS #8 EncryptedPrivateKeyInfo Media Type
- RFC-8550 :: S/MIME Version 4.0 Certificate Handling
- RFC-8551 :: S/MIME Version 4.0 Message Specification
- RFC-2634 :: Enhanced Security Services for S/MIME
- RFC-5035 :: Enhanced Security Services (ESS) Update
- RFC-7253 :: The OCB Authenticated-Encryption Algorithm
- draft-koch-openpgp-2015-rfc4880bis :: Updates to RFC-4880
- T6390 :: Notes on use of X25519 in GnuPG (https://dev.gnupg.org/T6390)
** v3 fingerprints
For packet version 3 we calculate the keyids this way:
- RSA :: Low 64 bits of n
@ -1718,17 +1747,10 @@ Description of some debug flags:
** gnupg.org notations
- adsk@gnupg.org :: Additional decryption subkey. This notation
gives a list of keys an implementation SHOULD
also encrypt to. The data consists of an array
of eight-octet numbers holding the Key ID of an
encryption subkey. This notation is only valid
on an encryption subkey (i.e. with first octet
of the key flags 0x04 or 0x08). Subkeys not on
the same keyblock MUST NOT be considered. For
interoperability this notation SHOULD NOT be
marked as criticial. Due to its nature it MUST
NOT be marked as human readable.
- rem@gnupg.org :: Used by Kleopatra to implement the tag feature.
These tags are used to mark keys for easier
searching and grouping.
** Simplified revocation certificates
Revocation certificates consist only of the signature packet;
@ -1797,3 +1819,27 @@ Description of some debug flags:
it is also possible to set them direct: Use a "=" character
directly followed by a combination of "a" (for authentication), "s"
(for signing), or "c" (for certification).
** extendedKeyUsage and keyUsage in gpgsm
This table describes how the extended KeyUsage masks the KeyUsage.
| ExtKeyUsage | Valid KeyUsages |
|-----------------+------------------|
| serverAuth | digitalSignature |
| | keyEncipherment |
| | keyAgreement |
|-----------------+------------------|
| clientAuth | digitalSignature |
| | keyAgreement |
|-----------------+------------------|
| codeSigning | digitalSignature |
|-----------------+------------------|
| emailProtection | digitalSignature |
| | nonRepudiation |
| | keyEncipherment |
| | keyAgreement |
|-----------------+------------------|
| timeStamping | digitalSignature |
| | nonRepudiation |
|-----------------+------------------|

View File

@ -615,15 +615,11 @@ remote machine.
@itemx --disable-extended-key-format
@opindex enable-extended-key-format
@opindex disable-extended-key-format
Since version 2.3 keys are created in the extended private key format.
Changing the passphrase of a key will also convert the key to that new
format. This new key format is supported since GnuPG version 2.1.12
and thus there should be no need to disable it. The disable option
allows to revert to the old behavior for new keys; be aware that keys
are never migrated back to the old format. However if the enable
option has been used the disable option won't have an effect. The
advantage of the extended private key format is that it is text based
and can carry additional meta data.
These options are obsolete and have no effect. The extended key format
is used for years now and has been supported since 2.1.12. Existing
keys in the old format are migrated to the new format as soon as they
are touched.
@anchor{option --enable-ssh-support}
@item --enable-ssh-support
@ -817,6 +813,11 @@ This flag has an effect only if used in the global list. This is now
the preferred way to mark such CA; the old way of having a separate
file @file{qualified.txt} is still supported.
@item de-vs
The CA is part of an approved PKI for the German classification level
VS-NfD. It is only valid in the global trustlist. As of now this is
used only for documentation purpose.
@end table

View File

@ -264,11 +264,11 @@ out the actual signed data, but there are other pitfalls with this
format as well. It is suggested to avoid cleartext signatures in
favor of detached signatures.
Note: Sometimes the use of the @command{gpgv} tool is easier than
using the full-fledged @command{gpg} with this option. @command{gpgv}
is designed to compare signed data against a list of trusted keys and
returns with success only for a good signature. It has its own manual
page.
Note: To check whether a file was signed by a certain key the option
@option{--assert-signer} can be used. As an alternative the
@command{gpgv} tool can be used. @command{gpgv} is designed to
compare signed data against a list of trusted keys and returns with
success only for a good signature. It has its own manual page.
@item --multifile
@ -622,7 +622,7 @@ outputs an endless stream of hex-encoded octets. The special level
@item --gen-prime @var{mode} @var{bits}
@opindex gen-prime
Use the source, Luke :-). The output format is subject to change
with ant release.
with any release.
@item --enarmor
@ -770,6 +770,15 @@ specifying a value, or using ``-'' results in a key expiring in a
reasonable default interval. The values ``never'', ``none'' can be
used for no expiration date.
@item --quick-add-adsk @var{fpr} @var{adskfpr}
@opindex quick-add-adsk
Directly add an Additional Decryption Subkey to the key identified by
the fingerprint @var{fpr}. @var{adskfpr} is the fingerprint of
another key's encryption subkey. A subkey is commonly used here
because by default a primary key has no encryption capability. Use
the option @option{--with-subkey-fingerprint} with a list command to
display the subkey fingerprints.
@item --generate-key
@opindex generate-key
@itemx --gen-key
@ -1067,6 +1076,15 @@ signing.
"sensitive". If a designated revoker is marked as sensitive, it will
not be exported by default (see export-options).
@item addadsk
@opindex keyedit:addadsk
Add an Additional Decryption Subkey. The user is asked to enter the
fingerprint of another encryption subkey. Note that the exact
fingerprint of another key's encryption subkey needs to be entered.
This is because commonly the primary key has no encryption
capability. Use the option @option{--with-subkey-fingerprint} with
a list command to display the subkey fingerprints.
@item passwd
@opindex keyedit:passwd
Change the passphrase of the secret key.
@ -1405,6 +1423,10 @@ give the opposite meaning. The options are:
@opindex list-options:show-unusable-subkeys
Show revoked and expired subkeys in key listings. Defaults to no.
@item show-unusable-sigs
@opindex list-options:show-unusable-sigs
Show key signature made using weak or unsupported algorithms.
@item show-keyring
@opindex list-options:show-keyring
Display the keyring name at the head of key listings to show which
@ -1746,6 +1768,19 @@ recipient's or signator's key. If the given key is not locally
available but an LDAP keyserver is configured the missing key is
imported from that server.
@item --add-desig-revoker [sensitive:]@var{fingerprint}
@opindex add-desig-revoker
Add the key specified by @var{fingerprint} as a designated revoker to
newly created keys. If the fingerprint is prefixed with the keyword
``sensitive:'' that info is normally not exported wit the key. This
option may be given several time to add more than one designated
revoker. If the keyword ``clear'' is used instead of a fingerprint,
all designated options previously encountered are discarded.
Designated revokers are marked on the key as non-revocable. Note that
a designated revoker specified using a parameter file will also be
added to the key.
@item --trust-model @{pgp|classic|tofu|tofu+pgp|direct|always|auto@}
@opindex trust-model
Set what trust model GnuPG should follow. The models are:
@ -1854,6 +1889,24 @@ Set what trust model GnuPG should follow. The models are:
must be enabled explicitly.
@end table
@item --always-trust
@opindex always-trust
Identical to @option{--trust-model always}.
@item --assert-signer @var{fpr_or_file}
@opindex assert-signer
This option checks whether at least one valid signature on a file has
been made with the specified key. The key is either specified as a
fingerprint or a file listing fingerprints. The fingerprint must be
given or listed in compact format (no colons or spaces in between).
This option can be given multiple times and each fingerprint is
checked against the signing key as well as the corresponding primary
key. If @var{fpr_or_file} specifies a file, empty lines are ignored
as well as all lines starting with a hash sign. With this option gpg
is guaranteed to return with an exit code of 0 if and only if a
signature has been encountered, is valid, and the key matches one of
the fingerprints given by this option.
@item --auto-key-locate @var{mechanisms}
@itemx --no-auto-key-locate
@ -3173,6 +3226,10 @@ Write log output to file descriptor @var{n} and not to STDERR.
Same as @option{--logger-fd}, except the logger data is written to
file @var{file}. Use @file{socket://} to log to s socket.
@item --log-time
@opindex log-time
Prefix all log output with a timestamp even if no log file is used.
@item --attribute-fd @var{n}
@opindex attribute-fd
Write attribute subpackets to the file descriptor @var{n}. This is most
@ -3817,10 +3874,6 @@ Display the keyring name at the head of key listings to show which
keyring a given key resides on. This option is deprecated: use
@option{--list-options [no-]show-keyring} instead.
@item --always-trust
@opindex always-trust
Identical to @option{--trust-model always}. This option is deprecated.
@item --show-notation
@itemx --no-show-notation
@opindex show-notation
@ -3876,7 +3929,9 @@ current home directory (@pxref{option --homedir}).
@efindex common.conf
This is an optional configuration file read by @command{@gpgname} on
startup. It may contain options pertaining to all components of
GnuPG. Its current main use is for the "use-keyboxd" option.
GnuPG. Its current main use is for the "use-keyboxd" option. If
the default home directory @file{~/.gnupg} does not exist, GnuPG creates
this directory and a @file{common.conf} file with "use_keyboxd".
@end table
@ -4327,7 +4382,7 @@ already been reported to our bug tracker at @url{https://bugs.gnupg.org}.
@c *************** UNATTENDED **************
@c *************** **************
@c *******************************************
@manpause
@mansect notes
@node Unattended Usage of GPG
@section Unattended Usage
@ -4398,32 +4453,21 @@ previous subsection ``The quick key manipulation interface''.
The parameters for the key are either read from stdin or given as a
file on the command line. The format of the parameter file is as
follows:
@itemize @bullet
@item Text only, line length is limited to about 1000 characters.
@item UTF-8 encoding must be used to specify non-ASCII characters.
@item Empty lines are ignored.
@item Leading and trailing white space is ignored.
@item A hash sign as the first non white space character indicates
a comment line.
@item Control statements are indicated by a leading percent sign, the
arguments are separated by white space from the keyword.
@item Parameters are specified by a keyword, followed by a colon. Arguments
are separated by white space.
@item
The first parameter must be @samp{Key-Type}; control statements may be
placed anywhere.
@item
The order of the parameters does not matter except for @samp{Key-Type}
which must be the first parameter. The parameters are only used for
the generated keyblock (primary and subkeys); parameters from previous
sets are not used. Some syntactically checks may be performed.
@item
Key generation takes place when either the end of the parameter file
is reached, the next @samp{Key-Type} parameter is encountered or at the
control statement @samp{%commit} is encountered.
@end itemize
follows: Text only, line length is limited to about 1000 characters.
UTF-8 encoding must be used to specify non-ASCII characters. Empty
lines are ignored. Leading and trailing white space is ignored. A
hash sign as the first non white space character indicates a comment
line. Control statements are indicated by a leading percent sign,
their arguments are separated by white space from the keyword.
Parameters are specified by a keyword, followed by a colon; arguments
are separated by white space. The first parameter must be
@samp{Key-Type} but control statements may be placed anywhere. The
order of the parameters does not matter except for @samp{Key-Type}.
The parameters are only used for the generated keyblock (primary and
subkeys); parameters from previous sets are not used. Some syntax
checks may be performed. Key commences when either the end of the
parameter file is reached, the next @samp{Key-Type} parameter is
encountered, or the control statement @samp{%commit} is encountered.
@noindent
Control statements:
@ -4459,7 +4503,7 @@ See the previous subsection ``Ephemeral home directories''.
@item %ask-passphrase
@itemx %no-ask-passphrase
This option is a no-op for GnuPG 2.1 and later.
This option is a no-op since GnuPG version 2.1.
@item %no-protection
Using this option allows the creation of keys without any passphrase

View File

@ -408,6 +408,10 @@ Do not print a warning when the so called "secure memory" cannot be used.
When running in server mode, append all logging output to @var{file}.
Use @file{socket://} to log to socket.
@item --log-time
@opindex log-time
Prefix all log output with a timestamp even if no log file is used.
@end table
@ -492,8 +496,10 @@ This usually means that Dirmngr is employed to search for the
certificate. Note that this option makes a "web bug" like behavior
possible. LDAP server operators can see which keys you request, so by
sending you a message signed by a brand new key (which you naturally
will not have on your local keybox), the operator can tell both your IP
address and the time when you verified the signature.
will not have on your local keybox), the operator can tell both your
IP address and the time when you verified the signature. Note that if
CRL checking is not disabled issuer certificates are retrieved in any
case using the caIssuers authorityInfoAccess method.
@anchor{gpgsm-option --validation-model}
@ -623,6 +629,15 @@ always listed in @option{--with-colons} mode.
Include info about the presence of a secret key in public key listings
done with @code{--with-colons}.
@item --no-pretty-dn
@opindex no-pretty-dn
By default gpgsm prints distinguished names (DNs) like the Issuer or
Subject in a more readable format (e.g. using a well defined order of
the parts). However, this format can't be used as input strings.
This option reverts printing to standard RFC-2253 format and thus
avoids the need to use --dump-cert or --with-colons to get the
``real'' name.
@end table
@c *******************************************

View File

@ -1907,6 +1907,8 @@ Put given files and directories into a vanilla ``ustar'' archive.
@item --extract
@opindex extract
Extract all files from a vanilla ``ustar'' archive.
If no file name is given (or it is "-") the archive is taken from
stdin.
@item --encrypt
@itemx -e
@ -1918,7 +1920,8 @@ be decrypted via a secret key or a passphrase.
@item --decrypt
@itemx -d
@opindex decrypt
Extract all files from an encrypted archive.
Extract all files from an encrypted archive. If no file name is given
(or it is "-") the archive is taken from stdin.
@item --sign
@itemx -s
@ -1929,7 +1932,8 @@ encrypted archive.
@item --list-archive
@itemx -t
@opindex list-archive
List the contents of the specified archive.
List the contents of the specified archive. If no file name is given
(or it is "-") the archive is taken from stdin.
@item --symmetric
@itemx -c

View File

@ -1345,19 +1345,23 @@ build_sig_subpkt (PKT_signature *sig, sigsubpkttype_t type,
/*
* Put all the required stuff from SIG into subpackets of sig.
* PKSK is the signing key.
* PKSK is the signing key. SIGNHINTS are various flags like
* SIGNHINT_ADSK.
* Hmmm, should we delete those subpackets which are in a wrong area?
*/
void
build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk)
build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk,
unsigned int signhints)
{
u32 u;
byte buf[1+MAX_FINGERPRINT_LEN];
size_t fprlen;
/* For v4 keys we need to write the ISSUER subpacket. We do not
* want that for a future v5 format. */
if (pksk->version < 5)
* want that for a future v5 format. We also don't write it if
* only the new RENC keyflag is set (implementations with support
* for this key flag should understand the ISSUER_FPR). */
if (pksk->version < 5 && !(signhints & SIGNHINT_ADSK))
{
u = sig->keyid[0];
buf[0] = (u >> 24) & 0xff;

View File

@ -1781,12 +1781,13 @@ card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock)
}
/* Store the key at NODE into the smartcard and modify NODE to
carry the serialno stuff instead of the actual secret key
parameters. USE is the usage for that key; 0 means any
usage. */
/* Store the key at NODE into the smartcard and modify NODE to carry
the serialno stuff instead of the actual secret key parameters.
USE is the usage for that key; 0 means any usage. If
PROCESSED_KEYS is not NULL it is a poiter to an strlist which will
be filled with the keygrips of successfully stored keys. */
int
card_store_subkey (KBNODE node, int use)
card_store_subkey (KBNODE node, int use, strlist_t *processed_keys)
{
struct agent_card_info_s info;
int okay = 0;
@ -1875,7 +1876,11 @@ card_store_subkey (KBNODE node, int use)
if (rc)
log_error (_("KEYTOCARD failed: %s\n"), gpg_strerror (rc));
else
okay = 1;
{
okay = 1;
if (processed_keys)
add_to_strlist (processed_keys, hexgrip);
}
xfree (hexgrip);
leave:

View File

@ -211,10 +211,10 @@ copy_prefs (const prefitem_t *prefs)
/* Copy the public key S to D. If D is NULL allocate a new public key
structure. If S has seckret key infos, only the public stuff is
copied. */
* structure. Only the basic stuff is copied; not any ancillary
* data. */
PKT_public_key *
copy_public_key (PKT_public_key *d, PKT_public_key *s)
copy_public_key_basics (PKT_public_key *d, PKT_public_key *s)
{
int n, i;
@ -222,8 +222,8 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
d = xmalloc (sizeof *d);
memcpy (d, s, sizeof *d);
d->seckey_info = NULL;
d->user_id = scopy_user_id (s->user_id);
d->prefs = copy_prefs (s->prefs);
d->user_id = NULL;
d->prefs = NULL;
n = pubkey_get_npkey (s->pubkey_algo);
i = 0;
@ -237,6 +237,24 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
for (; i < PUBKEY_MAX_NSKEY; i++)
d->pkey[i] = NULL;
d->revkey = NULL;
d->serialno = NULL;
d->updateurl = NULL;
return d;
}
/* Copy the public key S to D. If D is NULL allocate a new public key
structure. If S has seckret key infos, only the public stuff is
copied. */
PKT_public_key *
copy_public_key (PKT_public_key *d, PKT_public_key *s)
{
d = copy_public_key_basics (d, s);
d->user_id = scopy_user_id (s->user_id);
d->prefs = copy_prefs (s->prefs);
if (!s->revkey && s->numrevkeys)
BUG();
if (s->numrevkeys)
@ -244,8 +262,6 @@ copy_public_key (PKT_public_key *d, PKT_public_key *s)
d->revkey = xmalloc(sizeof(struct revocation_key)*s->numrevkeys);
memcpy(d->revkey,s->revkey,sizeof(struct revocation_key)*s->numrevkeys);
}
else
d->revkey = NULL;
if (s->serialno)
d->serialno = xstrdup (s->serialno);

View File

@ -1718,7 +1718,8 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
*
* This function returns 0 on success. Otherwise, an error code is
* returned. In particular, GPG_ERR_NO_PUBKEY is returned if the key
* is not found.
* is not found. If R_KEYBLOCK is not NULL and a key was found the
* keyblock is stored there; otherwiese NULL is stored there.
*
* The self-signed data has already been merged into the public key
* using merge_selfsigs. The caller must release the content of PK by
@ -1726,13 +1727,17 @@ get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
* free_public_key).
*/
gpg_error_t
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname,
kbnode_t *r_keyblock)
{
gpg_error_t err;
kbnode_t keyblock;
kbnode_t found_key;
unsigned int infoflags;
if (r_keyblock)
*r_keyblock = NULL;
err = read_key_from_file_or_buffer (ctrl, fname, NULL, 0, &keyblock);
if (!err)
{
@ -1747,7 +1752,10 @@ get_pubkey_fromfile (ctrl_t ctrl, PKT_public_key *pk, const char *fname)
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
}
release_kbnode (keyblock);
if (!err && r_keyblock)
*r_keyblock = keyblock;
else
release_kbnode (keyblock);
return err;
}
@ -1809,12 +1817,12 @@ get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
* returned public key may be a subkey rather than the primary key.
* Note: The self-signed data has already been merged into the public
* key using merge_selfsigs. Free *PK by calling
* release_public_key_parts (or, if PK was allocated using xfree, you
* release_public_key_parts (or, if PK was allocated using xmalloc, you
* can use free_public_key, which calls release_public_key_parts(PK)
* and then xfree(PK)).
*
* If PK->REQ_USAGE is set, it is used to filter the search results.
* (Thus, if PK is not NULL, PK->REQ_USAGE must be valid!!!) See the
* Thus, if PK is not NULL, PK->REQ_USAGE must be valid! See the
* documentation for finish_lookup to understand exactly how this is
* used.
*
@ -2417,7 +2425,8 @@ merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock)
}
static int
/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
unsigned int
parse_key_usage (PKT_signature * sig)
{
int key_usage = 0;
@ -2707,7 +2716,7 @@ merge_selfsigs_main (ctrl_t ctrl, kbnode_t keyblock, int *r_revoked,
* and there was no way to change it, so we start with the one
* from the key packet. We do not support v3 keys anymore but
* we keep the code in case a future key versions introduces a
* hadr expire time again. */
* hard expire time again. */
key_expire = pk->max_expiredate;
key_expire_seen = 1;
}
@ -3247,7 +3256,7 @@ buf_to_sig (const byte * buf, size_t len)
* has_expired
* expired_date
*
* On this subkey's most revent valid self-signed packet, the
* On this subkey's most recent valid self-signed packet, the
* following field is set:
*
* flags.chosen_selfsig

View File

@ -130,6 +130,7 @@ enum cmd_and_opt_values
aQuickRevSig,
aQuickAddUid,
aQuickAddKey,
aQuickAddADSK,
aQuickRevUid,
aQuickSetExpire,
aQuickSetPrimaryUid,
@ -337,6 +338,7 @@ enum cmd_and_opt_values
oEncryptToDefaultKey,
oLoggerFD,
oLoggerFile,
oLogTime,
oUtf8Strings,
oNoUtf8Strings,
oDisableCipherAlgo,
@ -443,6 +445,8 @@ enum cmd_and_opt_values
oForbidGenKey,
oRequireCompliance,
oCompatibilityFlags,
oAddDesigRevoker,
oAssertSigner,
oNoop
};
@ -484,6 +488,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_c (aQuickAddUid, "quick-adduid", "@"),
ARGPARSE_c (aQuickAddKey, "quick-add-key", "@"),
ARGPARSE_c (aQuickAddKey, "quick-addkey", "@"),
ARGPARSE_c (aQuickAddADSK, "quick-add-adsk", "@"),
ARGPARSE_c (aQuickRevUid, "quick-revoke-uid",
N_("quickly revoke a user-id")),
ARGPARSE_c (aQuickRevUid, "quick-revuid", "@"),
@ -599,6 +604,7 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oLoggerFile, "log-file",
N_("|FILE|write server mode logs to FILE")),
ARGPARSE_s_s (oLoggerFile, "logger-file", "@"), /* 1.4 compatibility. */
ARGPARSE_s_n (oLogTime, "log-time", "@"),
ARGPARSE_s_n (oQuickRandom, "debug-quick-random", "@"),
@ -702,7 +708,8 @@ static gpgrt_opt_t opts[] = {
ARGPARSE_s_s (oForceOwnertrust, "force-ownertrust", "@"),
ARGPARSE_s_n (oNoAutoTrustNewKey, "no-auto-trust-new-key", "@"),
#endif
ARGPARSE_s_s (oAddDesigRevoker, "add-desig-revoker", "@"),
ARGPARSE_s_s (oAssertSigner, "assert-signer", "@"),
ARGPARSE_header ("Input", N_("Options controlling the input")),
@ -1026,8 +1033,12 @@ static struct compatibility_flags_s compatibility_flags [] =
/* The list of the default AKL methods. */
#define DEFAULT_AKL_LIST "local,wkd"
/* Can be set to true to force gpg to return with EXIT_FAILURE. */
int g10_errors_seen = 0;
/* If opt.assert_signer_list is used and this variabale is not true
* gpg will be forced to return EXIT_FAILURE. */
int assert_signer_true = 0;
static int utf8_strings =
#ifdef HAVE_W32_SYSTEM
@ -1039,6 +1050,7 @@ static int utf8_strings =
static int maybe_setuid = 1;
static unsigned int opt_set_iobuf_size;
static unsigned int opt_set_iobuf_size_used;
static int opt_log_time;
/* Collection of options used only in this module. */
static struct {
@ -2047,6 +2059,8 @@ parse_list_options(char *str)
char *subpackets=""; /* something that isn't NULL */
struct parse_options lopts[]=
{
{"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL,
NULL},
{"show-photos",LIST_SHOW_PHOTOS,NULL,
N_("display photo IDs during key listings")},
{"show-usage",LIST_SHOW_USAGE,NULL,
@ -2069,6 +2083,8 @@ parse_list_options(char *str)
N_("show revoked and expired user IDs in key listings")},
{"show-unusable-subkeys",LIST_SHOW_UNUSABLE_SUBKEYS,NULL,
N_("show revoked and expired subkeys in key listings")},
{"show-unusable-sigs",LIST_SHOW_UNUSABLE_SIGS,NULL,
N_("show signatures with invalid algorithms during signature listings")},
{"show-keyring",LIST_SHOW_KEYRING,NULL,
N_("show the keyring name in key listings")},
{"show-sig-expire",LIST_SHOW_SIG_EXPIRE,NULL,
@ -2077,20 +2093,25 @@ parse_list_options(char *str)
N_("show preferences")},
{"show-pref-verbose", LIST_SHOW_PREF_VERBOSE, NULL,
N_("show preferences")},
{"show-sig-subpackets",LIST_SHOW_SIG_SUBPACKETS,NULL,
NULL},
{"show-only-fpr-mbox",LIST_SHOW_ONLY_FPR_MBOX, NULL,
NULL},
{"sort-sigs", LIST_SORT_SIGS, NULL,
NULL},
{NULL,0,NULL,NULL}
};
int i;
/* C99 allows for non-constant initializers, but we'd like to
compile everywhere, so fill in the show-sig-subpackets argument
here. Note that if the parse_options array changes, we'll have
to change the subscript here. */
lopts[13].value=&subpackets;
to change the subscript here. We use a loop here in case the
list above is reordered. */
for (i=0; lopts[i].name; i++)
if (lopts[i].bit == LIST_SHOW_SIG_SUBPACKETS)
{
lopts[i].value = &subpackets;
break;
}
if(parse_options(str,&opt.list_options,lopts,1))
{
@ -2677,6 +2698,7 @@ main (int argc, char **argv)
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
case aQuickAddADSK:
case aQuickRevUid:
case aQuickSetExpire:
case aQuickSetPrimaryUid:
@ -2853,6 +2875,9 @@ main (int argc, char **argv)
case oLoggerFile:
logfile = pargs.r.ret_str;
break;
case oLogTime:
opt_log_time = 1;
break;
case oWithFingerprint:
opt.with_fingerprint = 1;
@ -3707,6 +3732,18 @@ main (int argc, char **argv)
opt.flags.require_compliance = 1;
break;
case oAddDesigRevoker:
if (!strcmp (pargs.r.ret_str, "clear"))
FREE_STRLIST (opt.desig_revokers);
else
append_to_strlist (&opt.desig_revokers, pargs.r.ret_str);
break;
case oAssertSigner:
add_to_strlist (&opt.assert_signer_list, pargs.r.ret_str);
break;
case oNoop: break;
default:
@ -3811,6 +3848,9 @@ main (int argc, char **argv)
| GPGRT_LOG_WITH_TIME
| GPGRT_LOG_WITH_PID ));
}
else if (opt_log_time)
log_set_prefix (NULL, (GPGRT_LOG_WITH_PREFIX|GPGRT_LOG_NO_REGISTRY
|GPGRT_LOG_WITH_TIME));
if (opt.verbose > 2)
log_info ("using character set '%s'\n", get_native_charset ());
@ -4157,17 +4197,27 @@ main (int argc, char **argv)
* need to add the keyrings if we are running under SELinux, this
* is so that the rings are added to the list of secured files.
* We do not add any keyring if --no-keyring or --use-keyboxd has
* been used. */
* been used. Note that keydb_add_resource may create a new
* homedir and also tries to write a common.conf to enable the use
* of the keyboxd - in this case a special error code is returned
* and use_keyboxd is then also set. */
if (!opt.use_keyboxd
&& default_keyring >= 0
&& (ALWAYS_ADD_KEYRINGS
|| (cmd != aDeArmor && cmd != aEnArmor && cmd != aGPGConfTest)))
{
gpg_error_t tmperr = 0;
if (!nrings || default_keyring > 0) /* Add default ring. */
keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG,
KEYDB_RESOURCE_FLAG_DEFAULT);
for (sl = nrings; sl; sl = sl->next )
keydb_add_resource (sl->d, sl->flags);
tmperr = keydb_add_resource ("pubring" EXTSEP_S GPGEXT_GPG,
KEYDB_RESOURCE_FLAG_DEFAULT);
if (gpg_err_code (tmperr) == GPG_ERR_TRUE && opt.use_keyboxd)
; /* The keyboxd has been enabled. */
else
{
for (sl = nrings; sl; sl = sl->next )
keydb_add_resource (sl->d, sl->flags);
}
}
FREE_STRLIST(nrings);
@ -4275,6 +4325,7 @@ main (int argc, char **argv)
case aQuickKeygen:
case aQuickAddUid:
case aQuickAddKey:
case aQuickAddADSK:
case aQuickRevUid:
case aQuickSetPrimaryUid:
case aQuickUpdatePref:
@ -4742,6 +4793,17 @@ main (int argc, char **argv)
}
break;
case aQuickAddADSK:
{
if (argc != 2)
wrong_args ("--quick-add-adsk FINGERPRINT ADSK-FINGERPRINT");
if (mopt.forbid_gen_key)
gen_key_forbidden ();
else
keyedit_quick_addadsk (ctrl, argv[0], argv[1]);
}
break;
case aQuickRevUid:
{
const char *uid, *uidtorev;
@ -5048,9 +5110,6 @@ main (int argc, char **argv)
size_t nn;
p = gcry_random_bytes (n, level);
#ifdef HAVE_DOSISH_SYSTEM
setmode ( fileno(stdout), O_BINARY );
#endif
if (hexhack)
{
for (nn = 0; nn < n; nn++)
@ -5068,6 +5127,7 @@ main (int argc, char **argv)
}
else
{
es_set_binary (es_stdout);
es_fwrite( p, n, 1, es_stdout );
}
xfree(p);
@ -5398,7 +5458,15 @@ g10_exit( int rc )
gnupg_block_all_signals ();
emergency_cleanup ();
rc = rc? rc : log_get_errorcount(0)? 2 : g10_errors_seen? 1 : 0;
if (rc)
;
else if (log_get_errorcount(0))
rc = 2;
else if (g10_errors_seen)
rc = 1;
else if (opt.assert_signer_list && !assert_signer_true)
rc = 1;
exit (rc);
}

View File

@ -118,7 +118,7 @@ static struct debug_flags_s debug_flags [] =
int g10_errors_seen = 0;
int assert_signer_true = 0;
static char *
make_libversion (const char *libname, const char *(*getfnc)(const char*))

View File

@ -2656,6 +2656,7 @@ transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
* in case of cv25519. We have only opaque MPIs here. */
if (pk->pubkey_algo == PUBKEY_ALGO_ECDH
&& !strcmp (curvestr, "1.3.6.1.4.1.3029.1.5.1")
&& !gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1)
&& gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
{
const unsigned char *pp;

View File

@ -35,14 +35,19 @@
#include "key-clean.h"
#define NF_USABLE 8 /* Usable signature and not a revocation. */
#define NF_CONSIDER 9 /* Internal use. */
#define NF_PROCESSED 10 /* Internal use. */
#define NF_REVOC 11 /* Usable revocation. */
#define NF_NOKEY 12 /* Key not available. */
/*
* Mark the signature of the given UID which are used to certify it.
* To do this, we first remove all signatures which are not valid and
* from the remaining 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.
* node flag bit NF_USABLE. Revocations are marked with NF_REVOC, and
* sigs from unavailable keys are marked with NF_NOKEY.
*/
void
mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
@ -57,7 +62,8 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
{
int rc;
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
node->flag &= ~(1<<NF_USABLE | 1<<NF_CONSIDER
| 1<<NF_PROCESSED | 1<<NF_REVOC | 1<<NF_NOKEY);
if (node->pkt->pkttype == PKT_USER_ID
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
@ -81,19 +87,20 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
/* 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;
node->flag |= 1<<NF_NOKEY;
continue;
}
node->flag |= 1<<9;
node->flag |= 1<<NF_CONSIDER;
}
/* Reset the remaining flags. */
for (; node; node = node->next)
node->flag &= ~(1<<8 | 1<<9 | 1<<10 | 1<<11 | 1<<12);
node->flag &= ~(1<<NF_USABLE | 1<<NF_CONSIDER
| 1<<NF_PROCESSED | 1<<NF_REVOC | 1<<NF_NOKEY);
/* 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. */
/* kbnode flag usage: bit NF_CONSIDER is here set for signatures to consider,
* bit NF_PROCESSED will be set by the loop to keep track of keyIDs already
* processed, bit NF_USABLE will be set for the usable signatures, and bit
* NF_REVOC will be set for usable revocations. */
/* For each cert figure out the latest valid one. */
for (node=uidnode->next; node; node = node->next)
@ -105,11 +112,11 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
break;
if ( !(node->flag & (1<<9)) )
if ( !(node->flag & (1<<NF_CONSIDER)) )
continue; /* not a node to look at */
if ( (node->flag & (1<<10)) )
if ( (node->flag & (1<<NF_PROCESSED)) )
continue; /* signature with a keyID already processed */
node->flag |= (1<<10); /* mark this node as processed */
node->flag |= (1<<NF_PROCESSED); /* mark this node as processed */
sig = node->pkt->pkt.signature;
signode = node;
sigdate = sig->timestamp;
@ -121,14 +128,14 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|| n->pkt->pkttype == PKT_SECRET_SUBKEY)
break;
if ( !(n->flag & (1<<9)) )
if ( !(n->flag & (1<<NF_CONSIDER)) )
continue;
if ( (n->flag & (1<<10)) )
if ( (n->flag & (1<<NF_PROCESSED)) )
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 */
n->flag |= (1<<NF_PROCESSED); /* 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
@ -197,13 +204,13 @@ mark_usable_uid_certs (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
if (expire==0 || expire > curtime )
{
signode->flag |= (1<<8); /* yeah, found a good cert */
signode->flag |= (1<<NF_USABLE); /* yeah, found a good cert */
if (next_expire && expire && expire < *next_expire)
*next_expire = expire;
}
}
else
signode->flag |= (1<<11);
signode->flag |= (1<<NF_REVOC);
}
}
@ -231,12 +238,13 @@ clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
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.
not even a candidate. If a sig has flag NF_CONSIDER or
NF_PROCESSED, that means it was selected as a candidate and
vetted. If a sig has flag NF_USABLE it is a usable signature.
If a sig has flag NF_REVOC it is a usable revocation. If a sig
has flag NF_NOKEY 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
@ -252,34 +260,34 @@ clean_sigs_from_uid (ctrl_t ctrl, kbnode_t keyblock, kbnode_t uidnode,
&& node->pkt->pkt.signature->keyid[1] == keyid[1]) : 1;
/* Keep usable uid sigs ... */
if ((node->flag & (1<<8)) && keep)
if ((node->flag & (1<<NF_USABLE)) && keep)
continue;
/* ... and usable revocations... */
if ((node->flag & (1<<11)) && keep)
if ((node->flag & (1<<NF_REVOC)) && 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))
if(node->flag & (1<<NF_NOKEY))
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. */
/* At this point, if NF_NOKEY is set, the signing key was
* unavailable. If NF_CONSIDER or NF_PROCESSED 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" );
node->flag&(1<<NF_NOKEY)? "key unavailable":
node->flag&(1<<NF_CONSIDER)? "signature superseded"
/* */ : "invalid signature" );
delete_kbnode (node);
deleted++;

View File

@ -37,6 +37,7 @@
#include "../kbx/keybox.h"
#include "keydb.h"
#include "../common/i18n.h"
#include "../common/comopt.h"
#include "keydb-private.h" /* For struct keydb_handle_s */
@ -265,8 +266,24 @@ maybe_create_keyring_or_box (char *filename, int is_box, int force_create)
*last_slash_in_filename = save_slash;
goto leave;
}
*last_slash_in_filename = save_slash;
if (!opt.use_keyboxd
&& !parse_comopt (GNUPG_MODULE_NAME_GPG, 0)
&& comopt.use_keyboxd)
{
/* The above try_make_homedir created a new default hoemdir
* and also wrote a new common.conf. Thus we now see that
* use-keyboxd has been set. Let's set this option and
* return a dedicated error code. */
opt.use_keyboxd = comopt.use_keyboxd;
rc = gpg_error (GPG_ERR_TRUE);
goto leave;
}
}
*last_slash_in_filename = save_slash;
else
*last_slash_in_filename = save_slash;
/* To avoid races with other instances of gpg trying to create or
update the keyring (it is removed during an update for a short
@ -555,7 +572,8 @@ keydb_search_desc_dump (struct keydb_search_desc *desc)
* If KEYDB_RESOURCE_FLAG_READONLY is set and the resource is a
* keyring (not a keybox), then the keyring is marked as read only and
* operations just as keyring_insert_keyblock will return
* GPG_ERR_ACCESS. */
* GPG_ERR_ACCESS.
*/
gpg_error_t
keydb_add_resource (const char *url, unsigned int flags)
{
@ -774,9 +792,12 @@ keydb_add_resource (const char *url, unsigned int flags)
leave:
if (err)
{
log_error (_("keyblock resource '%s': %s\n"),
filename, gpg_strerror (err));
write_status_error ("add_keyblock_resource", err);
if (gpg_err_code (err) != GPG_ERR_TRUE)
{
log_error (_("keyblock resource '%s': %s\n"),
filename, gpg_strerror (err));
write_status_error ("add_keyblock_resource", err);
}
}
else
any_registered = 1;

View File

@ -391,7 +391,8 @@ gpg_error_t get_best_pubkey_byname (ctrl_t ctrl, enum get_pubkey_modes mode,
/* Get a public key directly from file FNAME. */
gpg_error_t get_pubkey_fromfile (ctrl_t ctrl,
PKT_public_key *pk, const char *fname);
PKT_public_key *pk, const char *fname,
kbnode_t *r_keyblock);
/* Get a public key from a buffer. */
gpg_error_t get_pubkey_from_buffer (ctrl_t ctrl, PKT_public_key *pkbuf,
@ -468,6 +469,9 @@ void setup_main_keyids (kbnode_t keyblock);
data structures. */
void merge_keys_and_selfsig (ctrl_t ctrl, kbnode_t keyblock);
/* This function parses the key flags and returns PUBKEY_USAGE_ flags. */
unsigned int parse_key_usage (PKT_signature *sig);
char *get_user_id_string_native (ctrl_t ctrl, u32 *keyid);
char *get_long_user_id_string (ctrl_t ctrl, u32 *keyid);
char *get_user_id (ctrl_t ctrl, u32 *keyid, size_t *rn, int *r_nouid);
@ -511,11 +515,18 @@ keyid_cmp (const u32 *a, const u32 *b)
return 0;
}
/* Return true if both keyids are equal. */
static int GPGRT_ATTR_UNUSED
keyid_eq (const u32 *a, const u32 *b)
{
return a[0] == b[0] && a[1] == b[1];
}
/* Return whether PK is a primary key. */
static int GPGRT_ATTR_UNUSED
pk_is_primary (PKT_public_key *pk)
{
return keyid_cmp (pk_keyid (pk), pk_main_keyid (pk)) == 0;
return keyid_eq (pk_keyid (pk), pk_main_keyid (pk));
}
/* Copy the keyid in SRC to DEST and return DEST. */

View File

@ -1,7 +1,7 @@
/* keyedit.c - Edit properties of a key
* Copyright (C) 1998-2010 Free Software Foundation, Inc.
* Copyright (C) 1998-2017 Werner Koch
* Copyright (C) 2015, 2016, 2022 g10 Code GmbH
* Copyright (C) 2015, 2016, 2022-2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -73,6 +73,8 @@ static int menu_delsig (ctrl_t ctrl, kbnode_t pub_keyblock);
static int menu_clean (ctrl_t ctrl, kbnode_t keyblock, int self_only);
static void menu_delkey (KBNODE pub_keyblock);
static int menu_addrevoker (ctrl_t ctrl, kbnode_t pub_keyblock, int sensitive);
static int menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock,
const char *adskfpr);
static gpg_error_t menu_expire (ctrl_t ctrl, kbnode_t pub_keyblock,
int unattended, u32 newexpiration);
static int menu_changeusage (ctrl_t ctrl, kbnode_t keyblock);
@ -1243,7 +1245,7 @@ enum cmdids
cmdREVSIG, cmdREVKEY, cmdREVUID, cmdDELSIG, cmdPRIMARY, cmdDEBUG,
cmdSAVE, cmdADDUID, cmdADDPHOTO, cmdDELUID, cmdADDKEY, cmdDELKEY,
cmdADDREVOKER, cmdTOGGLE, cmdSELKEY, cmdPASSWD, cmdTRUST, cmdPREF,
cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN,
cmdEXPIRE, cmdCHANGEUSAGE, cmdBACKSIGN, cmdADDADSK,
#ifndef NO_TRUST_MODELS
cmdENABLEKEY, cmdDISABLEKEY,
#endif /*!NO_TRUST_MODELS*/
@ -1308,6 +1310,8 @@ static struct
{ "delkey", cmdDELKEY, 0, N_("delete selected subkeys")},
{ "addrevoker", cmdADDREVOKER, KEYEDIT_NEED_SK,
N_("add a revocation key")},
{ "addadsk", cmdADDADSK, KEYEDIT_NEED_SK,
N_("add an additional decryption subkey")},
{ "delsig", cmdDELSIG, 0,
N_("delete signatures from the selected user IDs")},
{ "expire", cmdEXPIRE, KEYEDIT_NEED_SK | KEYEDIT_NEED_SUBSK,
@ -1421,6 +1425,8 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
int sec_shadowing = 0;
int run_subkey_warnings = 0;
int have_commands = !!commands;
strlist_t delseckey_list = NULL;
int delseckey_list_warn = 0;
if (opt.command_fd != -1)
;
@ -1497,6 +1503,14 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
subkey_expire_warning (keyblock);
}
if (delseckey_list_warn)
{
delseckey_list_warn = 0;
tty_printf
(_("Note: the local copy of the secret key"
" will only be deleted with \"save\".\n"));
}
do
{
xfree (answer);
@ -1869,10 +1883,12 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
if (node)
{
PKT_public_key *xxpk = node->pkt->pkt.public_key;
if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0))
if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0,
&delseckey_list))
{
redisplay = 1;
sec_shadowing = 1;
delseckey_list_warn = 1;
}
}
}
@ -1949,7 +1965,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
pkt->pkttype = PKT_PUBLIC_KEY;
/* Ask gpg-agent to store the secret key to card. */
if (card_store_subkey (node, 0))
if (card_store_subkey (node, 0, NULL))
{
redisplay = 1;
sec_shadowing = 1;
@ -2000,6 +2016,15 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
}
break;
case cmdADDADSK:
if (menu_addadsk (ctrl, keyblock, NULL))
{
redisplay = 1;
modified = 1;
merge_keys_and_selfsig (ctrl, keyblock);
}
break;
case cmdREVUID:
{
int n1;
@ -2250,6 +2275,27 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
}
}
if (delseckey_list)
{
strlist_t sl;
for (err = 0, sl = delseckey_list; sl; sl = sl->next)
{
if (*sl->d)
{
err = agent_delete_key (ctrl, sl->d, NULL, 1/*force*/);
if (err)
break;
*sl->d = 0; /* Mark deleted. */
}
}
if (err)
{
log_error (_("deleting copy of secret key failed: %s\n"),
gpg_strerror (err));
break; /* the "save". */
}
}
if (sec_shadowing)
{
err = agent_scd_learn (NULL, 1);
@ -2279,6 +2325,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
} /* End of the main command loop. */
leave:
free_strlist (delseckey_list);
release_kbnode (keyblock);
keydb_release (kdbhd);
xfree (answer);
@ -3201,6 +3248,69 @@ keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
}
/* Unattended ADSK setup function.
*
* FPR is the fingerprint of our key. ADSKFPR is the fingerprint of
* another subkey which we want to add as ADSK to our key.
*/
void
keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr)
{
gpg_error_t err;
kbnode_t keyblock;
KEYDB_HANDLE kdbhd;
int modified = 0;
PKT_public_key *pk;
#ifdef HAVE_W32_SYSTEM
/* See keyedit_menu for why we need this. */
check_trustdb_stale (ctrl);
#endif
/* We require a fingerprint because only this uniquely identifies a
* key and may thus be used to select a key for unattended adsk
* adding. */
if (find_by_primary_fpr (ctrl, fpr, &keyblock, &kdbhd))
goto leave;
if (fix_keyblock (ctrl, &keyblock))
modified++;
pk = keyblock->pkt->pkt.public_key;
if (pk->flags.revoked)
{
if (!opt.verbose)
show_key_with_all_names (ctrl, es_stdout, keyblock, 0, 0, 0, 0, 0, 1);
log_error ("%s%s", _("Key is revoked."), "\n");
goto leave;
}
/* Locate and add the ADSK. Note that the called function already
* prints error messages. */
if (menu_addadsk (ctrl, keyblock, adskfpr))
modified = 1;
else
log_inc_errorcount (); /* (We use log_info in menu_adsk) */
es_fflush (es_stdout);
/* Store. */
if (modified)
{
err = keydb_update_keyblock (ctrl, kdbhd, keyblock);
if (err)
{
log_error (_("update failed: %s\n"), gpg_strerror (err));
goto leave;
}
}
leave:
release_kbnode (keyblock);
keydb_release (kdbhd);
}
/* Unattended expiration setting function for the main key. If
* SUBKEYFPRS is not NULL and SUBKEYSFPRS[0] is neither NULL, it is
* expected to be an array of fingerprints for subkeys to change. It
@ -4643,6 +4753,176 @@ fail:
}
/*
* Ask for a new additional decryption subkey and add it to the key
* block. Returns true if the keyblock was changed and false
* otherwise. If ADSKFPR is not NULL, this fucntion has been called
* by quick_addadsk and gives the fingerprint of the to be added key.
*/
static int
menu_addadsk (ctrl_t ctrl, kbnode_t pub_keyblock, const char *adskfpr)
{
PKT_public_key *pk;
PKT_public_key *sub_pk;
PKT_public_key *main_pk;
PKT_public_key *adsk_pk = NULL;
kbnode_t adsk_keyblock = NULL;
PKT_signature *sig = NULL;
char *answer = NULL;
gpg_error_t err;
KEYDB_SEARCH_DESC desc;
byte fpr[MAX_FINGERPRINT_LEN];
size_t fprlen;
kbnode_t node, node2;
kbnode_t subkeynode = NULL;
PACKET *pkt; /* (temp. use; will be put into a kbnode_t) */
log_assert (pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
main_pk = pub_keyblock->pkt->pkt.public_key;
for (;;)
{
xfree (answer);
if (adskfpr)
answer = xstrdup (adskfpr);
else
{
answer = cpr_get_utf8
("keyedit.addadsk",
_("Enter the fingerprint of the additional decryption subkey: "));
if (answer[0] == '\0' || answer[0] == CONTROL_D)
{
err = gpg_error (GPG_ERR_CANCELED);
goto leave;
}
}
if (classify_user_id (answer, &desc, 1)
|| desc.mode != KEYDB_SEARCH_MODE_FPR)
{
log_info (_("\"%s\" is not a fingerprint\n"), answer);
err = gpg_error (GPG_ERR_INV_USER_ID);
if (adskfpr)
goto leave;
continue;
}
free_public_key (adsk_pk);
adsk_pk = xcalloc (1, sizeof *adsk_pk);
adsk_pk->req_usage = PUBKEY_USAGE_ENC;
release_kbnode (adsk_keyblock);
adsk_keyblock = NULL;
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, adsk_pk, answer, &adsk_keyblock, NULL, 1);
if (err)
{
log_info (_("key \"%s\" not found: %s\n"), answer,
gpg_strerror (err));
if ((!opt.batch || adskfpr) && !opt.quiet
&& gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY)
log_info (_("Did you specify the fingerprint of a subkey?\n"));
if (adskfpr)
goto leave;
continue;
}
for (node = adsk_keyblock; node; node = node->next)
{
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
pk = node->pkt->pkt.public_key;
fingerprint_from_pk (pk, fpr, &fprlen);
if (fprlen == desc.fprlen
&& !memcmp (fpr, desc.u.fpr, fprlen)
&& (pk->pubkey_usage & PUBKEY_USAGE_ENC))
break;
}
}
if (!node)
{
err = gpg_error (GPG_ERR_WRONG_KEY_USAGE);
log_info (_("key \"%s\" not found: %s\n"), answer,
gpg_strerror (err));
if ((!opt.batch || adskfpr) && !opt.quiet)
log_info (_("Did you specify the fingerprint of a subkey?\n"));
if (adskfpr)
goto leave;
continue;
}
/* Check that the selected subkey is not yet on our keyblock. */
for (node2 = pub_keyblock; node2; node2 = node2->next)
{
if (node2->pkt->pkttype == PKT_PUBLIC_KEY
|| node2->pkt->pkttype == PKT_PUBLIC_SUBKEY)
{
pk = node2->pkt->pkt.public_key;
fingerprint_from_pk (pk, fpr, &fprlen);
if (fprlen == desc.fprlen
&& !memcmp (fpr, desc.u.fpr, fprlen))
break;
}
}
if (node2)
{
log_info (_("key \"%s\" is already on this keyblock\n"), answer);
err = gpg_error (GPG_ERR_DUP_KEY);
if (adskfpr)
goto leave;
continue;
}
break;
}
/* Append the subkey.
* Note that we don't use the ADSK_PK directly because this is the
* primary key and in general we use a subkey to which NODE points.
* ADSK_PK has only been used to pass the requested key usage to
* get_pubkey_byname. SUB_PK will point to the actual adsk. */
log_assert (node->pkt->pkttype == PKT_PUBLIC_KEY
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY);
sub_pk = copy_public_key_basics (NULL, node->pkt->pkt.public_key);
keyid_from_pk (main_pk, sub_pk->main_keyid); /* Fixup main keyid. */
log_assert ((sub_pk->pubkey_usage & PUBKEY_USAGE_ENC));
sub_pk->pubkey_usage = PUBKEY_USAGE_RENC; /* 'e' -> 'r' */
pkt = xcalloc (1, sizeof *pkt);
pkt->pkttype = PKT_PUBLIC_SUBKEY; /* Make sure it is a subkey. */
pkt->pkt.public_key = sub_pk;
subkeynode = new_kbnode (pkt);
/* Make the signature. */
err = make_keysig_packet (ctrl, &sig, main_pk, NULL, sub_pk, main_pk, 0x18,
sub_pk->timestamp, 0,
keygen_add_key_flags_and_expire, sub_pk, NULL);
if (err)
{
write_status_error ("keysig", err);
log_error ("creating key binding failed: %s\n", gpg_strerror (err));
goto leave;
}
/* Append the subkey packet and the binding signature. */
add_kbnode (pub_keyblock, subkeynode);
subkeynode = NULL;
pkt = xcalloc (1, sizeof *pkt);
pkt->pkttype = PKT_SIGNATURE;
pkt->pkt.signature = sig;
add_kbnode (pub_keyblock, new_kbnode (pkt));
leave:
xfree (answer);
free_public_key (adsk_pk);
release_kbnode (adsk_keyblock);
release_kbnode (subkeynode);
if (!err)
return 1; /* The keyblock was modified. */
else
return 0; /* Not modified. */
}
/* With FORCE_MAINKEY cleared this function handles the interactive
* menu option "expire". With UNATTENDED set to 1 this function only
* sets the expiration date of the primary key to NEWEXPIRATION and

View File

@ -44,6 +44,7 @@ void keyedit_quick_adduid (ctrl_t ctrl, const char *username,
const char *newuid);
void keyedit_quick_addkey (ctrl_t ctrl, const char *fpr, const char *algostr,
const char *usagestr, const char *expirestr);
void keyedit_quick_addadsk (ctrl_t ctrl, const char *fpr, const char *adskfpr);
void keyedit_quick_revuid (ctrl_t ctrl, const char *username,
const char *uidtorev);
void keyedit_quick_sign (ctrl_t ctrl, const char *fpr,

View File

@ -130,12 +130,6 @@ struct output_control_s
};
struct opaque_data_usage_and_pk {
unsigned int usage;
PKT_public_key *pk;
};
/* FIXME: These globals vars are ugly. And using MAX_PREFS even for
* aeads is useless, given that we don't expects more than a very few
* algorithms. */
@ -256,22 +250,27 @@ write_uid (kbnode_t root, const char *s)
static void
do_add_key_flags (PKT_signature *sig, unsigned int use)
{
byte buf[1];
byte buf[2] = { 0, 0 };
buf[0] = 0;
/* The spec says that all primary keys MUST be able to certify. */
if ( sig->sig_class != 0x18 )
buf[0] |= 0x01;
/* The spec says that all primary keys MUST be able to certify. */
if(sig->sig_class!=0x18)
buf[0] |= 0x01;
if (use & PUBKEY_USAGE_SIG)
buf[0] |= 0x02;
if (use & PUBKEY_USAGE_ENC)
buf[0] |= 0x04 | 0x08;
if (use & PUBKEY_USAGE_AUTH)
buf[0] |= 0x20;
if (use & PUBKEY_USAGE_GROUP)
buf[0] |= 0x80;
if (use & PUBKEY_USAGE_SIG)
buf[0] |= 0x02;
if (use & PUBKEY_USAGE_ENC)
buf[0] |= 0x04 | 0x08;
if (use & PUBKEY_USAGE_AUTH)
buf[0] |= 0x20;
if (use & PUBKEY_USAGE_RENC)
buf[1] |= 0x04;
if (use & PUBKEY_USAGE_TIME)
buf[1] |= 0x08;
build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, 1);
build_sig_subpkt (sig, SIGSUBPKT_KEY_FLAGS, buf, buf[1]? 2:1);
}
@ -318,13 +317,11 @@ keygen_add_key_flags (PKT_signature *sig, void *opaque)
}
static int
int
keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque)
{
struct opaque_data_usage_and_pk *oduap = opaque;
do_add_key_flags (sig, oduap->usage);
return keygen_add_key_expire (sig, oduap->pk);
keygen_add_key_flags (sig, opaque);
return keygen_add_key_expire (sig, opaque);
}
@ -1215,7 +1212,6 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
PKT_signature *sig;
KBNODE node;
PKT_public_key *pri_pk, *sub_pk;
struct opaque_data_usage_and_pk oduap;
if (opt.verbose)
log_info(_("writing key binding signature\n"));
@ -1241,11 +1237,10 @@ write_keybinding (ctrl_t ctrl, kbnode_t root,
BUG();
/* Make the signature. */
oduap.usage = use;
oduap.pk = sub_pk;
sub_pk->pubkey_usage = use;
err = make_keysig_packet (ctrl, &sig, pri_pk, NULL, sub_pk, pri_psk, 0x18,
timestamp, 0,
keygen_add_key_flags_and_expire, &oduap,
keygen_add_key_flags_and_expire, sub_pk,
cache_nonce);
if (err)
{
@ -3792,14 +3787,29 @@ release_parameter_list (struct para_data_s *r)
}
}
/* Return the N-th parameter of name KEY from PARA. An IDX of 0
* returns the first and so on. */
static struct para_data_s *
get_parameter( struct para_data_s *para, enum para_name key )
get_parameter_idx (struct para_data_s *para, enum para_name key,
unsigned int idx)
{
struct para_data_s *r;
struct para_data_s *r;
for( r = para; r && r->key != key; r = r->next )
;
return r;
for(r = para; r; r = r->next)
if (r->key == key)
{
if (!idx)
return r;
idx--;
}
return NULL;
}
/* Return the first parameter of name KEY from PARA. */
static struct para_data_s *
get_parameter (struct para_data_s *para, enum para_name key)
{
return get_parameter_idx (para, key, 0);
}
static const char *
@ -3947,6 +3957,69 @@ parse_parameter_usage (const char *fname,
}
/* Parse the revocation key specified by NAME, check that the public
* key exists (so that we can get the required public key algorithm),
* and return a parameter wit the revocation key information. On
* error print a diagnostic and return NULL. */
static struct para_data_s *
prepare_desig_revoker (ctrl_t ctrl, const char *name)
{
gpg_error_t err;
struct para_data_s *para = NULL;
KEYDB_SEARCH_DESC desc;
int sensitive = 0;
struct revocation_key revkey;
PKT_public_key *revoker_pk = NULL;
size_t fprlen;
if (!ascii_strncasecmp (name, "sensitive:", 10) && !spacep (name+10))
{
name += 10;
sensitive = 1;
}
if (classify_user_id (name, &desc, 1)
|| desc.mode != KEYDB_SEARCH_MODE_FPR)
{
log_info (_("\"%s\" is not a fingerprint\n"), name);
err = gpg_error (GPG_ERR_INV_NAME);
goto leave;
}
revoker_pk = xcalloc (1, sizeof *revoker_pk);
revoker_pk->req_usage = PUBKEY_USAGE_CERT;
err = get_pubkey_byname (ctrl, GET_PUBKEY_NO_AKL,
NULL, revoker_pk, name, NULL, NULL, 1);
if (err)
goto leave;
fingerprint_from_pk (revoker_pk, revkey.fpr, &fprlen);
if (fprlen != 20 && fprlen != 32)
{
log_info (_("cannot appoint a PGP 2.x style key as a "
"designated revoker\n"));
err = gpg_error (GPG_ERR_UNUSABLE_PUBKEY);
goto leave;
}
revkey.fprlen = fprlen;
revkey.class = 0x80;
if (sensitive)
revkey.class |= 0x40;
revkey.algid = revoker_pk->pubkey_algo;
para = xcalloc (1, sizeof *para);
para->key = pREVOKER;
memcpy (&para->u.revkey, &revkey, sizeof revkey);
leave:
if (err)
log_error ("invalid revocation key '%s': %s\n", name, gpg_strerror (err));
free_public_key (revoker_pk);
return para;
}
/* Parse a pREVOKER parameter into its dedicated parts. */
static int
parse_revocation_key (const char *fname,
struct para_data_s *para, enum para_name key)
@ -4030,10 +4103,11 @@ get_parameter_uint( struct para_data_s *para, enum para_name key )
}
static struct revocation_key *
get_parameter_revkey( struct para_data_s *para, enum para_name key )
get_parameter_revkey (struct para_data_s *para, enum para_name key,
unsigned int idx)
{
struct para_data_s *r = get_parameter( para, key );
return r? &r->u.revkey : NULL;
struct para_data_s *r = get_parameter_idx (para, key, idx);
return r? &r->u.revkey : NULL;
}
static int
@ -4052,6 +4126,7 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
const char *s1, *s2, *s3;
size_t n;
char *p;
strlist_t sl;
int is_default = 0;
int have_user_id = 0;
int err, algo;
@ -4197,10 +4272,20 @@ proc_parameter_file (ctrl_t ctrl, struct para_data_s *para, const char *fname,
}
}
/* Set revoker, if any. */
/* Set revoker from parameter file, if any. Must be done first so
* that we don't find a parameter set via prepare_desig_revoker. */
if (parse_revocation_key (fname, para, pREVOKER))
return -1;
/* Check and appened revokers from the config file. */
for (sl = opt.desig_revokers; sl; sl = sl->next)
{
r = prepare_desig_revoker (ctrl, sl->d);
if (!r)
return -1;
append_to_parameter (para, r);
}
/* Make KEYCREATIONDATE from Creation-Date. We ignore this if the
* key has been taken from a card and a keycreationtime has already
@ -5330,6 +5415,7 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
const char *key_from_hexgrip = NULL;
int cardkey;
unsigned int keygen_flags;
unsigned int idx;
if (outctrl->dryrun)
{
@ -5464,7 +5550,10 @@ do_generate_keypair (ctrl_t ctrl, struct para_data_s *para,
keyid_copy (pri_psk->main_keyid, pri_psk->keyid);
}
if (!err && (revkey = get_parameter_revkey (para, pREVOKER)))
/* Write all signatures specifying designated revokers. */
for (idx=0;
!err && (revkey = get_parameter_revkey (para, pREVOKER, idx));
idx++)
err = write_direct_sig (ctrl, pub_root, pri_psk,
revkey, signtimestamp, cache_nonce);

View File

@ -1216,7 +1216,8 @@ cmp_signodes (const void *av, const void *bv)
}
/* Helper for list_keyblock_print. */
/* Helper for list_keyblock_print. The caller must have set
* NODFLG_MARK_B to indicate self-signatures. */
static void
list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
struct keylist_context *listctx)
@ -1247,6 +1248,11 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
case GPG_ERR_UNUSABLE_PUBKEY:
listctx->no_key++;
return;
case GPG_ERR_DIGEST_ALGO:
case GPG_ERR_PUBKEY_ALGO:
if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS))
return;
/* fallthru. */
default:
listctx->oth_err++;
sigrc = '%';
@ -1259,6 +1265,15 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
}
else
{
if (!(opt.list_options & LIST_SHOW_UNUSABLE_SIGS)
&& (gpg_err_code (openpgp_pk_test_algo (sig->pubkey_algo)
== GPG_ERR_PUBKEY_ALGO)
|| gpg_err_code (openpgp_md_test_algo (sig->digest_algo)
== GPG_ERR_DIGEST_ALGO)
|| (sig->digest_algo == DIGEST_ALGO_SHA1
&& !(node->flag & NODFLG_MARK_B) /*no selfsig*/
&& !opt.flags.allow_weak_key_signatures)))
return;
rc = 0;
sigrc = ' ';
}
@ -1306,7 +1321,9 @@ list_signature_print (ctrl_t ctrl, kbnode_t keyblock, kbnode_t node,
es_fprintf (es_stdout, "[%s] ", gpg_strerror (rc));
else if (sigrc == '?')
;
else if (!opt.fast_list_mode)
else if ((node->flag & NODFLG_MARK_B))
es_fputs (_("[self-signature]"), es_stdout);
else if (!opt.fast_list_mode )
{
size_t n;
char *p = get_user_id (ctrl, sig->keyid, &n, NULL);
@ -1585,37 +1602,33 @@ list_keyblock_print (ctrl_t ctrl, kbnode_t keyblock, int secret, int fpr,
else if (opt.list_sigs
&& node->pkt->pkttype == PKT_SIGNATURE && !skip_sigs)
{
if ((opt.list_options & LIST_SORT_SIGS))
kbnode_t n;
unsigned int sigcount = 0;
kbnode_t *sigarray;
unsigned int idx;
for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
sigcount++;
sigarray = xcalloc (sigcount, sizeof *sigarray);
sigcount = 0;
for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
{
kbnode_t n;
unsigned int sigcount = 0;
kbnode_t *sigarray;
unsigned int idx;
if (keyid_eq (mainkid, n->pkt->pkt.signature->keyid))
n->flag |= NODFLG_MARK_B; /* Is a self-sig. */
else
n->flag &= ~NODFLG_MARK_B;
for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
sigcount++;
sigarray = xcalloc (sigcount, sizeof *sigarray);
sigcount = 0;
for (n=node; n && n->pkt->pkttype == PKT_SIGNATURE; n = n->next)
{
if (!keyid_cmp (mainkid, n->pkt->pkt.signature->keyid))
n->flag |= NODFLG_MARK_B; /* Is a self-sig. */
else
n->flag &= ~NODFLG_MARK_B;
sigarray[sigcount++] = node = n;
}
/* Note that NODE is now at the last signature. */
qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
for (idx=0; idx < sigcount; idx++)
list_signature_print (ctrl, keyblock, sigarray[idx], listctx);
xfree (sigarray);
sigarray[sigcount++] = node = n;
}
else
list_signature_print (ctrl, keyblock, node, listctx);
/* Note that NODE is now at the last signature. */
if ((opt.list_options & LIST_SORT_SIGS))
qsort (sigarray, sigcount, sizeof *sigarray, cmp_signodes);
for (idx=0; idx < sigcount; idx++)
list_signature_print (ctrl, keyblock, sigarray[idx], listctx);
xfree (sigarray);
}
}
es_putc ('\n', es_stdout);

View File

@ -42,7 +42,7 @@
#endif
#define DEFAULT_DIGEST_ALGO ((GNUPG)? DIGEST_ALGO_SHA256:DIGEST_ALGO_SHA1)
#define DEFAULT_S2K_DIGEST_ALGO DIGEST_ALGO_SHA1
#define DEFAULT_S2K_DIGEST_ALGO DEFAULT_DIGEST_ALGO
#ifdef HAVE_ZIP
# define DEFAULT_COMPRESS_ALGO COMPRESS_ALGO_ZIP
#else
@ -83,6 +83,7 @@ struct weakhash
/*-- gpg.c --*/
extern int g10_errors_seen;
extern int assert_signer_true;
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5 )
void g10_exit(int rc) __attribute__ ((__noreturn__));
@ -235,7 +236,7 @@ int cpr_get_answer_okay_cancel (const char *keyword,
/*-- helptext.c --*/
void display_online_help( const char *keyword );
/*-- encode.c --*/
/*-- encrypt.c --*/
gpg_error_t setup_symkey (STRING2KEY **symkey_s2k,DEK **symkey_dek);
aead_algo_t use_aead (pk_list_t pk_list, int algo);
int use_mdc (pk_list_t pk_list,int algo);
@ -315,6 +316,7 @@ int keygen_set_std_prefs (const char *string,int personal);
PKT_user_id *keygen_get_std_prefs (void);
int keygen_add_key_expire( PKT_signature *sig, void *opaque );
int keygen_add_key_flags (PKT_signature *sig, void *opaque);
int keygen_add_key_flags_and_expire (PKT_signature *sig, void *opaque);
int keygen_add_std_prefs( PKT_signature *sig, void *opaque );
int keygen_upd_std_prefs( PKT_signature *sig, void *opaque );
int keygen_add_keyserver_url(PKT_signature *sig, void *opaque);
@ -491,6 +493,7 @@ void print_file_status( int status, const char *name, int what );
int verify_signatures (ctrl_t ctrl, int nfiles, char **files );
int verify_files (ctrl_t ctrl, int nfiles, char **files );
int gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp);
void check_assert_signer_list (const char *mainpkhex, const char *pkhex);
/*-- decrypt.c --*/
int decrypt_message (ctrl_t ctrl, const char *filename );
@ -515,7 +518,7 @@ void change_pin (int no, int allow_admin);
void card_status (ctrl_t ctrl, estream_t fp, const char *serialno);
void card_edit (ctrl_t ctrl, strlist_t commands);
gpg_error_t card_generate_subkey (ctrl_t ctrl, kbnode_t pub_keyblock);
int card_store_subkey (KBNODE node, int use);
int card_store_subkey (KBNODE node, int use, strlist_t *processed_keys);
#endif
/*-- migrate.c --*/

View File

@ -2410,7 +2410,7 @@ check_sig_and_print (CTX c, kbnode_t node)
}
/* For good signatures print the VALIDSIG status line. */
if (!rc && is_status_enabled () && pk)
if (!rc && (is_status_enabled () || opt.assert_signer_list) && pk)
{
char pkhex[MAX_FINGERPRINT_LEN*2+1];
char mainpkhex[MAX_FINGERPRINT_LEN*2+1];
@ -2430,6 +2430,8 @@ check_sig_and_print (CTX c, kbnode_t node)
sig->digest_algo,
sig->sig_class,
mainpkhex);
/* Handle the --assert-signer option. */
check_assert_signer_list (mainpkhex, pkhex);
}
/* Print compliance warning for Good signatures. */
@ -2510,6 +2512,7 @@ check_sig_and_print (CTX c, kbnode_t node)
is not a detached signature. */
log_info (_("WARNING: not a detached signature; "
"file '%s' was NOT verified!\n"), dfile);
assert_signer_true = 0;
}
xfree (dfile);
}

View File

@ -777,21 +777,21 @@ openpgp_pk_algo_usage ( int algo )
switch ( algo ) {
case PUBKEY_ALGO_RSA:
use = (PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_AUTH);
| PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC | PUBKEY_USAGE_AUTH);
break;
case PUBKEY_ALGO_RSA_E:
case PUBKEY_ALGO_ECDH:
use = PUBKEY_USAGE_ENC;
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_RSA_S:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG;
break;
case PUBKEY_ALGO_ELGAMAL:
if (RFC2440)
use = PUBKEY_USAGE_ENC;
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_ELGAMAL_E:
use = PUBKEY_USAGE_ENC;
use = PUBKEY_USAGE_ENC | PUBKEY_USAGE_RENC;
break;
case PUBKEY_ALGO_DSA:
use = PUBKEY_USAGE_CERT | PUBKEY_USAGE_SIG | PUBKEY_USAGE_AUTH;
@ -1563,9 +1563,10 @@ parse_options(char *str,unsigned int *options,
{
char *tok;
if (str && !strcmp (str, "help"))
if (str && (!strcmp (str, "help") || !strcmp (str, "full-help")))
{
int i,maxlen=0;
int full = *str == 'f';
/* Figure out the longest option name so we can line these up
neatly. */
@ -1577,6 +1578,10 @@ parse_options(char *str,unsigned int *options,
if(opts[i].help)
es_printf("%s%*s%s\n",opts[i].name,
maxlen+2-(int)strlen(opts[i].name),"",_(opts[i].help));
if (full)
for (i=0; opts[i].name; i++)
if(!opts[i].help)
es_printf("%s\n",opts[i].name);
g10_exit(0);
}

View File

@ -111,6 +111,9 @@ struct
* the option --sender. */
strlist_t sender_list;
/* A list of fingerprints added as designated revokers to new keys. */
strlist_t desig_revokers;
int def_cert_level;
int min_cert_level;
int ask_cert_level;
@ -232,6 +235,10 @@ struct
value. */
int limit_card_insert_tries;
/* The list of --assert-signer option values. Note: The values are
* modify to be uppercase if they represent a fingerrint */
strlist_t assert_signer_list;
struct
{
/* If set, require an 0x19 backsig to be present on signatures
@ -426,6 +433,7 @@ EXTERN_UNLESS_MAIN_MODULE int memory_stat_debug_mode;
#define LIST_SORT_SIGS (1<<13)
#define LIST_SHOW_PREF (1<<14)
#define LIST_SHOW_PREF_VERBOSE (1<<15)
#define LIST_SHOW_UNUSABLE_SIGS (1<<16)
#define VERIFY_SHOW_PHOTOS (1<<0)
#define VERIFY_SHOW_POLICY_URLS (1<<1)

View File

@ -56,9 +56,15 @@
| GCRY_PK_USAGE_AUTH | GCRY_PK_USAGE_UNKN) >= 256
# error Please choose another value for PUBKEY_USAGE_NONE
#endif
#define PUBKEY_USAGE_RENC 512 /* Restricted encryption. */
#define PUBKEY_USAGE_TIME 1024 /* Timestamp use. */
#define PUBKEY_USAGE_GROUP 512 /* Group flag. */
#define PUBKEY_USAGE_RENC 1024 /* Restricted encryption. */
#define PUBKEY_USAGE_TIME 2048 /* Timestamp use. */
/* Bitflags to convey hints on what kind of signature is created. */
#define SIGNHINT_KEYSIG 1
#define SIGNHINT_SELFSIG 2
#define SIGNHINT_ADSK 4
/* Helper macros. */
#define is_RSA(a) ((a)==PUBKEY_ALGO_RSA || (a)==PUBKEY_ALGO_RSA_E \
@ -287,7 +293,7 @@ typedef struct
/* The length of ATTRIB_DATA. */
unsigned long attrib_len;
byte *namehash;
int help_key_usage;
u16 help_key_usage;
u32 help_key_expire;
int help_full_count;
int help_marginal_count;
@ -388,7 +394,7 @@ typedef struct
byte selfsigversion; /* highest version of all of the self-sigs */
/* The public key algorithm. (Serialized.) */
byte pubkey_algo;
byte pubkey_usage; /* for now only used to pass it to getkey() */
u16 pubkey_usage; /* carries the usage info. */
byte req_usage; /* hack to pass a request to getkey() */
byte fprlen; /* 0 or length of FPR. */
u32 has_expired; /* set to the expiration date if expired */
@ -861,7 +867,8 @@ gpg_error_t gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a);
u32 calc_packet_length( PACKET *pkt );
void build_sig_subpkt( PKT_signature *sig, sigsubpkttype_t type,
const byte *buffer, size_t buflen );
void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk);
void build_sig_subpkt_from_sig (PKT_signature *sig, PKT_public_key *pksk,
unsigned int signhints);
int delete_sig_subpkt(subpktarea_t *buffer, sigsubpkttype_t type );
void build_attribute_subpkt(PKT_user_id *uid,byte type,
const void *buf,u32 buflen,
@ -883,6 +890,7 @@ void free_user_id( PKT_user_id *uid );
void free_comment( PKT_comment *rem );
void free_packet (PACKET *pkt, parse_packet_ctx_t parsectx);
prefitem_t *copy_prefs (const prefitem_t *prefs);
PKT_public_key *copy_public_key_basics (PKT_public_key *d, PKT_public_key *s);
PKT_public_key *copy_public_key( PKT_public_key *d, PKT_public_key *s );
PKT_signature *copy_signature( PKT_signature *d, PKT_signature *s );
PKT_user_id *scopy_user_id (PKT_user_id *sd );

View File

@ -845,7 +845,8 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
{
int rc;
PKT_public_key *pk;
KBNODE keyblock = NULL;
kbnode_t keyblock = NULL;
kbnode_t node;
if (!name || !*name)
return gpg_error (GPG_ERR_INV_USER_ID);
@ -856,7 +857,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
pk->req_usage = use;
if (from_file)
rc = get_pubkey_fromfile (ctrl, pk, name);
rc = get_pubkey_fromfile (ctrl, pk, name, &keyblock);
else
rc = get_best_pubkey_byname (ctrl, GET_PUBKEY_NORMAL,
NULL, pk, name, &keyblock, 0);
@ -895,10 +896,10 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
int trustlevel;
trustlevel = get_validity (ctrl, keyblock, pk, pk->user_id, NULL, 1);
release_kbnode (keyblock);
if ( (trustlevel & TRUST_FLAG_DISABLED) )
{
/* Key has been disabled. */
release_kbnode (keyblock);
send_status_inv_recp (13, name);
log_info (_("%s: skipped: public key is disabled\n"), name);
free_public_key (pk);
@ -908,6 +909,7 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
if ( !do_we_trust_pre (ctrl, pk, trustlevel) )
{
/* We don't trust this key. */
release_kbnode (keyblock);
send_status_inv_recp (10, name);
free_public_key (pk);
return GPG_ERR_UNUSABLE_PUBKEY;
@ -926,19 +928,33 @@ find_and_check_key (ctrl_t ctrl, const char *name, unsigned int use,
{
pk_list_t r;
r = xtrymalloc (sizeof *r);
if (!r)
{
rc = gpg_error_from_syserror ();
free_public_key (pk);
return rc;
}
r = xmalloc (sizeof *r);
r->pk = pk;
r->next = *pk_list_addr;
r->flags = mark_hidden? 1:0;
*pk_list_addr = r;
}
for (node = keyblock; node; node = node->next)
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
&& ((pk=node->pkt->pkt.public_key)->pubkey_usage & PUBKEY_USAGE_RENC)
&& pk->flags.valid
&& !pk->flags.revoked
&& !pk->flags.disabled
&& !pk->has_expired
&& key_present_in_pk_list (*pk_list_addr, pk))
{
pk_list_t r;
r = xmalloc (sizeof *r);
r->pk = copy_public_key (NULL, pk);
r->next = *pk_list_addr;
r->flags = mark_hidden? 1:0; /* FIXME: Use PK_LIST_HIDDEN ? */
*pk_list_addr = r;
}
release_kbnode (keyblock);
return 0;
}

View File

@ -363,7 +363,8 @@ check_signature_metadata_validity (PKT_public_key *pk, PKT_signature *sig,
if (r_revoked)
*r_revoked = 0;
if (pk->timestamp > sig->timestamp )
if (pk->timestamp > sig->timestamp
&& !(parse_key_usage (sig) & PUBKEY_USAGE_RENC))
{
ulong d = pk->timestamp - sig->timestamp;
if ( d < 86400 )

View File

@ -50,11 +50,6 @@
#endif
/* Bitflags to convey hints on what kind of signayire is created. */
#define SIGNHINT_KEYSIG 1
#define SIGNHINT_SELFSIG 2
/* Hack */
static int recipient_digest_algo;
@ -416,7 +411,10 @@ do_sign (ctrl_t ctrl, PKT_public_key *pksk, PKT_signature *sig,
byte *dp;
char *hexgrip;
if (pksk->timestamp > sig->timestamp )
/* An ADSK key commonly has a creation date older than the primary
* key. For example because the ADSK is used as an archive key for
* a group of users. */
if (pksk->timestamp > sig->timestamp && !(signhints & SIGNHINT_ADSK))
{
ulong d = pksk->timestamp - sig->timestamp;
log_info (ngettext("key %s was created %lu second"
@ -964,7 +962,7 @@ write_signature_packets (ctrl_t ctrl,
if (gcry_md_copy (&md, hash))
BUG ();
build_sig_subpkt_from_sig (sig, pk);
build_sig_subpkt_from_sig (sig, pk, 0);
mk_notation_policy_etc (ctrl, sig, NULL, pk);
if (opt.flags.include_key_block && IS_SIG (sig))
err = mk_sig_subpkt_key_block (ctrl, sig, pk);
@ -1758,14 +1756,14 @@ sign_symencrypt_file (ctrl_t ctrl, const char *fname, strlist_t locusr)
*
* SIGCLASS is the type of signature to create.
*
* DIGEST_ALGO is the digest algorithm. If it is 0 the function
* selects an appropriate one.
*
* TIMESTAMP is the timestamp to use for the signature. 0 means "now"
*
* DURATION is the amount of time (in seconds) until the signature
* expires.
*
* If CACHED_NONCE is not NULL the agent may use it to avoid
* additional pinnetry popups for the same keyblock.
*
* This function creates the following subpackets: issuer, created,
* and expire (if duration is not 0). Additional subpackets can be
* added using MKSUBPKT, which is called after these subpackets are
@ -1833,6 +1831,8 @@ make_keysig_packet (ctrl_t ctrl,
{
/* Hash the subkey binding/backsig/revocation. */
hash_public_key (md, subpk);
if ((subpk->pubkey_usage & PUBKEY_USAGE_RENC))
signhints |= SIGNHINT_ADSK;
}
else if (sigclass != 0x1F && sigclass != 0x20)
{
@ -1852,7 +1852,7 @@ make_keysig_packet (ctrl_t ctrl,
sig->expiredate = sig->timestamp + duration;
sig->sig_class = sigclass;
build_sig_subpkt_from_sig (sig, pksk);
build_sig_subpkt_from_sig (sig, pksk, signhints);
mk_notation_policy_etc (ctrl, sig, pk, pksk);
/* Crucial that the call to mksubpkt comes LAST before the calls
@ -1976,6 +1976,12 @@ update_keysig_packet (ctrl_t ctrl,
}
}
/* Detect an ADSK key binding signature. */
if ((sig->sig_class == 0x18
|| sig->sig_class == 0x19 || sig->sig_class == 0x28)
&& (pk->pubkey_usage & PUBKEY_USAGE_RENC))
signhints |= SIGNHINT_ADSK;
/* Note that already expired sigs will remain expired (with a
* duration of 1) since build-packet.c:build_sig_subpkt_from_sig
* detects this case. */
@ -1984,7 +1990,7 @@ update_keysig_packet (ctrl_t ctrl,
* automagically lower any sig expiration dates to correctly
* correspond to the differences in the timestamps (i.e. the
* duration will shrink). */
build_sig_subpkt_from_sig (sig, pksk);
build_sig_subpkt_from_sig (sig, pksk, signhints);
if (mksubpkt)
rc = (*mksubpkt)(sig, opaque);

View File

@ -67,3 +67,12 @@ do_test (int argc, char *argv[])
release_kbnode (kb1);
xfree (ctrl);
}
int assert_signer_true = 0;
void
check_assert_signer_list (const char *mainpkhex, const char *pkhex)
{
(void)mainpkhex;
(void)pkhex;
}

View File

@ -105,3 +105,13 @@ do_test (int argc, char *argv[])
keydb_release (hd2);
xfree (ctrl);
}
int assert_signer_true = 0;
void
check_assert_signer_list (const char *mainpkhex, const char *pkhex)
{
(void)mainpkhex;
(void)pkhex;
}

View File

@ -611,3 +611,12 @@ do_test (int argc, char *argv[])
xfree (filename);
}
int assert_signer_true = 0;
void
check_assert_signer_list (const char *mainpkhex, const char *pkhex)
{
(void)mainpkhex;
(void)pkhex;
}

View File

@ -59,7 +59,7 @@ register_trusted_key (const char *string)
/* Some users have conf files with entries like
* trusted-key 0x1234567812345678 # foo
* That is obviously wrong. Before fixing bug#1206 trailing garbage
* on a key specification if was ignored. We detect the above use case
* on a key specification was ignored. We detect the above use case
* here and cut off the junk-looking-like-a comment. */
if (strchr (string, '#'))
{

View File

@ -1,6 +1,8 @@
/* verify.c - Verify signed data
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2006,
* 2007, 2010 Free Software Foundation, Inc.
* Copyright (C) 2003, 2006-2008, 2010-2011, 2015-2017,
* 2020, 2023 g10 Code GmbH
*
* This file is part of GnuPG.
*
@ -16,6 +18,7 @@
*
* 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>
@ -281,3 +284,124 @@ gpg_verify (ctrl_t ctrl, int sig_fd, int data_fd, estream_t out_fp)
release_armor_context (afx);
return rc;
}
static int
is_fingerprint (const char *string)
{
int n;
if (!string || !*string)
return 0;
for (n=0; hexdigitp (string); string++)
n++;
if (!*string && (n == 40 || n == 64))
return 1; /* v4 or v5 fingerprint. */
return 0;
}
/* This function shall be called with the main and subkey fingerprint
* iff a signature is fully valid. If the option --assert-signer is
* active it check whether the signing key matches one of the keys
* given by this option and if so, sets a global flag. */
void
check_assert_signer_list (const char *mainpkhex, const char *pkhex)
{
gpg_error_t err;
strlist_t item;
const char *fname;
estream_t fp = NULL;
int lnr;
int n, c;
char *p, *pend;
char line[256];
if (!opt.assert_signer_list)
return; /* Nothing to do. */
if (assert_signer_true)
return; /* Already one valid signature seen. */
for (item = opt.assert_signer_list; item; item = item->next)
{
if (is_fingerprint (item->d))
{
ascii_strupr (item->d);
if (!strcmp (item->d, mainpkhex) || !strcmp (item->d, pkhex))
{
assert_signer_true = 1;
write_status_text (STATUS_ASSERT_SIGNER, item->d);
if (!opt.quiet)
log_info ("signer '%s' matched\n", item->d);
goto leave;
}
}
else /* Assume this is a file - read and compare. */
{
fname = item->d;
es_fclose (fp);
fp = es_fopen (fname, "r");
if (!fp)
{
err = gpg_error_from_syserror ();
log_error (_("error opening '%s': %s\n"),
fname, gpg_strerror (err));
continue;
}
lnr = 0;
err = 0;
while (es_fgets (line, DIM(line)-1, fp))
{
lnr++;
n = strlen (line);
if (!n || line[n-1] != '\n')
{
/* Eat until end of line. */
while ( (c=es_getc (fp)) != EOF && c != '\n')
;
err = gpg_error (GPG_ERR_INCOMPLETE_LINE);
log_error (_("file '%s', line %d: %s\n"),
fname, lnr, gpg_strerror (err));
continue;
}
line[--n] = 0; /* Chop the LF. */
if (n && line[n-1] == '\r')
line[--n] = 0; /* Chop an optional CR. */
/* Allow for empty lines and spaces */
for (p=line; spacep (p); p++)
;
if (!*p || *p == '#')
continue;
/* Get the first token and ignore trailing stuff. */
for (pend = p; *pend && !spacep (pend); pend++)
;
*pend = 0;
ascii_strupr (p);
if (!strcmp (p, mainpkhex) || !strcmp (p, pkhex))
{
assert_signer_true = 1;
write_status_text (STATUS_ASSERT_SIGNER, p);
if (!opt.quiet)
log_info ("signer '%s' matched '%s', line %d\n",
p, fname, lnr);
goto leave;
}
}
if (!err && !es_feof (fp))
{
err = gpg_error_from_syserror ();
log_error (_("error reading '%s', line %d: %s\n"),
fname, lnr, gpg_strerror (err));
}
}
}
leave:
es_fclose (fp);
}

View File

@ -207,6 +207,7 @@ be_is_x509_blob (const unsigned char *blob, size_t bloblen)
* SEQUENCE SEQUENCE [0] INTEGER INTEGER
* (tbs) (version) (s/n)
*
* Note that v0 certificates don't have an explict version number.
*/
p = blob;
@ -226,7 +227,11 @@ be_is_x509_blob (const unsigned char *blob, size_t bloblen)
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
return 0; /* Not a proper BER object. */
if (!(class == CLASS_CONTEXT && tag == 0 && cons))
return 0; /* No context tag. */
{
if (class == CLASS_UNIVERSAL && tag == TAG_INTEGER && !cons)
return 1; /* Might be a X.509 v0 cert with implict version. */
return 0; /* No context tag. */
}
if (parse_ber_header (&p, &n, &class, &tag, &cons, &ndef, &objlen, &hdrlen))
return 0; /* Not a proper BER object. */

View File

@ -1,5 +1,5 @@
# gpg-error.m4 - autoconf macro to detect libgpg-error.
# Copyright (C) 2002, 2003, 2004, 2011, 2014, 2018, 2020, 2021
# Copyright (C) 2002, 2003, 2004, 2011, 2014, 2018, 2020, 2021, 2022
# g10 Code GmbH
#
# This file is free software; as a special exception the author gives
@ -10,23 +10,13 @@
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Last-changed: 2022-09-21
# Last-changed: 2023-04-01
dnl AM_PATH_GPG_ERROR([MINIMUM-VERSION,
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
dnl
dnl Test for libgpg-error and define GPG_ERROR_CFLAGS, GPG_ERROR_LIBS,
dnl GPG_ERROR_MT_CFLAGS, and GPG_ERROR_MT_LIBS. The _MT_ variants are
dnl used for programs requireing real multi thread support.
dnl Find gpg-error-config, for backward compatibility
dnl
dnl If a prefix option is not used, the config script is first
dnl searched in $SYSROOT/bin and then along $PATH. If the used
dnl config script does not match the host specification the script
dnl is added to the gpg_config_script_warn variable.
dnl
AC_DEFUN([AM_PATH_GPG_ERROR],
[ AC_REQUIRE([AC_CANONICAL_HOST])
dnl _AM_PATH_POSSIBLE_GPG_ERROR_CONFIG
AC_DEFUN([_AM_PATH_POSSIBLE_GPG_ERROR_CONFIG],[dnl
gpg_error_config_prefix=""
dnl --with-libgpg-error-prefix=PFX is the preferred name for this option,
dnl since that is consistent with how our three siblings use the directory/
@ -62,9 +52,14 @@ AC_DEFUN([AM_PATH_GPG_ERROR],
fi
AC_PATH_PROG(GPG_ERROR_CONFIG, gpg-error-config, no)
min_gpg_error_version=ifelse([$1], ,1.33,$1)
ok=no
])
dnl
dnl Find gpgrt-config, which uses .pc file
dnl (minimum pkg-config functionality, supporting cross build)
dnl
dnl _AM_PATH_GPGRT_CONFIG
AC_DEFUN([_AM_PATH_GPGRT_CONFIG],[dnl
AC_PATH_PROG(GPGRT_CONFIG, gpgrt-config, no, [$prefix/bin:$PATH])
if test "$GPGRT_CONFIG" != "no"; then
# Determine gpgrt_libdir
@ -120,12 +115,9 @@ AC_DEFUN([AM_PATH_GPG_ERROR],
fi
if test -n "$gpgrt_libdir"; then break; fi
done
if test -z "$libdir_candidates"; then
# No valid pkgconfig dir in any of the system directories, fallback
gpgrt_libdir=${possible_libdir1}
fi
else
# When we cannot determine system libdir-format, use this:
fi
if test -z "$gpgrt_libdir"; then
# No valid pkgconfig dir in any of the system directories, fallback
gpgrt_libdir=${possible_libdir1}
fi
else
@ -139,12 +131,33 @@ AC_DEFUN([AM_PATH_GPG_ERROR],
AC_MSG_NOTICE([Use gpgrt-config with $gpgrt_libdir as gpg-error-config])
gpg_error_config_version=`$GPG_ERROR_CONFIG --modversion`
else
gpg_error_config_version=`$GPG_ERROR_CONFIG --version`
unset GPGRT_CONFIG
fi
elif test "$GPG_ERROR_CONFIG" != "no"; then
gpg_error_config_version=`$GPG_ERROR_CONFIG --version`
unset GPGRT_CONFIG
fi
])
dnl AM_PATH_GPG_ERROR([MINIMUM-VERSION,
dnl [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND ]]])
dnl
dnl Test for libgpg-error and define GPG_ERROR_CFLAGS, GPG_ERROR_LIBS,
dnl GPG_ERROR_MT_CFLAGS, and GPG_ERROR_MT_LIBS. The _MT_ variants are
dnl used for programs requireing real multi thread support.
dnl
dnl If a prefix option is not used, the config script is first
dnl searched in $SYSROOT/bin and then along $PATH. If the used
dnl config script does not match the host specification the script
dnl is added to the gpg_config_script_warn variable.
dnl
AC_DEFUN([AM_PATH_GPG_ERROR],[dnl
AC_REQUIRE([AC_CANONICAL_HOST])dnl
AC_REQUIRE([_AM_PATH_POSSIBLE_GPG_ERROR_CONFIG])dnl
AC_REQUIRE([_AM_PATH_GPGRT_CONFIG])dnl
min_gpg_error_version=ifelse([$1], ,1.33,$1)
ok=no
if test "$GPG_ERROR_CONFIG" != "no"; then
req_major=`echo $min_gpg_error_version | \
sed 's/\([[0-9]]*\)\.\([[0-9]]*\)/\1/'`

View File

@ -9,7 +9,7 @@ msgid ""
msgstr ""
"Project-Id-Version: gnupg-2.3.0\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2022-12-16 16:11+0100\n"
"PO-Revision-Date: 2023-03-21 09:31+0100\n"
"Last-Translator: Werner Koch <wk@gnupg.org>\n"
"Language-Team: German <de@li.org>\n"
"Language: de\n"
@ -332,7 +332,7 @@ msgid "Please enter the passphrase to%0Aprotect your new key"
msgstr "Bitte geben Sie das Passwort ein,%0Aum Ihren Schlüssel zu schützen."
msgid "Please enter the new passphrase"
msgstr "Bitte geben Sie das Passwort ein:"
msgstr "Bitte geben Sie das neue Passwort ein:"
msgid "Options used for startup"
msgstr "Optionen zum Start des Programms"
@ -404,19 +404,19 @@ msgid "Options controlling the security"
msgstr "Optionen zur Einstellung der Sicherheit"
msgid "|N|expire cached PINs after N seconds"
msgstr "|N|Lasse PINs im Cache nach N Sekunden verfallen"
msgstr "|N|Lösche unbenutzte Passwörter nach N Sekunden aus dem Cache"
msgid "|N|expire SSH keys after N seconds"
msgstr "|N|Lasse SSH Schlüssel im Cache nach N Sekunden verfallen"
msgstr "|N|Lösche unbenutzte SSH Passwörter nach N Sekunden aus dem Cache"
msgid "|N|set maximum PIN cache lifetime to N seconds"
msgstr "|N|Setze die maximale Lebensdauer von PINs im Cache auf N Sekunden"
msgstr "|N|Lösche Passwörter nach N Sekunden aus dem Cache"
msgid "|N|set maximum SSH key lifetime to N seconds"
msgstr "|N|Setze die maximale Lebenszeit von SSH Schlüsseln auf N Sekunden"
msgstr "|N|Lösche SSH Passwörter nach N Sekunden aus dem Cache"
msgid "do not use the PIN cache when signing"
msgstr "Benutze PINs im Cache nicht beim Signieren"
msgstr "Benutze den Passwort Cache nicht beim Signieren"
msgid "disallow the use of an external password cache"
msgstr "Verbiete die Verwendung eines externen Passwordmanagers"
@ -6715,7 +6715,7 @@ msgstr "Lesen des öffentlichen Schlüssels fehlgeschlagen: %s\n"
#. * the %s at the start and end of the string.
#, c-format
msgid "%sNumber: %s%%0AHolder: %s%%0ACounter: %lu%s"
msgstr "%sNummer: %s%%0ABesitzer: %s%%0AAnzahl: %lu%s"
msgstr "%sNummer: %s%%0ABesitzer: %s%%0AZähler: %lu%s"
#, c-format
msgid "using default PIN as %s\n"

View File

@ -9,9 +9,9 @@
#
msgid ""
msgstr ""
"Project-Id-Version: gnupg 2.3.8\n"
"Project-Id-Version: gnupg 2.4.0\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
"PO-Revision-Date: 2022-09-01 14:45+0900\n"
"PO-Revision-Date: 2023-01-26 15:24+0900\n"
"Last-Translator: NIIBE Yutaka <gniibe@fsij.org>\n"
"Language-Team: none\n"
"Language: ja\n"
@ -378,18 +378,16 @@ msgid "ignore requests to change the X display"
msgstr "Xディスプレイの変更要求を無視する"
msgid "enable ssh support"
msgstr "sshサポートを有にする"
msgstr "sshサポートを有にする"
msgid "|ALGO|use ALGO to show ssh fingerprints"
msgstr "|ALGO|ssh署名の表示にALGOを使う"
msgid "enable putty support"
msgstr "puttyサポートを有にする"
msgstr "puttyサポートを有にする"
#, fuzzy
#| msgid "enable putty support"
msgid "enable Win32-OpenSSH support"
msgstr "puttyサポートを有功にする"
msgstr "Win32-OpenSSH サポートを有効する"
msgid "Options controlling the security"
msgstr "セキュリティを制御するオプション"
@ -1768,10 +1766,9 @@ msgstr "*警告*: 鍵%sは、%sモードでは、暗号化に適しません\n"
msgid "error creating passphrase: %s\n"
msgstr "パスフレーズの作成エラー: %s\n"
#, fuzzy, c-format
#| msgid "can't use a symmetric ESK packet due to the S2K mode\n"
#, c-format
msgid "can't use a SKESK packet due to the S2K mode\n"
msgstr "S2Kモードのため、共通鍵ESKパケットを使えません\n"
msgstr "S2Kモードのため、SKESKパケットを使えません\n"
#, c-format
msgid "using cipher %s.%s\n"
@ -1840,18 +1837,14 @@ msgstr "エクスポートの際、利用できない部分を除去する"
msgid "remove as much as possible from key during export"
msgstr "エクスポートの際、できるだけ除去する"
#, fuzzy
#| msgid "generate a revocation certificate"
msgid "export only revocation certificates"
msgstr "失効証明書を生成"
msgstr "失効証明書だけをエクスポートする"
msgid "use the GnuPG key backup format"
msgstr "GnuPGの鍵のバックアップフォーマットを使います"
#, fuzzy
#| msgid "exporting secret keys not allowed\n"
msgid "export secret keys using the GnuPG format"
msgstr "秘密鍵のエクスポートは認められません\n"
msgstr "GnuPG フォーマットで秘密鍵をエクスポートをする"
msgid " - skipped"
msgstr " - スキップされました"
@ -2283,10 +2276,8 @@ msgstr "鍵の一覧に鍵リングの名前を表示する"
msgid "show expiration dates during signature listings"
msgstr "署名の一覧時に有効期限の日付を表示する"
#, fuzzy
#| msgid "list preferences (expert)"
msgid "show preferences"
msgstr "優先指定の一覧 (エキスパート)"
msgstr "優先指定の表示"
#, c-format
msgid "unknown TOFU policy '%s'\n"

View File

@ -1863,7 +1863,7 @@ read_public_key (app_t app, ctrl_t ctrl, u32 created_at, int keyno,
len = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
keybuf = xtrymalloc (len);
if (!data)
if (!keybuf)
{
err = gpg_error_from_syserror ();
gcry_sexp_release (s_pkey);
@ -4824,6 +4824,7 @@ do_writekey (app_t app, ctrl_t ctrl,
const unsigned char *buf, *tok;
size_t buflen, toklen;
int depth;
char *algostr = NULL;
(void)ctrl;
@ -4866,17 +4867,41 @@ do_writekey (app_t app, ctrl_t ctrl,
goto leave;
if ((err = parse_sexp (&buf, &buflen, &depth, &tok, &toklen)))
goto leave;
if (tok && toklen == 3 && memcmp ("rsa", tok, toklen) == 0)
err = rsa_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth);
else if (tok && toklen == 3 && memcmp ("ecc", tok, toklen) == 0)
err = ecc_writekey (app, ctrl, pincb, pincb_arg, keyno, buf, buflen, depth);
if (tok && toklen == 3 && (!memcmp ("rsa", tok, toklen)
|| !memcmp ("ecc", tok, toklen)))
{
gcry_sexp_t stmp;
if (!gcry_sexp_new (&stmp, keydata, keydatalen, 0))
algostr = pubkey_algo_string (stmp, NULL);
else
algostr = NULL;
gcry_sexp_release (stmp);
if (app->app_local->keyattr[keyno].keyalgo && algostr
&& strcmp (app->app_local->keyattr[keyno].keyalgo, algostr))
{
log_info ("openpgp: changing key attribute from %s to %s\n",
app->app_local->keyattr[keyno].keyalgo, algostr);
err = change_keyattr_from_string (app, ctrl, pincb, pincb_arg,
keyid, algostr, NULL, 0);
if (err)
return err;
}
if (*tok == 'r')
err = rsa_writekey (app, ctrl, pincb, pincb_arg, keyno,
buf,buflen,depth);
else
err = ecc_writekey (app, ctrl, pincb, pincb_arg, keyno,
buf, buflen, depth);
}
else
{
err = gpg_error (GPG_ERR_WRONG_PUBKEY_ALGO);
goto leave;
}
leave:
xfree (algostr);
return err;
}

View File

@ -326,7 +326,7 @@ struct prkdf_object_s
char *serial_number;
/* KDF/KEK parameter for OpenPGP's ECDH. First byte is zero if not
* available. .*/
* available. */
unsigned char ecdh_kdf[4];
/* Length and allocated buffer with the Id of this object. */

View File

@ -890,6 +890,8 @@ istrusted_status_cb (void *opaque, const char *line)
flags->chain_model = 1;
else if (has_leading_keyword (line, "qual"))
flags->qualified = 1;
else if (has_leading_keyword (line, "de-vs"))
flags->de_vs = 1;
}
return 0;
}

View File

@ -362,7 +362,7 @@ inq_certificate (void *opaque, const char *line)
}
else
{
log_error ("unsupported inquiry '%s'\n", line);
log_error ("unsupported certificate inquiry '%s'\n", line);
return gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
}
@ -386,8 +386,8 @@ inq_certificate (void *opaque, const char *line)
int err;
ksba_cert_t cert;
err = gpgsm_find_cert (parm->ctrl, line, ski, &cert, 1);
err = gpgsm_find_cert (parm->ctrl, line, ski, &cert,
FIND_CERT_ALLOW_AMBIG|FIND_CERT_WITH_EPHEM);
if (err)
{
log_error ("certificate not found: %s\n", gpg_strerror (err));
@ -521,6 +521,7 @@ isvalid_status_cb (void *opaque, const char *line)
GPG_ERR_CERTIFICATE_REVOKED
GPG_ERR_NO_CRL_KNOWN
GPG_ERR_INV_CRL_OBJ
GPG_ERR_CRL_TOO_OLD
Values for USE_OCSP:
@ -1014,7 +1015,8 @@ run_command_inq_cb (void *opaque, const char *line)
if (!*line)
return gpg_error (GPG_ERR_ASS_PARAMETER);
err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert, 1);
err = gpgsm_find_cert (parm->ctrl, line, NULL, &cert,
FIND_CERT_ALLOW_AMBIG);
if (err)
{
log_error ("certificate not found: %s\n", gpg_strerror (err));
@ -1035,9 +1037,33 @@ run_command_inq_cb (void *opaque, const char *line)
line = s;
log_info ("dirmngr: %s\n", line);
}
else if ((s = has_leading_keyword (line, "ISTRUSTED")))
{
/* The server is asking us whether the certificate is a trusted
root certificate. */
char fpr[41];
struct rootca_flags_s rootca_flags;
int n;
line = s;
for (s=line,n=0; hexdigitp (s); s++, n++)
;
if (*s || n != 40)
return gpg_error (GPG_ERR_ASS_PARAMETER);
for (s=line, n=0; n < 40; s++, n++)
fpr[n] = (*s >= 'a')? (*s & 0xdf): *s;
fpr[n] = 0;
if (!gpgsm_agent_istrusted (parm->ctrl, NULL, fpr, &rootca_flags))
rc = assuan_send_data (parm->ctx, "1", 1);
else
rc = 0;
return rc;
}
else
{
log_error ("unsupported inquiry '%s'\n", line);
log_error ("unsupported command inquiry '%s'\n", line);
rc = gpg_error (GPG_ERR_ASS_UNKNOWN_INQUIRE);
}

View File

@ -122,6 +122,7 @@ do_list (int is_error, int listmode, estream_t fp, const char *format, ...)
}
else
{
es_fflush (es_stdout);
log_logv (is_error? GPGRT_LOGLVL_ERROR: GPGRT_LOGLVL_INFO,
format, arg_ptr);
log_printf ("\n");
@ -1480,6 +1481,7 @@ ask_marktrusted (ctrl_t ctrl, ksba_cert_t cert, int listmode)
int success = 0;
fpr = gpgsm_get_fingerprint_string (cert, GCRY_MD_SHA1);
es_fflush (es_stdout);
log_info (_("fingerprint=%s\n"), fpr? fpr : "?");
xfree (fpr);
@ -2277,6 +2279,7 @@ gpgsm_basic_cert_check (ctrl_t ctrl, ksba_cert_t cert)
{
if (!opt.quiet)
{
es_fflush (es_stdout);
log_info ("issuer certificate (#/");
gpgsm_dump_string (issuer);
log_printf (") not found\n");

View File

@ -728,7 +728,14 @@ gpgsm_es_print_name2 (estream_t fp, const char *name, int translate)
void
gpgsm_es_print_name (estream_t fp, const char *name)
{
gpgsm_es_print_name2 (fp, name, 1);
if (opt.no_pretty_dn)
{
if (!name)
name = "[error]";
es_write_sanitized (fp, name, strlen (name), NULL, NULL);
}
else
gpgsm_es_print_name2 (fp, name, 1);
}

View File

@ -508,11 +508,12 @@ gpgsm_release_certlist (certlist_t list)
int
gpgsm_find_cert (ctrl_t ctrl,
const char *name, ksba_sexp_t keyid, ksba_cert_t *r_cert,
int allow_ambiguous)
unsigned int flags)
{
int rc;
KEYDB_SEARCH_DESC desc;
KEYDB_HANDLE kh = NULL;
int allow_ambiguous = (flags & FIND_CERT_ALLOW_AMBIG);
*r_cert = NULL;
rc = classify_user_id (name, &desc, 0);
@ -523,6 +524,9 @@ gpgsm_find_cert (ctrl_t ctrl,
rc = gpg_error (GPG_ERR_ENOMEM);
else
{
if ((flags & FIND_CERT_WITH_EPHEM))
keydb_set_ephemeral (kh, 1);
nextone:
rc = keydb_search (ctrl, kh, &desc, 1);
if (!rc)

View File

@ -37,14 +37,6 @@
#include "../common/tlv.h"
#include "../common/compliance.h"
/* We can provide an enum value which is only availabale with KSBA
* 1.6.0 so that we can compile even against older versions. Some
* calls will of course return an error in this case. This value is
* currently not used because the cipher mode is sufficient here. */
/* #if KSBA_VERSION_NUMBER < 0x010600 /\* 1.6.0 *\/ */
/* # define KSBA_CT_AUTHENVELOPED_DATA 10 */
/* #endif */
struct decrypt_filter_parm_s
{

Some files were not shown because too many files have changed in this diff Show More