mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
Merge branch 'master' into gniibe/t6275
This commit is contained in:
commit
8dcfb5e4d0
28
INSTALL
28
INSTALL
@ -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
28
NEWS
@ -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
10
README
@ -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:
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
269
agent/findkey.c
269
agent/findkey.c
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
136
agent/protect.c
136
agent/protect.c
@ -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;
|
||||
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -53,6 +53,7 @@ enum
|
||||
|
||||
STATUS_NEED_PASSPHRASE,
|
||||
STATUS_VALIDSIG,
|
||||
STATUS_ASSERT_SIGNER,
|
||||
STATUS_SIG_ID,
|
||||
STATUS_ENC_TO,
|
||||
STATUS_NODATA,
|
||||
|
@ -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;
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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. */
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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=*)
|
||||
*
|
||||
|
@ -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
63
dirmngr/fakecrl.c
Normal 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;
|
||||
}
|
@ -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
|
||||
}
|
||||
|
@ -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*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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*/
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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*/
|
||||
|
@ -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)))
|
||||
|
245
dirmngr/server.c
245
dirmngr/server.c
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
70
doc/DETAILS
70
doc/DETAILS
@ -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 |
|
||||
|-----------------+------------------|
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
122
doc/gpg.texi
122
doc/gpg.texi
@ -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
|
||||
|
@ -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 *******************************************
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
25
g10/getkey.c
25
g10/getkey.c
@ -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
|
||||
|
98
g10/gpg.c
98
g10/gpg.c
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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*))
|
||||
|
@ -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;
|
||||
|
@ -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++;
|
||||
|
31
g10/keydb.c
31
g10/keydb.c
@ -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;
|
||||
|
15
g10/keydb.h
15
g10/keydb.h
@ -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. */
|
||||
|
288
g10/keyedit.c
288
g10/keyedit.c
@ -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
|
||||
|
@ -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,
|
||||
|
163
g10/keygen.c
163
g10/keygen.c
@ -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 (¶->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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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 --*/
|
||||
|
@ -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);
|
||||
}
|
||||
|
15
g10/misc.c
15
g10/misc.c
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
|
18
g10/packet.h
18
g10/packet.h
@ -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 );
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 )
|
||||
|
30
g10/sign.c
30
g10/sign.c
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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, '#'))
|
||||
{
|
||||
|
124
g10/verify.c
124
g10/verify.c
@ -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);
|
||||
}
|
||||
|
@ -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. */
|
||||
|
@ -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/'`
|
||||
|
16
po/de.po
16
po/de.po
@ -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"
|
||||
|
29
po/ja.po
29
po/ja.po
@ -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"
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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. */
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user