2006-04-19 13:26:11 +02:00
|
|
|
|
/* import.c - import a key into our key storage.
|
2014-12-04 10:45:53 +01:00
|
|
|
|
* Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc.
|
2019-03-18 13:07:14 +01:00
|
|
|
|
* Copyright (C) 2014, 2016, 2017, 2019 Werner Koch
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*
|
|
|
|
|
* 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
|
2007-07-04 21:49:40 +02:00
|
|
|
|
* the Free Software Foundation; either version 3 of the License, or
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* (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
|
2016-11-05 12:02:19 +01:00
|
|
|
|
* along with this program; if not, see <https://www.gnu.org/licenses/>.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#include "gpg.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#include "options.h"
|
|
|
|
|
#include "packet.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/status.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#include "keydb.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/util.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#include "trustdb.h"
|
|
|
|
|
#include "main.h"
|
2017-03-07 12:21:23 +01:00
|
|
|
|
#include "../common/i18n.h"
|
|
|
|
|
#include "../common/ttyio.h"
|
|
|
|
|
#include "../common/recsel.h"
|
2003-06-05 09:14:21 +02:00
|
|
|
|
#include "keyserver-internal.h"
|
2010-08-31 17:58:39 +02:00
|
|
|
|
#include "call-agent.h"
|
|
|
|
|
#include "../common/membuf.h"
|
2016-07-01 16:24:04 +02:00
|
|
|
|
#include "../common/init.h"
|
|
|
|
|
#include "../common/mbox-util.h"
|
2017-06-13 15:35:01 +02:00
|
|
|
|
#include "key-check.h"
|
2018-07-06 11:40:16 +02:00
|
|
|
|
#include "key-clean.h"
|
2016-07-01 16:24:04 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2015-12-12 18:19:35 +01:00
|
|
|
|
struct import_stats_s
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
ulong count;
|
|
|
|
|
ulong no_user_id;
|
|
|
|
|
ulong imported;
|
|
|
|
|
ulong n_uids;
|
|
|
|
|
ulong n_sigs;
|
|
|
|
|
ulong n_subk;
|
|
|
|
|
ulong unchanged;
|
|
|
|
|
ulong n_revoc;
|
|
|
|
|
ulong secret_read;
|
|
|
|
|
ulong secret_imported;
|
|
|
|
|
ulong secret_dups;
|
|
|
|
|
ulong skipped_new_keys;
|
|
|
|
|
ulong not_imported;
|
|
|
|
|
ulong n_sigs_cleaned;
|
|
|
|
|
ulong n_uids_cleaned;
|
|
|
|
|
ulong v3keys; /* Number of V3 keys seen. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
2016-07-06 10:35:36 +02:00
|
|
|
|
/* Node flag to indicate that a user ID or a subkey has a
|
|
|
|
|
* valid self-signature. */
|
|
|
|
|
#define NODE_GOOD_SELFSIG 1
|
|
|
|
|
/* Node flag to indicate that a user ID or subkey has
|
|
|
|
|
* an invalid self-signature. */
|
|
|
|
|
#define NODE_BAD_SELFSIG 2
|
|
|
|
|
/* Node flag to indicate that the node shall be deleted. */
|
|
|
|
|
#define NODE_DELETION_MARK 4
|
|
|
|
|
/* A node flag used to temporary mark a node. */
|
|
|
|
|
#define NODE_FLAG_A 8
|
2019-03-18 13:07:14 +01:00
|
|
|
|
/* A flag used by transfer_secret_keys. */
|
|
|
|
|
#define NODE_TRANSFER_SECKEY 16
|
2016-07-06 10:35:36 +02:00
|
|
|
|
|
|
|
|
|
|
2017-02-20 22:19:50 +01:00
|
|
|
|
/* An object and a global instance to store selectors created from
|
2016-07-01 16:24:04 +02:00
|
|
|
|
* --import-filter keep-uid=EXPR.
|
2016-08-18 16:15:49 +02:00
|
|
|
|
* --import-filter drop-sig=EXPR.
|
2016-07-01 16:24:04 +02:00
|
|
|
|
*
|
|
|
|
|
* FIXME: We should put this into the CTRL object but that requires a
|
2016-09-28 13:39:09 +02:00
|
|
|
|
* lot more changes right now. For now we use save and restore
|
2016-10-27 14:58:01 +02:00
|
|
|
|
* function to temporary change them.
|
2016-07-01 16:24:04 +02:00
|
|
|
|
*/
|
2016-09-28 13:39:09 +02:00
|
|
|
|
/* Definition of the import filters. */
|
|
|
|
|
struct import_filter_s
|
|
|
|
|
{
|
|
|
|
|
recsel_expr_t keep_uid;
|
|
|
|
|
recsel_expr_t drop_sig;
|
|
|
|
|
};
|
|
|
|
|
/* The current instance. */
|
|
|
|
|
struct import_filter_s import_filter;
|
2016-07-01 16:24:04 +02:00
|
|
|
|
|
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
static int import (ctrl_t ctrl,
|
2015-12-12 18:19:35 +01:00
|
|
|
|
IOBUF inp, const char* fname, struct import_stats_s *stats,
|
2014-08-14 15:20:53 +02:00
|
|
|
|
unsigned char **fpr, size_t *fpr_len, unsigned int options,
|
2017-07-24 20:05:28 +02:00
|
|
|
|
import_screener_t screener, void *screener_arg,
|
|
|
|
|
int origin, const char *url);
|
2019-07-01 14:01:08 +02:00
|
|
|
|
static int read_block (IOBUF a, unsigned int options,
|
gpg: Revamp reading and writing of ring trust packets.
* g10/parse-packet.c (parse_trust): Rename to ...
(parse_ring_trust): this. Change args and implement new ring trust
packet format.
(parse): Add special ring trust packet handling.
* g10/packet.h (PKT_user_id): New fields KEYUPDATE, UPDATEURL, and
KEYSRC.
(PKT_public_key): Ditto.
(RING_TRUST_SIG, RING_TRUST_KEY, RING_TRUST_UID): New consts.
(PKT_ring_trust): New.
(struct packet_struct): Remove member RING_TRUST.
(strcu parse_packet_ctx_s): Add field SKIP_META.
(init_parse_packet): Init SKIPT_META.
* g10/free-packet.c (release_public_key_parts): Free UDPATEURL.
(free_user_id): Ditto.
* g10/mainproc.c (list_node): Remove printing of non-documented "rtv"
lines.
* g10/build-packet.c (build_packet_and_meta): New.
(do_ring_trust): New.
* g10/export.c (write_keyblock_to_output): Use build_packet_and_meta
in backup mode.
(do_export_one_keyblock): Ditto.
* g10/import.c (read_block): Add arg WITH_META. Skip ring trust
packets if that ism not set.
(import): Call read_block WITH_META in restore mode.
* g10/keydb.h (KEYSRC_UNKNOWN, KEYSRC_FILE, KEYSRC_KS, KEYSRC_PREF_KS)
(KEYSRC_WKD, KEYSRC_WKD_SD, KEYSRC_DANE): New constants. They are not
yet used, though.
* g10/keydb.c (parse_keyblock_image): Allow ring trust packets.
(build_keyblock_image): Ditto. Use build_packet_and_meta.
* g10/keyring.c (keyring_get_keyblock): Remove specila treatment of
ring trust packets.
(write_keyblock): Use build_packet_and_meta. Remove special treatment
of ring trust packets and initialization of the signature caches.
--
This patch introduced the framework to store meta data for keys and
user ids in the keyrings/keyboxes. Ring trust packets are
implementation defined and have always been used in gpg to cache the
signature verification status.
Ring trust packets are only exported with the export option "backup"
and only imported with the import option "restore".
The new code uses a cleaner way to handle the ring trust packets: When
the parser reads a ring trust packet and the previously read packet
matches the type of that ring trust packet, the information is stored
in that previously read packet (signature, user id, or primary key)
and the next packet is read immediately. Thus only the parser sees
the ring trust packets. Ring trust packets are written by using the
new function build_packet_and_meta instead of build_packet. That
function writes a ring trust packet when the needed information is
available.
As a side-effect of this patch the signature status cache works again
and "gpg --check-sigs" is thus much faster.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-03-30 09:07:02 +02:00
|
|
|
|
PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys);
|
2010-10-01 22:33:53 +02:00
|
|
|
|
static void revocation_present (ctrl_t ctrl, kbnode_t keyblock);
|
2017-10-18 13:09:47 +02:00
|
|
|
|
static gpg_error_t import_one (ctrl_t ctrl,
|
2016-07-06 10:35:36 +02:00
|
|
|
|
kbnode_t keyblock,
|
2015-12-12 18:19:35 +01:00
|
|
|
|
struct import_stats_s *stats,
|
2014-08-14 15:20:53 +02:00
|
|
|
|
unsigned char **fpr, size_t *fpr_len,
|
|
|
|
|
unsigned int options, int from_sk, int silent,
|
2017-07-13 18:22:36 +02:00
|
|
|
|
import_screener_t screener, void *screener_arg,
|
2019-03-15 19:50:37 +01:00
|
|
|
|
int origin, const char *url, int *r_valid);
|
2019-03-18 13:07:14 +01:00
|
|
|
|
static gpg_error_t import_matching_seckeys (
|
|
|
|
|
ctrl_t ctrl, kbnode_t seckeys,
|
|
|
|
|
const byte *mainfpr, size_t mainfprlen,
|
|
|
|
|
struct import_stats_s *stats, int batch);
|
2019-03-15 19:50:37 +01:00
|
|
|
|
static gpg_error_t import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
|
2015-12-12 18:19:35 +01:00
|
|
|
|
struct import_stats_s *stats, int batch,
|
2014-08-14 15:20:53 +02:00
|
|
|
|
unsigned int options, int for_migration,
|
2019-03-18 13:07:14 +01:00
|
|
|
|
import_screener_t screener, void *screener_arg,
|
|
|
|
|
kbnode_t *r_secattic);
|
2018-06-12 08:44:55 +02:00
|
|
|
|
static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
|
|
|
|
|
struct import_stats_s *stats);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
|
|
|
|
int *non_self);
|
|
|
|
|
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
|
2022-10-28 09:29:30 +02:00
|
|
|
|
u32 *keyid, unsigned int options,
|
|
|
|
|
kbnode_t *r_otherrevsigs);
|
2016-09-28 15:32:04 +02:00
|
|
|
|
static int any_uid_left (kbnode_t keyblock);
|
2019-07-01 21:53:55 +02:00
|
|
|
|
static void remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid);
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
static int merge_blocks (ctrl_t ctrl, unsigned int options,
|
|
|
|
|
kbnode_t keyblock_orig,
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t keyblock, u32 *keyid,
|
2017-07-25 11:23:08 +02:00
|
|
|
|
u32 curtime, int origin, const char *url,
|
2003-06-05 09:14:21 +02:00
|
|
|
|
int *n_uids, int *n_sigs, int *n_subk );
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
static gpg_error_t append_new_uid (unsigned int options,
|
|
|
|
|
kbnode_t keyblock, kbnode_t node,
|
|
|
|
|
u32 curtime, int origin, const char *url,
|
|
|
|
|
int *n_sigs);
|
2016-07-06 10:35:36 +02:00
|
|
|
|
static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs);
|
|
|
|
|
static int merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs);
|
|
|
|
|
static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2016-07-01 16:24:04 +02:00
|
|
|
|
|
|
|
|
|
|
2016-09-28 13:39:09 +02:00
|
|
|
|
static void
|
|
|
|
|
release_import_filter (import_filter_t filt)
|
|
|
|
|
{
|
|
|
|
|
recsel_release (filt->keep_uid);
|
|
|
|
|
filt->keep_uid = NULL;
|
|
|
|
|
recsel_release (filt->drop_sig);
|
|
|
|
|
filt->drop_sig = NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-01 16:24:04 +02:00
|
|
|
|
static void
|
|
|
|
|
cleanup_import_globals (void)
|
|
|
|
|
{
|
2016-09-28 13:39:09 +02:00
|
|
|
|
release_import_filter (&import_filter);
|
2016-07-01 16:24:04 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
int
|
2006-04-19 13:26:11 +02:00
|
|
|
|
parse_import_options(char *str,unsigned int *options,int noisy)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
struct parse_options import_opts[]=
|
|
|
|
|
{
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{"import-local-sigs",IMPORT_LOCAL_SIGS,NULL,
|
|
|
|
|
N_("import signatures that are marked as local-only")},
|
2014-11-12 09:56:40 +01:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{"repair-pks-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,
|
|
|
|
|
N_("repair damage from the pks keyserver during import")},
|
2014-11-12 09:56:40 +01:00
|
|
|
|
|
|
|
|
|
{"keep-ownertrust", IMPORT_KEEP_OWNERTTRUST, NULL,
|
|
|
|
|
N_("do not clear the ownertrust values during import")},
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{"fast-import",IMPORT_FAST,NULL,
|
|
|
|
|
N_("do not update the trustdb after import")},
|
2014-11-12 09:56:40 +01:00
|
|
|
|
|
2020-09-24 16:47:10 +02:00
|
|
|
|
{"bulk-import",IMPORT_BULK, NULL,
|
|
|
|
|
N_("enable bulk import mode")},
|
|
|
|
|
|
2016-06-23 19:25:53 +02:00
|
|
|
|
{"import-show",IMPORT_SHOW,NULL,
|
|
|
|
|
N_("show key during import")},
|
|
|
|
|
|
2020-09-24 16:47:10 +02:00
|
|
|
|
{"show-only", (IMPORT_SHOW | IMPORT_DRY_RUN), NULL,
|
|
|
|
|
N_("show key but do not actually import") },
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{"merge-only",IMPORT_MERGE_ONLY,NULL,
|
|
|
|
|
N_("only accept updates to existing keys")},
|
2014-11-12 09:56:40 +01:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{"import-clean",IMPORT_CLEAN,NULL,
|
|
|
|
|
N_("remove unusable parts from key after import")},
|
2014-11-12 09:56:40 +01:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{"import-minimal",IMPORT_MINIMAL|IMPORT_CLEAN,NULL,
|
|
|
|
|
N_("remove as much as possible from key after import")},
|
2014-11-12 09:56:40 +01:00
|
|
|
|
|
2019-07-01 15:14:59 +02:00
|
|
|
|
{"self-sigs-only", IMPORT_SELF_SIGS_ONLY, NULL,
|
|
|
|
|
N_("ignore key-signatures which are not self-signatures")},
|
2018-10-02 11:02:08 +02:00
|
|
|
|
|
2016-06-24 13:11:37 +02:00
|
|
|
|
{"import-export", IMPORT_EXPORT, NULL,
|
|
|
|
|
N_("run import filters and export key immediately")},
|
|
|
|
|
|
2017-01-23 10:12:18 +01:00
|
|
|
|
{"restore", IMPORT_RESTORE, NULL,
|
|
|
|
|
N_("assume the GnuPG key backup format")},
|
|
|
|
|
{"import-restore", IMPORT_RESTORE, NULL, NULL},
|
|
|
|
|
|
2017-06-13 15:35:01 +02:00
|
|
|
|
{"repair-keys", IMPORT_REPAIR_KEYS, NULL,
|
|
|
|
|
N_("repair keys on import")},
|
|
|
|
|
|
2024-01-24 18:23:02 +01:00
|
|
|
|
/* New options. Right now, without description string. */
|
|
|
|
|
{"ignore-attributes", IMPORT_IGNORE_ATTRIBUTES, NULL, NULL},
|
|
|
|
|
|
2024-06-24 11:49:05 +02:00
|
|
|
|
{"only-pubkeys", IMPORT_ONLY_PUBKEYS, NULL, NULL},
|
2024-06-11 15:52:07 +02:00
|
|
|
|
|
2020-08-25 10:33:57 +02:00
|
|
|
|
/* Hidden options which are enabled by default and are provided
|
|
|
|
|
* in case of problems with the respective implementation. */
|
|
|
|
|
{"collapse-uids", IMPORT_COLLAPSE_UIDS, NULL, NULL},
|
|
|
|
|
{"collapse-subkeys", IMPORT_COLLAPSE_SUBKEYS, NULL, NULL},
|
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
/* Aliases for backward compatibility */
|
|
|
|
|
{"allow-local-sigs",IMPORT_LOCAL_SIGS,NULL,NULL},
|
|
|
|
|
{"repair-hkp-subkey-bug",IMPORT_REPAIR_PKS_SUBKEY_BUG,NULL,NULL},
|
|
|
|
|
/* dummy */
|
|
|
|
|
{"import-unusable-sigs",0,NULL,NULL},
|
|
|
|
|
{"import-clean-sigs",0,NULL,NULL},
|
|
|
|
|
{"import-clean-uids",0,NULL,NULL},
|
2010-09-02 17:11:51 +02:00
|
|
|
|
{"convert-sk-to-pk",0, NULL,NULL}, /* Not anymore needed due to
|
|
|
|
|
the new design. */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{NULL,0,NULL,NULL}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
};
|
2017-01-23 10:12:18 +01:00
|
|
|
|
int rc;
|
2021-04-26 14:15:21 +02:00
|
|
|
|
int saved_self_sigs_only, saved_import_clean;
|
2021-04-13 14:25:16 +02:00
|
|
|
|
|
2024-05-13 00:09:23 +02:00
|
|
|
|
/* We need to set flags indicating whether the user has set certain
|
2021-04-26 14:15:21 +02:00
|
|
|
|
* options or if they came from the default. */
|
2021-04-13 14:25:16 +02:00
|
|
|
|
saved_self_sigs_only = (*options & IMPORT_SELF_SIGS_ONLY);
|
|
|
|
|
saved_self_sigs_only &= ~IMPORT_SELF_SIGS_ONLY;
|
2021-04-26 14:15:21 +02:00
|
|
|
|
saved_import_clean = (*options & IMPORT_CLEAN);
|
|
|
|
|
saved_import_clean &= ~IMPORT_CLEAN;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2017-01-23 10:12:18 +01:00
|
|
|
|
rc = parse_options (str, options, import_opts, noisy);
|
2021-04-13 14:25:16 +02:00
|
|
|
|
|
|
|
|
|
if (rc && (*options & IMPORT_SELF_SIGS_ONLY))
|
|
|
|
|
opt.flags.expl_import_self_sigs_only = 1;
|
|
|
|
|
else
|
|
|
|
|
*options |= saved_self_sigs_only;
|
|
|
|
|
|
2021-04-26 14:15:21 +02:00
|
|
|
|
if (rc && (*options & IMPORT_CLEAN))
|
|
|
|
|
opt.flags.expl_import_clean = 1;
|
|
|
|
|
else
|
|
|
|
|
*options |= saved_import_clean;
|
|
|
|
|
|
|
|
|
|
|
2017-01-23 10:12:18 +01:00
|
|
|
|
if (rc && (*options & IMPORT_RESTORE))
|
|
|
|
|
{
|
|
|
|
|
/* Alter other options we want or don't want for restore. */
|
|
|
|
|
*options |= (IMPORT_LOCAL_SIGS | IMPORT_KEEP_OWNERTTRUST);
|
|
|
|
|
*options &= ~(IMPORT_MINIMAL | IMPORT_CLEAN
|
|
|
|
|
| IMPORT_REPAIR_PKS_SUBKEY_BUG
|
|
|
|
|
| IMPORT_MERGE_ONLY);
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2016-07-01 16:24:04 +02:00
|
|
|
|
/* Parse and set an import filter from string. STRING has the format
|
|
|
|
|
* "NAME=EXPR" with NAME being the name of the filter. Spaces before
|
|
|
|
|
* and after NAME are not allowed. If this function is all called
|
|
|
|
|
* several times all expressions for the same NAME are concatenated.
|
|
|
|
|
* Supported filter names are:
|
|
|
|
|
*
|
|
|
|
|
* - keep-uid :: If the expression evaluates to true for a certain
|
|
|
|
|
* user ID packet, that packet and all it dependencies
|
|
|
|
|
* will be imported. The expression may use these
|
|
|
|
|
* variables:
|
|
|
|
|
*
|
|
|
|
|
* - uid :: The entire user ID.
|
|
|
|
|
* - mbox :: The mail box part of the user ID.
|
|
|
|
|
* - primary :: Evaluate to true for the primary user ID.
|
|
|
|
|
*/
|
|
|
|
|
gpg_error_t
|
|
|
|
|
parse_and_set_import_filter (const char *string)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
|
|
|
|
|
/* Auto register the cleanup function. */
|
|
|
|
|
register_mem_cleanup_func (cleanup_import_globals);
|
|
|
|
|
|
|
|
|
|
if (!strncmp (string, "keep-uid=", 9))
|
2016-09-28 13:39:09 +02:00
|
|
|
|
err = recsel_parse_expr (&import_filter.keep_uid, string+9);
|
2016-08-18 16:15:49 +02:00
|
|
|
|
else if (!strncmp (string, "drop-sig=", 9))
|
2016-09-28 13:39:09 +02:00
|
|
|
|
err = recsel_parse_expr (&import_filter.drop_sig, string+9);
|
2016-07-01 16:24:04 +02:00
|
|
|
|
else
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_NAME);
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-09-28 13:39:09 +02:00
|
|
|
|
/* Save the current import filters, return them, and clear the current
|
|
|
|
|
* filters. Returns NULL on error and sets ERRNO. */
|
|
|
|
|
import_filter_t
|
|
|
|
|
save_and_clear_import_filter (void)
|
|
|
|
|
{
|
|
|
|
|
import_filter_t filt;
|
|
|
|
|
|
|
|
|
|
filt = xtrycalloc (1, sizeof *filt);
|
|
|
|
|
if (!filt)
|
|
|
|
|
return NULL;
|
|
|
|
|
*filt = import_filter;
|
|
|
|
|
memset (&import_filter, 0, sizeof import_filter);
|
|
|
|
|
|
|
|
|
|
return filt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Release the current import filters and restore them from NEWFILT.
|
|
|
|
|
* Ownership of NEWFILT is moved to this function. */
|
|
|
|
|
void
|
|
|
|
|
restore_import_filter (import_filter_t filt)
|
|
|
|
|
{
|
|
|
|
|
if (filt)
|
|
|
|
|
{
|
|
|
|
|
release_import_filter (&import_filter);
|
|
|
|
|
import_filter = *filt;
|
|
|
|
|
xfree (filt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-01 16:24:04 +02:00
|
|
|
|
|
2015-12-12 18:19:35 +01:00
|
|
|
|
import_stats_t
|
2003-06-05 09:14:21 +02:00
|
|
|
|
import_new_stats_handle (void)
|
|
|
|
|
{
|
2015-12-12 18:19:35 +01:00
|
|
|
|
return xmalloc_clear ( sizeof (struct import_stats_s) );
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
void
|
2015-12-12 18:19:35 +01:00
|
|
|
|
import_release_stats_handle (import_stats_t p)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
xfree (p);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2016-07-06 14:03:50 +02:00
|
|
|
|
/* Read a key from a file. Only the first key in the file is
|
|
|
|
|
* considered and stored at R_KEYBLOCK. FNAME is the name of the
|
|
|
|
|
* file.
|
|
|
|
|
*/
|
|
|
|
|
gpg_error_t
|
2020-03-13 17:14:34 +01:00
|
|
|
|
read_key_from_file_or_buffer (ctrl_t ctrl, const char *fname,
|
|
|
|
|
const void *buffer, size_t buflen,
|
|
|
|
|
kbnode_t *r_keyblock)
|
2016-07-06 14:03:50 +02:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
iobuf_t inp;
|
|
|
|
|
PACKET *pending_pkt = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
int v3keys; /* Dummy */
|
|
|
|
|
int non_self; /* Dummy */
|
|
|
|
|
|
|
|
|
|
(void)ctrl;
|
|
|
|
|
|
|
|
|
|
*r_keyblock = NULL;
|
|
|
|
|
|
2020-03-13 17:14:34 +01:00
|
|
|
|
log_assert (!!fname ^ !!buffer);
|
|
|
|
|
|
|
|
|
|
if (fname)
|
2016-07-06 14:03:50 +02:00
|
|
|
|
{
|
2020-03-13 17:14:34 +01:00
|
|
|
|
inp = iobuf_open (fname);
|
|
|
|
|
if (!inp)
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
else if (is_secured_file (iobuf_get_fd (inp)))
|
|
|
|
|
{
|
|
|
|
|
iobuf_close (inp);
|
|
|
|
|
inp = NULL;
|
|
|
|
|
err = gpg_error (GPG_ERR_EPERM);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
err = 0;
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("can't open '%s': %s\n"),
|
|
|
|
|
iobuf_is_pipe_filename (fname)? "[stdin]": fname,
|
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_ENOENT)
|
|
|
|
|
err = gpg_error (GPG_ERR_NO_PUBKEY);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Push the armor filter. */
|
|
|
|
|
{
|
|
|
|
|
armor_filter_context_t *afx;
|
|
|
|
|
afx = new_armor_context ();
|
|
|
|
|
afx->only_keyblocks = 1;
|
|
|
|
|
push_armor_filter (afx, inp);
|
|
|
|
|
release_armor_context (afx);
|
|
|
|
|
}
|
|
|
|
|
|
2016-07-06 14:03:50 +02:00
|
|
|
|
}
|
2020-03-13 17:14:34 +01:00
|
|
|
|
else /* Read from buffer (No armor expected). */
|
2016-07-06 14:03:50 +02:00
|
|
|
|
{
|
2020-03-13 17:14:34 +01:00
|
|
|
|
inp = iobuf_temp_with_content (buffer, buflen);
|
2016-07-06 14:03:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read the first non-v3 keyblock. */
|
gpg: Revamp reading and writing of ring trust packets.
* g10/parse-packet.c (parse_trust): Rename to ...
(parse_ring_trust): this. Change args and implement new ring trust
packet format.
(parse): Add special ring trust packet handling.
* g10/packet.h (PKT_user_id): New fields KEYUPDATE, UPDATEURL, and
KEYSRC.
(PKT_public_key): Ditto.
(RING_TRUST_SIG, RING_TRUST_KEY, RING_TRUST_UID): New consts.
(PKT_ring_trust): New.
(struct packet_struct): Remove member RING_TRUST.
(strcu parse_packet_ctx_s): Add field SKIP_META.
(init_parse_packet): Init SKIPT_META.
* g10/free-packet.c (release_public_key_parts): Free UDPATEURL.
(free_user_id): Ditto.
* g10/mainproc.c (list_node): Remove printing of non-documented "rtv"
lines.
* g10/build-packet.c (build_packet_and_meta): New.
(do_ring_trust): New.
* g10/export.c (write_keyblock_to_output): Use build_packet_and_meta
in backup mode.
(do_export_one_keyblock): Ditto.
* g10/import.c (read_block): Add arg WITH_META. Skip ring trust
packets if that ism not set.
(import): Call read_block WITH_META in restore mode.
* g10/keydb.h (KEYSRC_UNKNOWN, KEYSRC_FILE, KEYSRC_KS, KEYSRC_PREF_KS)
(KEYSRC_WKD, KEYSRC_WKD_SD, KEYSRC_DANE): New constants. They are not
yet used, though.
* g10/keydb.c (parse_keyblock_image): Allow ring trust packets.
(build_keyblock_image): Ditto. Use build_packet_and_meta.
* g10/keyring.c (keyring_get_keyblock): Remove specila treatment of
ring trust packets.
(write_keyblock): Use build_packet_and_meta. Remove special treatment
of ring trust packets and initialization of the signature caches.
--
This patch introduced the framework to store meta data for keys and
user ids in the keyrings/keyboxes. Ring trust packets are
implementation defined and have always been used in gpg to cache the
signature verification status.
Ring trust packets are only exported with the export option "backup"
and only imported with the import option "restore".
The new code uses a cleaner way to handle the ring trust packets: When
the parser reads a ring trust packet and the previously read packet
matches the type of that ring trust packet, the information is stored
in that previously read packet (signature, user id, or primary key)
and the next packet is read immediately. Thus only the parser sees
the ring trust packets. Ring trust packets are written by using the
new function build_packet_and_meta instead of build_packet. That
function writes a ring trust packet when the needed information is
available.
As a side-effect of this patch the signature status cache works again
and "gpg --check-sigs" is thus much faster.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-03-30 09:07:02 +02:00
|
|
|
|
while (!(err = read_block (inp, 0, &pending_pkt, &keyblock, &v3keys)))
|
2016-07-06 14:03:50 +02:00
|
|
|
|
{
|
|
|
|
|
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
|
|
|
|
|
break;
|
|
|
|
|
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
keyblock = NULL;
|
|
|
|
|
}
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
if (gpg_err_code (err) != GPG_ERR_INV_KEYRING)
|
|
|
|
|
log_error (_("error reading '%s': %s\n"),
|
2020-03-13 17:14:34 +01:00
|
|
|
|
fname? (iobuf_is_pipe_filename (fname)? "[stdin]": fname)
|
|
|
|
|
/* */ : "[buffer]",
|
2016-07-06 14:03:50 +02:00
|
|
|
|
gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
|
|
|
|
|
|
|
|
|
|
if (!find_next_kbnode (keyblock, PKT_USER_ID))
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_NO_USER_ID);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-25 10:33:57 +02:00
|
|
|
|
/* We do the collapsing unconditionally although it is expected that
|
|
|
|
|
* clean keys are provided here. */
|
2016-07-06 14:03:50 +02:00
|
|
|
|
collapse_uids (&keyblock);
|
2020-08-25 10:33:57 +02:00
|
|
|
|
collapse_subkeys (&keyblock);
|
2016-07-06 14:03:50 +02:00
|
|
|
|
|
|
|
|
|
clear_kbnode_flags (keyblock);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (chk_self_sigs (ctrl, keyblock, keyid, &non_self))
|
2016-07-06 14:03:50 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_INV_KEYRING);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-28 09:29:30 +02:00
|
|
|
|
if (!delete_inv_parts (ctrl, keyblock, keyid, 0, NULL) )
|
2016-07-06 14:03:50 +02:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_NO_USER_ID);
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*r_keyblock = keyblock;
|
|
|
|
|
keyblock = NULL;
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
if (inp)
|
|
|
|
|
{
|
|
|
|
|
iobuf_close (inp);
|
|
|
|
|
/* Must invalidate that ugly cache to actually close the file. */
|
2020-03-13 17:14:34 +01:00
|
|
|
|
if (fname)
|
|
|
|
|
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
|
2016-07-06 14:03:50 +02:00
|
|
|
|
}
|
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
/* FIXME: Do we need to free PENDING_PKT ? */
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2020-03-13 17:14:34 +01:00
|
|
|
|
/* Import an already checked public key which was included in a
|
|
|
|
|
* signature and the signature verified out using this key. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
import_included_key_block (ctrl_t ctrl, kbnode_t keyblock)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
struct import_stats_s *stats;
|
|
|
|
|
import_filter_t save_filt;
|
|
|
|
|
int save_armor = opt.armor;
|
|
|
|
|
|
|
|
|
|
opt.armor = 0;
|
|
|
|
|
stats = import_new_stats_handle ();
|
|
|
|
|
save_filt = save_and_clear_import_filter ();
|
|
|
|
|
if (!save_filt)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: Should we introduce a dedicated KEYORG ? */
|
|
|
|
|
err = import_one (ctrl, keyblock,
|
|
|
|
|
stats, NULL, 0, 0, 0, 0,
|
|
|
|
|
NULL, NULL, KEYORG_UNKNOWN, NULL, NULL);
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
restore_import_filter (save_filt);
|
|
|
|
|
import_release_stats_handle (stats);
|
|
|
|
|
opt.armor = save_armor;
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-07-06 14:03:50 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Import the public keys from the given filename. Input may be armored.
|
|
|
|
|
* This function rejects all keys which are not validly self signed on at
|
|
|
|
|
* least one userid. Only user ids which are self signed will be imported.
|
|
|
|
|
* Other signatures are not checked.
|
|
|
|
|
*
|
|
|
|
|
* Actually this function does a merge. It works like this:
|
|
|
|
|
*
|
|
|
|
|
* - get the keyblock
|
|
|
|
|
* - check self-signatures and remove all userids and their signatures
|
|
|
|
|
* without/invalid self-signatures.
|
|
|
|
|
* - reject the keyblock, if we have no valid userid.
|
|
|
|
|
* - See whether we have this key already in one of our pubrings.
|
|
|
|
|
* If not, simply add it to the default keyring.
|
|
|
|
|
* - Compare the key and the self-signatures of the new and the one in
|
|
|
|
|
* our keyring. If they are different something weird is going on;
|
|
|
|
|
* ask what to do.
|
|
|
|
|
* - See whether we have only non-self-signature on one user id; if not
|
|
|
|
|
* ask the user what to do.
|
|
|
|
|
* - compare the signatures: If we already have this signature, check
|
|
|
|
|
* that they compare okay; if not, issue a warning and ask the user.
|
|
|
|
|
* (consider looking at the timestamp and use the newest?)
|
|
|
|
|
* - Simply add the signature. Can't verify here because we may not have
|
|
|
|
|
* the signature's public key yet; verification is done when putting it
|
|
|
|
|
* into the trustdb, which is done automagically as soon as this pubkey
|
|
|
|
|
* is used.
|
|
|
|
|
* - Proceed with next signature.
|
|
|
|
|
*
|
|
|
|
|
* Key revocation certificates have special handling.
|
|
|
|
|
*/
|
2017-10-18 13:09:47 +02:00
|
|
|
|
static gpg_error_t
|
2010-08-31 17:58:39 +02:00
|
|
|
|
import_keys_internal (ctrl_t ctrl, iobuf_t inp, char **fnames, int nnames,
|
2015-12-12 18:19:35 +01:00
|
|
|
|
import_stats_t stats_handle,
|
|
|
|
|
unsigned char **fpr, size_t *fpr_len,
|
2014-08-14 15:20:53 +02:00
|
|
|
|
unsigned int options,
|
2017-07-13 18:22:36 +02:00
|
|
|
|
import_screener_t screener, void *screener_arg,
|
2017-07-24 20:05:28 +02:00
|
|
|
|
int origin, const char *url)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
int i;
|
2017-10-18 13:09:47 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2015-12-12 18:19:35 +01:00
|
|
|
|
struct import_stats_s *stats = stats_handle;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!stats)
|
|
|
|
|
stats = import_new_stats_handle ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (inp)
|
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = import (ctrl, inp, "[stream]", stats, fpr, fpr_len, options,
|
|
|
|
|
screener, screener_arg, origin, url);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!fnames && !nnames)
|
|
|
|
|
nnames = 1; /* Ohh what a ugly hack to jump into the loop */
|
|
|
|
|
|
|
|
|
|
for (i=0; i < nnames; i++)
|
|
|
|
|
{
|
|
|
|
|
const char *fname = fnames? fnames[i] : NULL;
|
|
|
|
|
IOBUF inp2 = iobuf_open(fname);
|
|
|
|
|
|
|
|
|
|
if (!fname)
|
|
|
|
|
fname = "[stdin]";
|
|
|
|
|
if (inp2 && is_secured_file (iobuf_get_fd (inp2)))
|
|
|
|
|
{
|
|
|
|
|
iobuf_close (inp2);
|
|
|
|
|
inp2 = NULL;
|
|
|
|
|
gpg_err_set_errno (EPERM);
|
|
|
|
|
}
|
|
|
|
|
if (!inp2)
|
|
|
|
|
log_error (_("can't open '%s': %s\n"), fname, strerror (errno));
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = import (ctrl, inp2, fname, stats, fpr, fpr_len, options,
|
2017-07-24 20:05:28 +02:00
|
|
|
|
screener, screener_arg, origin, url);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
iobuf_close (inp2);
|
|
|
|
|
/* Must invalidate that ugly cache to actually close it. */
|
|
|
|
|
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
|
2017-10-18 13:09:47 +02:00
|
|
|
|
if (err)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_error ("import from '%s' failed: %s\n",
|
2017-10-18 13:09:47 +02:00
|
|
|
|
fname, gpg_strerror (err) );
|
2014-12-04 10:45:53 +01:00
|
|
|
|
}
|
|
|
|
|
if (!fname)
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
if (!stats_handle)
|
|
|
|
|
{
|
2018-06-06 11:50:58 +02:00
|
|
|
|
if ((options & (IMPORT_SHOW | IMPORT_DRY_RUN))
|
|
|
|
|
!= (IMPORT_SHOW | IMPORT_DRY_RUN))
|
|
|
|
|
import_print_stats (stats);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
import_release_stats_handle (stats);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* If no fast import and the trustdb is dirty (i.e. we added a key
|
|
|
|
|
or userID that had something other than a selfsig, a signature
|
|
|
|
|
that was other than a selfsig, or any revocation), then
|
|
|
|
|
update/check the trustdb if the user specified by setting
|
|
|
|
|
interactive or by not setting no-auto-check-trustdb */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!(options & IMPORT_FAST))
|
2016-05-21 11:41:49 +02:00
|
|
|
|
check_or_update_trustdb (ctrl);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2017-10-18 13:09:47 +02:00
|
|
|
|
return err;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 11:19:59 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
void
|
2010-08-31 17:58:39 +02:00
|
|
|
|
import_keys (ctrl_t ctrl, char **fnames, int nnames,
|
2017-07-24 20:05:28 +02:00
|
|
|
|
import_stats_t stats_handle, unsigned int options,
|
|
|
|
|
int origin, const char *url)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-08-31 17:58:39 +02:00
|
|
|
|
import_keys_internal (ctrl, NULL, fnames, nnames, stats_handle,
|
2017-07-24 20:05:28 +02:00
|
|
|
|
NULL, NULL, options, NULL, NULL, origin, url);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2011-01-18 12:51:16 +01:00
|
|
|
|
|
2017-10-18 13:09:47 +02:00
|
|
|
|
gpg_error_t
|
2015-12-12 18:19:35 +01:00
|
|
|
|
import_keys_es_stream (ctrl_t ctrl, estream_t fp,
|
|
|
|
|
import_stats_t stats_handle,
|
2011-01-18 12:51:16 +01:00
|
|
|
|
unsigned char **fpr, size_t *fpr_len,
|
2014-08-14 15:20:53 +02:00
|
|
|
|
unsigned int options,
|
2017-07-13 18:22:36 +02:00
|
|
|
|
import_screener_t screener, void *screener_arg,
|
2017-07-24 20:05:28 +02:00
|
|
|
|
int origin, const char *url)
|
2011-01-18 12:51:16 +01:00
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
gpg_error_t err;
|
2011-01-18 12:51:16 +01:00
|
|
|
|
iobuf_t inp;
|
|
|
|
|
|
2019-09-10 15:45:58 +02:00
|
|
|
|
inp = iobuf_esopen (fp, "rb", 1, 0);
|
2011-01-18 12:51:16 +01:00
|
|
|
|
if (!inp)
|
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error ("iobuf_esopen failed: %s\n", gpg_strerror (err));
|
|
|
|
|
return err;
|
2011-01-18 12:51:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = import_keys_internal (ctrl, inp, NULL, 0, stats_handle,
|
2014-08-14 15:20:53 +02:00
|
|
|
|
fpr, fpr_len, options,
|
2017-07-24 20:05:28 +02:00
|
|
|
|
screener, screener_arg, origin, url);
|
2011-01-18 12:51:16 +01:00
|
|
|
|
|
|
|
|
|
iobuf_close (inp);
|
2017-10-18 13:09:47 +02:00
|
|
|
|
return err;
|
2011-01-18 12:51:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2015-12-12 18:19:35 +01:00
|
|
|
|
import (ctrl_t ctrl, IOBUF inp, const char* fname,struct import_stats_s *stats,
|
2014-08-14 15:20:53 +02:00
|
|
|
|
unsigned char **fpr,size_t *fpr_len, unsigned int options,
|
2017-07-24 20:05:28 +02:00
|
|
|
|
import_screener_t screener, void *screener_arg,
|
|
|
|
|
int origin, const char *url)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
PACKET *pending_pkt = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL; /* Need to initialize because gcc can't
|
2006-05-23 18:19:43 +02:00
|
|
|
|
grasp the return semantics of
|
|
|
|
|
read_block. */
|
2019-03-18 13:07:14 +01:00
|
|
|
|
kbnode_t secattic = NULL; /* Kludge for PGP desktop percularity */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
int rc = 0;
|
|
|
|
|
int v3keys;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
getkey_disable_caches ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!opt.no_armor) /* Armored reading is not disabled. */
|
|
|
|
|
{
|
|
|
|
|
armor_filter_context_t *afx;
|
2006-12-06 11:16:50 +01:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
afx = new_armor_context ();
|
|
|
|
|
afx->only_keyblocks = 1;
|
|
|
|
|
push_armor_filter (afx, inp);
|
|
|
|
|
release_armor_context (afx);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-07-01 14:01:08 +02:00
|
|
|
|
while (!(rc = read_block (inp, options, &pending_pkt, &keyblock, &v3keys)))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
stats->v3keys += v3keys;
|
|
|
|
|
if (keyblock->pkt->pkttype == PKT_PUBLIC_KEY)
|
2019-03-18 13:07:14 +01:00
|
|
|
|
{
|
|
|
|
|
rc = import_one (ctrl, keyblock,
|
|
|
|
|
stats, fpr, fpr_len, options, 0, 0,
|
|
|
|
|
screener, screener_arg, origin, url, NULL);
|
|
|
|
|
if (secattic)
|
|
|
|
|
{
|
|
|
|
|
byte tmpfpr[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t tmpfprlen;
|
|
|
|
|
|
|
|
|
|
if (!rc && !(opt.dry_run || (options & IMPORT_DRY_RUN)))
|
|
|
|
|
{
|
|
|
|
|
/* Kudge for PGP desktop - see below. */
|
|
|
|
|
fingerprint_from_pk (keyblock->pkt->pkt.public_key,
|
|
|
|
|
tmpfpr, &tmpfprlen);
|
|
|
|
|
rc = import_matching_seckeys (ctrl, secattic,
|
|
|
|
|
tmpfpr, tmpfprlen,
|
|
|
|
|
stats, opt.batch);
|
|
|
|
|
}
|
|
|
|
|
release_kbnode (secattic);
|
|
|
|
|
secattic = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
|
2019-03-18 13:07:14 +01:00
|
|
|
|
{
|
|
|
|
|
release_kbnode (secattic);
|
|
|
|
|
secattic = NULL;
|
|
|
|
|
rc = import_secret_one (ctrl, keyblock, stats,
|
|
|
|
|
opt.batch, options, 0,
|
|
|
|
|
screener, screener_arg, &secattic);
|
|
|
|
|
keyblock = NULL; /* Ownership was transferred. */
|
|
|
|
|
if (secattic)
|
|
|
|
|
{
|
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY)
|
|
|
|
|
rc = 0; /* Try import after the next pubkey. */
|
|
|
|
|
|
|
|
|
|
/* The attic is a workaround for the peculiar PGP
|
|
|
|
|
* Desktop method of exporting a secret key: The
|
|
|
|
|
* exported file is the concatenation of two armored
|
|
|
|
|
* keyblocks; first the private one and then the public
|
|
|
|
|
* one. The strange thing is that the secret one has no
|
|
|
|
|
* binding signatures at all and thus we have not
|
|
|
|
|
* imported it. The attic stores that secret keys and
|
|
|
|
|
* we try to import it once after the very next public
|
|
|
|
|
* keyblock. */
|
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (keyblock->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 17:38:03 +02:00
|
|
|
|
&& IS_KEY_REV (keyblock->pkt->pkt.signature) )
|
2019-03-18 13:07:14 +01:00
|
|
|
|
{
|
|
|
|
|
release_kbnode (secattic);
|
|
|
|
|
secattic = NULL;
|
|
|
|
|
rc = import_revoke_cert (ctrl, keyblock, options, stats);
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (secattic);
|
|
|
|
|
secattic = NULL;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_info (_("skipping block of type %d\n"), keyblock->pkt->pkttype);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2014-12-04 10:53:10 +01:00
|
|
|
|
|
|
|
|
|
/* fixme: we should increment the not imported counter but
|
|
|
|
|
this does only make sense if we keep on going despite of
|
|
|
|
|
errors. For now we do this only if the imported key is too
|
|
|
|
|
large. */
|
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_TOO_LARGE
|
|
|
|
|
&& gpg_err_source (rc) == GPG_ERR_SOURCE_KEYBOX)
|
|
|
|
|
{
|
|
|
|
|
stats->not_imported++;
|
|
|
|
|
}
|
|
|
|
|
else if (rc)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
break;
|
2014-12-04 10:53:10 +01:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!(++stats->count % 100) && !opt.quiet)
|
|
|
|
|
log_info (_("%lu keys processed so far\n"), stats->count );
|
2019-04-11 09:43:33 +02:00
|
|
|
|
|
|
|
|
|
if (origin == KEYORG_WKD && stats->count >= 5)
|
|
|
|
|
{
|
|
|
|
|
/* We limit the number of keys _received_ from the WKD to 5.
|
|
|
|
|
* In fact there should be only one key but some sites want
|
|
|
|
|
* to store a few expired keys there also. gpg's key
|
|
|
|
|
* selection will later figure out which key to use. Note
|
|
|
|
|
* that for WKD we always return the fingerprint of the
|
|
|
|
|
* first imported key. */
|
|
|
|
|
log_info ("import from WKD stopped after %d keys\n", 5);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
stats->v3keys += v3keys;
|
|
|
|
|
if (rc == -1)
|
|
|
|
|
rc = 0;
|
2015-01-22 12:06:11 +01:00
|
|
|
|
else if (rc && gpg_err_code (rc) != GPG_ERR_INV_KEYRING)
|
|
|
|
|
log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (rc));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (secattic);
|
2019-04-17 02:58:07 +02:00
|
|
|
|
|
|
|
|
|
/* When read_block loop was stopped by error, we have PENDING_PKT left. */
|
|
|
|
|
if (pending_pkt)
|
|
|
|
|
{
|
|
|
|
|
free_packet (pending_pkt, NULL);
|
|
|
|
|
xfree (pending_pkt);
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-06-05 11:19:59 +02:00
|
|
|
|
/* Helper to migrate secring.gpg to GnuPG 2.1. */
|
|
|
|
|
gpg_error_t
|
|
|
|
|
import_old_secring (ctrl_t ctrl, const char *fname)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
iobuf_t inp;
|
|
|
|
|
PACKET *pending_pkt = NULL;
|
|
|
|
|
kbnode_t keyblock = NULL; /* Need to initialize because gcc can't
|
|
|
|
|
grasp the return semantics of
|
|
|
|
|
read_block. */
|
2015-12-12 18:19:35 +01:00
|
|
|
|
struct import_stats_s *stats;
|
2014-11-19 10:34:32 +01:00
|
|
|
|
int v3keys;
|
2014-06-05 11:19:59 +02:00
|
|
|
|
|
|
|
|
|
inp = iobuf_open (fname);
|
|
|
|
|
if (inp && is_secured_file (iobuf_get_fd (inp)))
|
|
|
|
|
{
|
|
|
|
|
iobuf_close (inp);
|
|
|
|
|
inp = NULL;
|
|
|
|
|
gpg_err_set_errno (EPERM);
|
|
|
|
|
}
|
|
|
|
|
if (!inp)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error (_("can't open '%s': %s\n"), fname, gpg_strerror (err));
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getkey_disable_caches();
|
|
|
|
|
stats = import_new_stats_handle ();
|
gpg: Revamp reading and writing of ring trust packets.
* g10/parse-packet.c (parse_trust): Rename to ...
(parse_ring_trust): this. Change args and implement new ring trust
packet format.
(parse): Add special ring trust packet handling.
* g10/packet.h (PKT_user_id): New fields KEYUPDATE, UPDATEURL, and
KEYSRC.
(PKT_public_key): Ditto.
(RING_TRUST_SIG, RING_TRUST_KEY, RING_TRUST_UID): New consts.
(PKT_ring_trust): New.
(struct packet_struct): Remove member RING_TRUST.
(strcu parse_packet_ctx_s): Add field SKIP_META.
(init_parse_packet): Init SKIPT_META.
* g10/free-packet.c (release_public_key_parts): Free UDPATEURL.
(free_user_id): Ditto.
* g10/mainproc.c (list_node): Remove printing of non-documented "rtv"
lines.
* g10/build-packet.c (build_packet_and_meta): New.
(do_ring_trust): New.
* g10/export.c (write_keyblock_to_output): Use build_packet_and_meta
in backup mode.
(do_export_one_keyblock): Ditto.
* g10/import.c (read_block): Add arg WITH_META. Skip ring trust
packets if that ism not set.
(import): Call read_block WITH_META in restore mode.
* g10/keydb.h (KEYSRC_UNKNOWN, KEYSRC_FILE, KEYSRC_KS, KEYSRC_PREF_KS)
(KEYSRC_WKD, KEYSRC_WKD_SD, KEYSRC_DANE): New constants. They are not
yet used, though.
* g10/keydb.c (parse_keyblock_image): Allow ring trust packets.
(build_keyblock_image): Ditto. Use build_packet_and_meta.
* g10/keyring.c (keyring_get_keyblock): Remove specila treatment of
ring trust packets.
(write_keyblock): Use build_packet_and_meta. Remove special treatment
of ring trust packets and initialization of the signature caches.
--
This patch introduced the framework to store meta data for keys and
user ids in the keyrings/keyboxes. Ring trust packets are
implementation defined and have always been used in gpg to cache the
signature verification status.
Ring trust packets are only exported with the export option "backup"
and only imported with the import option "restore".
The new code uses a cleaner way to handle the ring trust packets: When
the parser reads a ring trust packet and the previously read packet
matches the type of that ring trust packet, the information is stored
in that previously read packet (signature, user id, or primary key)
and the next packet is read immediately. Thus only the parser sees
the ring trust packets. Ring trust packets are written by using the
new function build_packet_and_meta instead of build_packet. That
function writes a ring trust packet when the needed information is
available.
As a side-effect of this patch the signature status cache works again
and "gpg --check-sigs" is thus much faster.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-03-30 09:07:02 +02:00
|
|
|
|
while (!(err = read_block (inp, 0, &pending_pkt, &keyblock, &v3keys)))
|
2014-06-05 11:19:59 +02:00
|
|
|
|
{
|
|
|
|
|
if (keyblock->pkt->pkttype == PKT_SECRET_KEY)
|
2019-03-18 13:07:14 +01:00
|
|
|
|
{
|
|
|
|
|
err = import_secret_one (ctrl, keyblock, stats, 1, 0, 1,
|
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
keyblock = NULL; /* Ownership was transferred. */
|
|
|
|
|
}
|
2014-06-05 11:19:59 +02:00
|
|
|
|
release_kbnode (keyblock);
|
|
|
|
|
if (err)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
import_release_stats_handle (stats);
|
|
|
|
|
if (err == -1)
|
|
|
|
|
err = 0;
|
2015-01-22 12:06:11 +01:00
|
|
|
|
else if (err && gpg_err_code (err) != GPG_ERR_INV_KEYRING)
|
2014-06-05 11:19:59 +02:00
|
|
|
|
log_error (_("error reading '%s': %s\n"), fname, gpg_strerror (err));
|
|
|
|
|
else if (err)
|
|
|
|
|
log_error ("import from '%s' failed: %s\n", fname, gpg_strerror (err));
|
|
|
|
|
|
|
|
|
|
iobuf_close (inp);
|
|
|
|
|
iobuf_ioctl (NULL, IOBUF_IOCTL_INVALIDATE_CACHE, 0, (char*)fname);
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
void
|
2015-12-12 18:19:35 +01:00
|
|
|
|
import_print_stats (import_stats_t stats)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!opt.quiet)
|
|
|
|
|
{
|
|
|
|
|
log_info(_("Total number processed: %lu\n"),
|
|
|
|
|
stats->count + stats->v3keys);
|
|
|
|
|
if (stats->v3keys)
|
|
|
|
|
log_info(_(" skipped PGP-2 keys: %lu\n"), stats->v3keys);
|
|
|
|
|
if (stats->skipped_new_keys )
|
|
|
|
|
log_info(_(" skipped new keys: %lu\n"),
|
|
|
|
|
stats->skipped_new_keys );
|
|
|
|
|
if (stats->no_user_id )
|
|
|
|
|
log_info(_(" w/o user IDs: %lu\n"), stats->no_user_id );
|
|
|
|
|
if (stats->imported)
|
|
|
|
|
{
|
|
|
|
|
log_info(_(" imported: %lu"), stats->imported );
|
|
|
|
|
log_printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
if (stats->unchanged )
|
|
|
|
|
log_info(_(" unchanged: %lu\n"), stats->unchanged );
|
|
|
|
|
if (stats->n_uids )
|
|
|
|
|
log_info(_(" new user IDs: %lu\n"), stats->n_uids );
|
|
|
|
|
if (stats->n_subk )
|
|
|
|
|
log_info(_(" new subkeys: %lu\n"), stats->n_subk );
|
|
|
|
|
if (stats->n_sigs )
|
|
|
|
|
log_info(_(" new signatures: %lu\n"), stats->n_sigs );
|
|
|
|
|
if (stats->n_revoc )
|
|
|
|
|
log_info(_(" new key revocations: %lu\n"), stats->n_revoc );
|
|
|
|
|
if (stats->secret_read )
|
|
|
|
|
log_info(_(" secret keys read: %lu\n"), stats->secret_read );
|
|
|
|
|
if (stats->secret_imported )
|
|
|
|
|
log_info(_(" secret keys imported: %lu\n"), stats->secret_imported );
|
|
|
|
|
if (stats->secret_dups )
|
|
|
|
|
log_info(_(" secret keys unchanged: %lu\n"), stats->secret_dups );
|
|
|
|
|
if (stats->not_imported )
|
|
|
|
|
log_info(_(" not imported: %lu\n"), stats->not_imported );
|
|
|
|
|
if (stats->n_sigs_cleaned)
|
|
|
|
|
log_info(_(" signatures cleaned: %lu\n"),stats->n_sigs_cleaned);
|
|
|
|
|
if (stats->n_uids_cleaned)
|
|
|
|
|
log_info(_(" user IDs cleaned: %lu\n"),stats->n_uids_cleaned);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (is_status_enabled ())
|
|
|
|
|
{
|
|
|
|
|
char buf[15*20];
|
|
|
|
|
|
|
|
|
|
snprintf (buf, sizeof buf,
|
|
|
|
|
"%lu %lu %lu 0 %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu",
|
2014-11-19 10:34:32 +01:00
|
|
|
|
stats->count + stats->v3keys,
|
2003-06-05 09:14:21 +02:00
|
|
|
|
stats->no_user_id,
|
|
|
|
|
stats->imported,
|
|
|
|
|
stats->unchanged,
|
|
|
|
|
stats->n_uids,
|
|
|
|
|
stats->n_subk,
|
|
|
|
|
stats->n_sigs,
|
|
|
|
|
stats->n_revoc,
|
|
|
|
|
stats->secret_read,
|
|
|
|
|
stats->secret_imported,
|
|
|
|
|
stats->secret_dups,
|
|
|
|
|
stats->skipped_new_keys,
|
2014-12-04 10:45:53 +01:00
|
|
|
|
stats->not_imported,
|
2014-11-19 10:34:32 +01:00
|
|
|
|
stats->v3keys );
|
2014-12-04 10:45:53 +01:00
|
|
|
|
write_status_text (STATUS_IMPORT_RES, buf);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2012-12-20 09:43:41 +01:00
|
|
|
|
/* Return true if PKTTYPE is valid in a keyblock. */
|
|
|
|
|
static int
|
|
|
|
|
valid_keyblock_packet (int pkttype)
|
|
|
|
|
{
|
|
|
|
|
switch (pkttype)
|
|
|
|
|
{
|
|
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
|
case PKT_PUBLIC_SUBKEY:
|
|
|
|
|
case PKT_SECRET_KEY:
|
|
|
|
|
case PKT_SECRET_SUBKEY:
|
|
|
|
|
case PKT_SIGNATURE:
|
|
|
|
|
case PKT_USER_ID:
|
|
|
|
|
case PKT_ATTRIBUTE:
|
|
|
|
|
case PKT_RING_TRUST:
|
|
|
|
|
return 1;
|
|
|
|
|
default:
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-07-01 14:01:08 +02:00
|
|
|
|
/* Read the next keyblock from stream A. Meta data (ring trust
|
|
|
|
|
* packets) are only considered if OPTIONS has the IMPORT_RESTORE flag
|
|
|
|
|
* set. PENDING_PKT should be initialized to NULL and not changed by
|
|
|
|
|
* the caller.
|
|
|
|
|
*
|
|
|
|
|
* Returns 0 for okay, -1 no more blocks, or any other errorcode. The
|
|
|
|
|
* integer at R_V3KEY counts the number of unsupported v3 keyblocks.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2019-07-01 14:01:08 +02:00
|
|
|
|
read_block( IOBUF a, unsigned int options,
|
gpg: Revamp reading and writing of ring trust packets.
* g10/parse-packet.c (parse_trust): Rename to ...
(parse_ring_trust): this. Change args and implement new ring trust
packet format.
(parse): Add special ring trust packet handling.
* g10/packet.h (PKT_user_id): New fields KEYUPDATE, UPDATEURL, and
KEYSRC.
(PKT_public_key): Ditto.
(RING_TRUST_SIG, RING_TRUST_KEY, RING_TRUST_UID): New consts.
(PKT_ring_trust): New.
(struct packet_struct): Remove member RING_TRUST.
(strcu parse_packet_ctx_s): Add field SKIP_META.
(init_parse_packet): Init SKIPT_META.
* g10/free-packet.c (release_public_key_parts): Free UDPATEURL.
(free_user_id): Ditto.
* g10/mainproc.c (list_node): Remove printing of non-documented "rtv"
lines.
* g10/build-packet.c (build_packet_and_meta): New.
(do_ring_trust): New.
* g10/export.c (write_keyblock_to_output): Use build_packet_and_meta
in backup mode.
(do_export_one_keyblock): Ditto.
* g10/import.c (read_block): Add arg WITH_META. Skip ring trust
packets if that ism not set.
(import): Call read_block WITH_META in restore mode.
* g10/keydb.h (KEYSRC_UNKNOWN, KEYSRC_FILE, KEYSRC_KS, KEYSRC_PREF_KS)
(KEYSRC_WKD, KEYSRC_WKD_SD, KEYSRC_DANE): New constants. They are not
yet used, though.
* g10/keydb.c (parse_keyblock_image): Allow ring trust packets.
(build_keyblock_image): Ditto. Use build_packet_and_meta.
* g10/keyring.c (keyring_get_keyblock): Remove specila treatment of
ring trust packets.
(write_keyblock): Use build_packet_and_meta. Remove special treatment
of ring trust packets and initialization of the signature caches.
--
This patch introduced the framework to store meta data for keys and
user ids in the keyrings/keyboxes. Ring trust packets are
implementation defined and have always been used in gpg to cache the
signature verification status.
Ring trust packets are only exported with the export option "backup"
and only imported with the import option "restore".
The new code uses a cleaner way to handle the ring trust packets: When
the parser reads a ring trust packet and the previously read packet
matches the type of that ring trust packet, the information is stored
in that previously read packet (signature, user id, or primary key)
and the next packet is read immediately. Thus only the parser sees
the ring trust packets. Ring trust packets are written by using the
new function build_packet_and_meta instead of build_packet. That
function writes a ring trust packet when the needed information is
available.
As a side-effect of this patch the signature status cache works again
and "gpg --check-sigs" is thus much faster.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-03-30 09:07:02 +02:00
|
|
|
|
PACKET **pending_pkt, kbnode_t *ret_root, int *r_v3keys)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
int rc;
|
2017-03-29 10:02:40 +02:00
|
|
|
|
struct parse_packet_ctx_s parsectx;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
PACKET *pkt;
|
|
|
|
|
kbnode_t root = NULL;
|
2019-07-10 08:42:07 +02:00
|
|
|
|
kbnode_t lastnode = NULL;
|
2018-07-04 09:53:10 +02:00
|
|
|
|
int in_cert, in_v3key, skip_sigs;
|
2019-07-01 15:14:59 +02:00
|
|
|
|
u32 keyid[2];
|
2019-07-09 11:07:35 +02:00
|
|
|
|
int got_keyid = 0;
|
2019-07-01 15:14:59 +02:00
|
|
|
|
unsigned int dropped_nonselfsigs = 0;
|
2014-11-19 10:34:32 +01:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
*r_v3keys = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (*pending_pkt)
|
|
|
|
|
{
|
2019-07-10 08:42:07 +02:00
|
|
|
|
root = lastnode = new_kbnode( *pending_pkt );
|
2014-12-04 10:45:53 +01:00
|
|
|
|
*pending_pkt = NULL;
|
2019-07-09 11:07:35 +02:00
|
|
|
|
log_assert (root->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| root->pkt->pkttype == PKT_SECRET_KEY);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
in_cert = 1;
|
2019-07-09 11:07:35 +02:00
|
|
|
|
keyid_from_pk (root->pkt->pkt.public_key, keyid);
|
|
|
|
|
got_keyid = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else
|
|
|
|
|
in_cert = 0;
|
|
|
|
|
|
|
|
|
|
pkt = xmalloc (sizeof *pkt);
|
|
|
|
|
init_packet (pkt);
|
2017-03-29 10:02:40 +02:00
|
|
|
|
init_parse_packet (&parsectx, a);
|
2019-07-01 14:01:08 +02:00
|
|
|
|
if (!(options & IMPORT_RESTORE))
|
gpg: Revamp reading and writing of ring trust packets.
* g10/parse-packet.c (parse_trust): Rename to ...
(parse_ring_trust): this. Change args and implement new ring trust
packet format.
(parse): Add special ring trust packet handling.
* g10/packet.h (PKT_user_id): New fields KEYUPDATE, UPDATEURL, and
KEYSRC.
(PKT_public_key): Ditto.
(RING_TRUST_SIG, RING_TRUST_KEY, RING_TRUST_UID): New consts.
(PKT_ring_trust): New.
(struct packet_struct): Remove member RING_TRUST.
(strcu parse_packet_ctx_s): Add field SKIP_META.
(init_parse_packet): Init SKIPT_META.
* g10/free-packet.c (release_public_key_parts): Free UDPATEURL.
(free_user_id): Ditto.
* g10/mainproc.c (list_node): Remove printing of non-documented "rtv"
lines.
* g10/build-packet.c (build_packet_and_meta): New.
(do_ring_trust): New.
* g10/export.c (write_keyblock_to_output): Use build_packet_and_meta
in backup mode.
(do_export_one_keyblock): Ditto.
* g10/import.c (read_block): Add arg WITH_META. Skip ring trust
packets if that ism not set.
(import): Call read_block WITH_META in restore mode.
* g10/keydb.h (KEYSRC_UNKNOWN, KEYSRC_FILE, KEYSRC_KS, KEYSRC_PREF_KS)
(KEYSRC_WKD, KEYSRC_WKD_SD, KEYSRC_DANE): New constants. They are not
yet used, though.
* g10/keydb.c (parse_keyblock_image): Allow ring trust packets.
(build_keyblock_image): Ditto. Use build_packet_and_meta.
* g10/keyring.c (keyring_get_keyblock): Remove specila treatment of
ring trust packets.
(write_keyblock): Use build_packet_and_meta. Remove special treatment
of ring trust packets and initialization of the signature caches.
--
This patch introduced the framework to store meta data for keys and
user ids in the keyrings/keyboxes. Ring trust packets are
implementation defined and have always been used in gpg to cache the
signature verification status.
Ring trust packets are only exported with the export option "backup"
and only imported with the import option "restore".
The new code uses a cleaner way to handle the ring trust packets: When
the parser reads a ring trust packet and the previously read packet
matches the type of that ring trust packet, the information is stored
in that previously read packet (signature, user id, or primary key)
and the next packet is read immediately. Thus only the parser sees
the ring trust packets. Ring trust packets are written by using the
new function build_packet_and_meta instead of build_packet. That
function writes a ring trust packet when the needed information is
available.
As a side-effect of this patch the signature status cache works again
and "gpg --check-sigs" is thus much faster.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-03-30 09:07:02 +02:00
|
|
|
|
parsectx.skip_meta = 1;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
in_v3key = 0;
|
2018-07-04 09:53:10 +02:00
|
|
|
|
skip_sigs = 0;
|
2017-03-29 10:02:40 +02:00
|
|
|
|
while ((rc=parse_packet (&parsectx, pkt)) != -1)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2015-01-22 12:14:48 +01:00
|
|
|
|
if (rc && (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY
|
2014-12-04 10:45:53 +01:00
|
|
|
|
&& (pkt->pkttype == PKT_PUBLIC_KEY
|
2015-01-22 12:14:48 +01:00
|
|
|
|
|| pkt->pkttype == PKT_SECRET_KEY)))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
in_v3key = 1;
|
|
|
|
|
++*r_v3keys;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (pkt, &parsectx);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
init_packet (pkt);
|
|
|
|
|
continue;
|
2014-11-19 10:34:32 +01:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (rc ) /* (ignore errors) */
|
|
|
|
|
{
|
2018-07-04 09:53:10 +02:00
|
|
|
|
skip_sigs = 0;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_UNKNOWN_PACKET)
|
|
|
|
|
; /* Do not show a diagnostic. */
|
2018-07-04 09:53:10 +02:00
|
|
|
|
else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
|
|
|
|
|
&& (pkt->pkttype == PKT_USER_ID
|
|
|
|
|
|| pkt->pkttype == PKT_ATTRIBUTE))
|
|
|
|
|
{
|
|
|
|
|
/* This indicates a too large user id or attribute
|
|
|
|
|
* packet. We skip this packet and all following
|
|
|
|
|
* signatures. Sure, this won't allow to repair a
|
|
|
|
|
* garbled keyring in case one of the signatures belong
|
|
|
|
|
* to another user id. However, this better mitigates
|
|
|
|
|
* DoS using inserted user ids. */
|
|
|
|
|
skip_sigs = 1;
|
|
|
|
|
}
|
|
|
|
|
else if (gpg_err_code (rc) == GPG_ERR_INV_PACKET
|
|
|
|
|
&& (pkt->pkttype == PKT_OLD_COMMENT
|
|
|
|
|
|| pkt->pkttype == PKT_COMMENT))
|
|
|
|
|
; /* Ignore too large comment packets. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_error("read_block: read error: %s\n", gpg_strerror (rc) );
|
|
|
|
|
rc = GPG_ERR_INV_KEYRING;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
goto ready;
|
|
|
|
|
}
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (pkt, &parsectx);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
init_packet(pkt);
|
|
|
|
|
continue;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2024-01-24 18:23:02 +01:00
|
|
|
|
else if ((opt.import_options & IMPORT_IGNORE_ATTRIBUTES)
|
|
|
|
|
&& (pkt->pkttype == PKT_USER_ID || pkt->pkttype == PKT_ATTRIBUTE)
|
|
|
|
|
&& pkt->pkt.user_id->attrib_data)
|
|
|
|
|
{
|
|
|
|
|
skip_sigs = 1;
|
|
|
|
|
free_packet (pkt, &parsectx);
|
|
|
|
|
init_packet (pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2018-07-04 09:53:10 +02:00
|
|
|
|
if (skip_sigs)
|
|
|
|
|
{
|
|
|
|
|
if (pkt->pkttype == PKT_SIGNATURE)
|
|
|
|
|
{
|
|
|
|
|
free_packet (pkt, &parsectx);
|
|
|
|
|
init_packet (pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
skip_sigs = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-04 09:45:52 +02:00
|
|
|
|
if (in_v3key && !(pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| pkt->pkttype == PKT_SECRET_KEY))
|
|
|
|
|
{
|
|
|
|
|
free_packet (pkt, &parsectx);
|
|
|
|
|
init_packet(pkt);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
in_v3key = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2018-07-04 09:45:52 +02:00
|
|
|
|
if (!root && pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& IS_KEY_REV (pkt->pkt.signature) )
|
|
|
|
|
{
|
|
|
|
|
/* This is a revocation certificate which is handled in a
|
|
|
|
|
* special way. */
|
|
|
|
|
root = new_kbnode( pkt );
|
|
|
|
|
pkt = NULL;
|
|
|
|
|
goto ready;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Make a linked list of all packets. */
|
|
|
|
|
switch (pkt->pkttype)
|
|
|
|
|
{
|
|
|
|
|
case PKT_COMPRESSED:
|
|
|
|
|
if (check_compress_algo (pkt->pkt.compressed->algorithm))
|
|
|
|
|
{
|
|
|
|
|
rc = GPG_ERR_COMPR_ALGO;
|
|
|
|
|
goto ready;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
compress_filter_context_t *cfx = xmalloc_clear( sizeof *cfx );
|
|
|
|
|
pkt->pkt.compressed->buf = NULL;
|
|
|
|
|
if (push_compress_filter2 (a, cfx,
|
|
|
|
|
pkt->pkt.compressed->algorithm, 1))
|
|
|
|
|
xfree (cfx); /* e.g. in case of compression_algo NONE. */
|
|
|
|
|
}
|
|
|
|
|
free_packet (pkt, &parsectx);
|
|
|
|
|
init_packet(pkt);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case PKT_RING_TRUST:
|
|
|
|
|
/* Skip those packets unless we are in restore mode. */
|
|
|
|
|
if ((opt.import_options & IMPORT_RESTORE))
|
|
|
|
|
goto x_default;
|
|
|
|
|
free_packet (pkt, &parsectx);
|
|
|
|
|
init_packet(pkt);
|
|
|
|
|
break;
|
|
|
|
|
|
2019-07-01 15:14:59 +02:00
|
|
|
|
case PKT_SIGNATURE:
|
|
|
|
|
if (!in_cert)
|
|
|
|
|
goto x_default;
|
|
|
|
|
if (!(options & IMPORT_SELF_SIGS_ONLY))
|
|
|
|
|
goto x_default;
|
2019-07-09 11:07:35 +02:00
|
|
|
|
log_assert (got_keyid);
|
2019-07-01 15:14:59 +02:00
|
|
|
|
if (pkt->pkt.signature->keyid[0] == keyid[0]
|
|
|
|
|
&& pkt->pkt.signature->keyid[1] == keyid[1])
|
|
|
|
|
{ /* This is likely a self-signature. We import this one.
|
|
|
|
|
* Eventually we should use the ISSUER_FPR to compare
|
|
|
|
|
* self-signatures, but that will work only for v5 keys
|
|
|
|
|
* which are currently not even deployed.
|
|
|
|
|
* Note that we do not do any crypto verify here because
|
|
|
|
|
* that would defeat this very mitigation of DoS by
|
|
|
|
|
* importing a key with a huge amount of faked
|
|
|
|
|
* key-signatures. A verification will be done later in
|
|
|
|
|
* the processing anyway. Here we want a cheap an early
|
|
|
|
|
* way to drop non-self-signatures. */
|
|
|
|
|
goto x_default;
|
|
|
|
|
}
|
|
|
|
|
/* Skip this signature. */
|
|
|
|
|
dropped_nonselfsigs++;
|
|
|
|
|
free_packet (pkt, &parsectx);
|
|
|
|
|
init_packet(pkt);
|
|
|
|
|
break;
|
|
|
|
|
|
2018-07-04 09:45:52 +02:00
|
|
|
|
case PKT_PUBLIC_KEY:
|
|
|
|
|
case PKT_SECRET_KEY:
|
2019-07-09 11:07:35 +02:00
|
|
|
|
if (!got_keyid)
|
|
|
|
|
{
|
|
|
|
|
keyid_from_pk (pkt->pkt.public_key, keyid);
|
|
|
|
|
got_keyid = 1;
|
|
|
|
|
}
|
2019-07-01 15:14:59 +02:00
|
|
|
|
if (in_cert) /* Store this packet. */
|
2018-07-04 09:45:52 +02:00
|
|
|
|
{
|
|
|
|
|
*pending_pkt = pkt;
|
|
|
|
|
pkt = NULL;
|
|
|
|
|
goto ready;
|
|
|
|
|
}
|
|
|
|
|
in_cert = 1;
|
2019-07-01 15:14:59 +02:00
|
|
|
|
goto x_default;
|
|
|
|
|
|
2018-07-04 09:45:52 +02:00
|
|
|
|
default:
|
|
|
|
|
x_default:
|
|
|
|
|
if (in_cert && valid_keyblock_packet (pkt->pkttype))
|
|
|
|
|
{
|
|
|
|
|
if (!root )
|
2019-07-10 08:42:07 +02:00
|
|
|
|
root = lastnode = new_kbnode (pkt);
|
2018-07-04 09:45:52 +02:00
|
|
|
|
else
|
2019-07-10 08:42:07 +02:00
|
|
|
|
{
|
|
|
|
|
lastnode->next = new_kbnode (pkt);
|
|
|
|
|
lastnode = lastnode->next;
|
|
|
|
|
}
|
2018-07-04 09:45:52 +02:00
|
|
|
|
pkt = xmalloc (sizeof *pkt);
|
|
|
|
|
}
|
2018-09-07 06:01:52 +02:00
|
|
|
|
else
|
|
|
|
|
free_packet (pkt, &parsectx);
|
2018-07-04 09:45:52 +02:00
|
|
|
|
init_packet(pkt);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
ready:
|
|
|
|
|
if (rc == -1 && root )
|
|
|
|
|
rc = 0;
|
|
|
|
|
|
|
|
|
|
if (rc )
|
|
|
|
|
release_kbnode( root );
|
|
|
|
|
else
|
|
|
|
|
*ret_root = root;
|
2017-03-29 11:57:40 +02:00
|
|
|
|
free_packet (pkt, &parsectx);
|
|
|
|
|
deinit_parse_packet (&parsectx);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
xfree( pkt );
|
2019-07-01 15:14:59 +02:00
|
|
|
|
if (!rc && dropped_nonselfsigs && opt.verbose)
|
|
|
|
|
log_info ("key %s: number of dropped non-self-signatures: %u\n",
|
|
|
|
|
keystr (keyid), dropped_nonselfsigs);
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* Walk through the subkeys on a pk to find if we have the PKS
|
|
|
|
|
disease: multiple subkeys with their binding sigs stripped, and the
|
|
|
|
|
sig for the first subkey placed after the last subkey. That is,
|
|
|
|
|
instead of "pk uid sig sub1 bind1 sub2 bind2 sub3 bind3" we have
|
|
|
|
|
"pk uid sig sub1 sub2 sub3 bind1". We can't do anything about sub2
|
|
|
|
|
and sub3, as they are already lost, but we can try and rescue sub1
|
|
|
|
|
by reordering the keyblock so that it reads "pk uid sig sub1 bind1
|
|
|
|
|
sub2 sub3". Returns TRUE if the keyblock was modified. */
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
fix_pks_corruption (ctrl_t ctrl, kbnode_t keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
int changed = 0;
|
|
|
|
|
int keycount = 0;
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
kbnode_t last = NULL;
|
|
|
|
|
kbnode_t sknode=NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* First determine if we have the problem at all. Look for 2 or
|
|
|
|
|
more subkeys in a row, followed by a single binding sig. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
for (node=keyblock; node; last=node, node=node->next)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
keycount++;
|
|
|
|
|
if(!sknode)
|
|
|
|
|
sknode=node;
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 17:38:03 +02:00
|
|
|
|
&& IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
&& keycount >= 2
|
|
|
|
|
&& !node->next)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
/* We might have the problem, as this key has two subkeys in
|
|
|
|
|
a row without any intervening packets. */
|
|
|
|
|
|
|
|
|
|
/* Sanity check */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!last)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
/* Temporarily attach node to sknode. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
node->next = sknode->next;
|
|
|
|
|
sknode->next = node;
|
|
|
|
|
last->next = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* Note we aren't checking whether this binding sig is a
|
|
|
|
|
selfsig. This is not necessary here as the subkey and
|
|
|
|
|
binding sig will be rejected later if that is the
|
|
|
|
|
case. */
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (check_key_signature (ctrl, keyblock,node,NULL))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
/* Not a match, so undo the changes. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
sknode->next = node->next;
|
|
|
|
|
last->next = node;
|
|
|
|
|
node->next = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
/* Mark it good so we don't need to check it again */
|
|
|
|
|
sknode->flag |= NODE_GOOD_SELFSIG;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
changed = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2014-12-04 10:45:53 +01:00
|
|
|
|
keycount = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
/* Versions of GnuPG before 1.4.11 and 2.0.16 allowed to import bogus
|
|
|
|
|
direct key signatures. A side effect of this was that a later
|
|
|
|
|
import of the same good direct key signatures was not possible
|
|
|
|
|
because the cmp_signature check in merge_blocks considered them
|
|
|
|
|
equal. Although direct key signatures are now checked during
|
|
|
|
|
import, there might still be bogus signatures sitting in a keyring.
|
|
|
|
|
We need to detect and delete them before doing a merge. This
|
2010-08-31 17:58:39 +02:00
|
|
|
|
function returns the number of removed sigs. */
|
2010-05-07 15:13:56 +02:00
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
fix_bad_direct_key_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid)
|
2010-05-07 15:13:56 +02:00
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
for (node = keyblock->next; node; node=node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
break;
|
|
|
|
|
if (node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& IS_KEY_SIG (node->pkt->pkt.signature))
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
err = check_key_signature (ctrl, keyblock, node, NULL);
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if (err && gpg_err_code (err) != GPG_ERR_PUBKEY_ALGO )
|
|
|
|
|
{
|
|
|
|
|
/* If we don't know the error, we can't decide; this is
|
|
|
|
|
not a problem because cmp_signature can't compare the
|
|
|
|
|
signature either. */
|
|
|
|
|
log_info ("key %s: invalid direct key signature removed\n",
|
|
|
|
|
keystr (keyid));
|
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
count++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static void
|
2010-09-06 21:57:42 +02:00
|
|
|
|
print_import_ok (PKT_public_key *pk, unsigned int reason)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
byte array[MAX_FINGERPRINT_LEN], *s;
|
|
|
|
|
char buf[MAX_FINGERPRINT_LEN*2+30], *p;
|
|
|
|
|
size_t i, n;
|
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
snprintf (buf, sizeof buf, "%u ", reason);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
p = buf + strlen (buf);
|
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
fingerprint_from_pk (pk, array, &n);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
s = array;
|
|
|
|
|
for (i=0; i < n ; i++, s++, p += 2)
|
|
|
|
|
sprintf (p, "%02X", *s);
|
|
|
|
|
|
|
|
|
|
write_status_text (STATUS_IMPORT_OK, buf);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static void
|
2003-06-05 09:14:21 +02:00
|
|
|
|
print_import_check (PKT_public_key * pk, PKT_user_id * id)
|
|
|
|
|
{
|
2019-03-15 13:02:44 +01:00
|
|
|
|
byte hexfpr[2*MAX_FINGERPRINT_LEN+1];
|
2014-12-04 10:45:53 +01:00
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
|
|
|
|
keyid_from_pk (pk, keyid);
|
2019-03-15 13:02:44 +01:00
|
|
|
|
hexfingerprint (pk, hexfpr, sizeof hexfpr);
|
|
|
|
|
write_status_printf (STATUS_IMPORT_CHECK, "%08X%08X %s %s",
|
|
|
|
|
keyid[0], keyid[1], hexfpr, id->name);
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static void
|
|
|
|
|
check_prefs_warning(PKT_public_key *pk)
|
|
|
|
|
{
|
|
|
|
|
log_info(_("WARNING: key %s contains preferences for unavailable\n"
|
|
|
|
|
"algorithms on these user IDs:\n"), keystr_from_pk(pk));
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
static void
|
2010-10-01 22:33:53 +02:00
|
|
|
|
check_prefs (ctrl_t ctrl, kbnode_t keyblock)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2010-10-01 22:33:53 +02:00
|
|
|
|
kbnode_t node;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
int problem=0;
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
pk=keyblock->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
|
|
for(node=keyblock;node;node=node->next)
|
|
|
|
|
{
|
|
|
|
|
if(node->pkt->pkttype==PKT_USER_ID
|
|
|
|
|
&& node->pkt->pkt.user_id->created
|
|
|
|
|
&& node->pkt->pkt.user_id->prefs)
|
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
prefitem_t *prefs = uid->prefs;
|
|
|
|
|
char *user = utf8_to_native(uid->name,strlen(uid->name),0);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
|
|
|
|
for(;prefs->type;prefs++)
|
|
|
|
|
{
|
|
|
|
|
char num[10]; /* prefs->value is a byte, so we're over
|
|
|
|
|
safe here */
|
|
|
|
|
|
|
|
|
|
sprintf(num,"%u",prefs->value);
|
|
|
|
|
|
|
|
|
|
if(prefs->type==PREFTYPE_SYM)
|
|
|
|
|
{
|
2006-05-23 18:19:43 +02:00
|
|
|
|
if (openpgp_cipher_test_algo (prefs->value))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2011-02-02 15:48:54 +01:00
|
|
|
|
const char *algo =
|
2007-12-12 11:28:30 +01:00
|
|
|
|
(openpgp_cipher_test_algo (prefs->value)
|
2011-02-02 15:48:54 +01:00
|
|
|
|
? num
|
2007-12-12 11:28:30 +01:00
|
|
|
|
: openpgp_cipher_algo_name (prefs->value));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
if(!problem)
|
|
|
|
|
check_prefs_warning(pk);
|
|
|
|
|
log_info(_(" \"%s\": preference for cipher"
|
2007-02-26 21:24:29 +01:00
|
|
|
|
" algorithm %s\n"), user, algo);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
problem=1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-01-23 12:07:25 +01:00
|
|
|
|
else if(prefs->type==PREFTYPE_AEAD)
|
|
|
|
|
{
|
|
|
|
|
if (openpgp_aead_test_algo (prefs->value))
|
|
|
|
|
{
|
|
|
|
|
/* FIXME: The test below is wrong. We should
|
|
|
|
|
* check if ...algo_name yields a "?" and
|
|
|
|
|
* only in that case use NUM. */
|
|
|
|
|
const char *algo =
|
|
|
|
|
(openpgp_aead_test_algo (prefs->value)
|
|
|
|
|
? num
|
|
|
|
|
: openpgp_aead_algo_name (prefs->value));
|
|
|
|
|
if(!problem)
|
|
|
|
|
check_prefs_warning(pk);
|
|
|
|
|
log_info(_(" \"%s\": preference for AEAD"
|
|
|
|
|
" algorithm %s\n"), user, algo);
|
|
|
|
|
problem=1;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
else if(prefs->type==PREFTYPE_HASH)
|
|
|
|
|
{
|
2006-04-19 15:24:36 +02:00
|
|
|
|
if(openpgp_md_test_algo(prefs->value))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2007-02-26 21:24:29 +01:00
|
|
|
|
const char *algo =
|
|
|
|
|
(gcry_md_test_algo (prefs->value)
|
2011-02-02 15:48:54 +01:00
|
|
|
|
? num
|
2007-02-26 21:24:29 +01:00
|
|
|
|
: gcry_md_algo_name (prefs->value));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
if(!problem)
|
|
|
|
|
check_prefs_warning(pk);
|
|
|
|
|
log_info(_(" \"%s\": preference for digest"
|
2007-02-26 21:24:29 +01:00
|
|
|
|
" algorithm %s\n"), user, algo);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
problem=1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(prefs->type==PREFTYPE_ZIP)
|
|
|
|
|
{
|
2006-04-19 15:24:36 +02:00
|
|
|
|
if(check_compress_algo (prefs->value))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
|
|
|
|
const char *algo=compress_algo_to_string(prefs->value);
|
|
|
|
|
if(!problem)
|
|
|
|
|
check_prefs_warning(pk);
|
|
|
|
|
log_info(_(" \"%s\": preference for compression"
|
|
|
|
|
" algorithm %s\n"),user,algo?algo:num);
|
|
|
|
|
problem=1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xfree(user);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(problem)
|
|
|
|
|
{
|
|
|
|
|
log_info(_("it is strongly suggested that you update"
|
|
|
|
|
" your preferences and\n"));
|
|
|
|
|
log_info(_("re-distribute this key to avoid potential algorithm"
|
|
|
|
|
" mismatch problems\n"));
|
|
|
|
|
|
|
|
|
|
if(!opt.batch)
|
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
strlist_t sl = NULL;
|
|
|
|
|
strlist_t locusr = NULL;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
size_t fprlen=0;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
byte fpr[MAX_FINGERPRINT_LEN], *p;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
char username[(MAX_FINGERPRINT_LEN*2)+1];
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
p = fingerprint_from_pk (pk,fpr,&fprlen);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
for(i=0;i<fprlen;i++,p++)
|
|
|
|
|
sprintf(username+2*i,"%02X",*p);
|
|
|
|
|
add_to_strlist(&locusr,username);
|
|
|
|
|
|
|
|
|
|
append_to_strlist(&sl,"updpref");
|
|
|
|
|
append_to_strlist(&sl,"save");
|
|
|
|
|
|
2010-10-01 22:33:53 +02:00
|
|
|
|
keyedit_menu (ctrl, username, locusr, sl, 1, 1 );
|
2006-04-19 13:26:11 +02:00
|
|
|
|
free_strlist(sl);
|
|
|
|
|
free_strlist(locusr);
|
|
|
|
|
}
|
|
|
|
|
else if(!opt.quiet)
|
|
|
|
|
log_info(_("you can update your preferences with:"
|
|
|
|
|
" gpg --edit-key %s updpref save\n"),keystr_from_pk(pk));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2022-11-25 16:04:54 +01:00
|
|
|
|
/* Helper for apply_*_filter in import.c and export.c and also used by
|
|
|
|
|
* keylist.c. */
|
2016-09-05 08:31:25 +02:00
|
|
|
|
const char *
|
|
|
|
|
impex_filter_getval (void *cookie, const char *propname)
|
2016-07-01 16:24:04 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
/* FIXME: Malloc our static buffers and access them via PARM. */
|
|
|
|
|
struct impex_filter_parm_s *parm = cookie;
|
|
|
|
|
ctrl_t ctrl = parm->ctrl;
|
|
|
|
|
kbnode_t node = parm->node;
|
2016-08-18 16:15:49 +02:00
|
|
|
|
static char numbuf[20];
|
2016-07-01 16:24:04 +02:00
|
|
|
|
const char *result;
|
2022-11-25 16:04:54 +01:00
|
|
|
|
const char *s;
|
|
|
|
|
enum { scpNone = 0, scpPub, scpSub, scpUid, scpSig} scope = 0;
|
2016-07-01 16:24:04 +02:00
|
|
|
|
|
2017-03-31 20:06:54 +02:00
|
|
|
|
log_assert (ctrl && ctrl->magic == SERVER_CONTROL_MAGIC);
|
|
|
|
|
|
2022-11-25 16:04:54 +01:00
|
|
|
|
/* We allow a prefix delimited by a slash to limit the scope of the
|
|
|
|
|
* keyword. Note that "pub" also includes "sec" and "sub" includes
|
|
|
|
|
* "ssb". */
|
|
|
|
|
if ((s=strchr (propname, '/')) && s != propname)
|
|
|
|
|
{
|
|
|
|
|
size_t n = s - propname;
|
|
|
|
|
if (!strncmp (propname, "pub", n))
|
|
|
|
|
scope = scpPub;
|
|
|
|
|
else if (!strncmp (propname, "sub", n))
|
|
|
|
|
scope = scpSub;
|
|
|
|
|
else if (!strncmp (propname, "uid", n))
|
|
|
|
|
scope = scpUid;
|
|
|
|
|
else if (!strncmp (propname, "sig", n))
|
|
|
|
|
scope = scpSig;
|
|
|
|
|
|
|
|
|
|
propname = s + 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((node->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
|| node->pkt->pkttype == PKT_ATTRIBUTE)
|
|
|
|
|
&& (!scope || scope == scpUid))
|
2016-07-01 16:24:04 +02:00
|
|
|
|
{
|
2017-03-03 09:22:40 +01:00
|
|
|
|
PKT_user_id *uid = node->pkt->pkt.user_id;
|
|
|
|
|
|
2016-07-01 16:24:04 +02:00
|
|
|
|
if (!strcmp (propname, "uid"))
|
2017-03-03 09:22:40 +01:00
|
|
|
|
result = uid->name;
|
2016-07-01 16:24:04 +02:00
|
|
|
|
else if (!strcmp (propname, "mbox"))
|
|
|
|
|
{
|
2017-03-03 09:22:40 +01:00
|
|
|
|
if (!uid->mbox)
|
2016-07-01 16:24:04 +02:00
|
|
|
|
{
|
2018-11-12 07:44:33 +01:00
|
|
|
|
uid->mbox = mailbox_from_userid (uid->name, 0);
|
2016-07-01 16:24:04 +02:00
|
|
|
|
}
|
2017-03-03 09:22:40 +01:00
|
|
|
|
result = uid->mbox;
|
2016-07-01 16:24:04 +02:00
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "primary"))
|
2017-03-03 09:22:40 +01:00
|
|
|
|
{
|
2017-03-08 11:01:22 +01:00
|
|
|
|
result = uid->flags.primary? "1":"0";
|
2017-03-03 09:22:40 +01:00
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "expired"))
|
|
|
|
|
{
|
2017-03-08 11:01:22 +01:00
|
|
|
|
result = uid->flags.expired? "1":"0";
|
2017-03-03 09:22:40 +01:00
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "revoked"))
|
|
|
|
|
{
|
2017-03-08 11:01:22 +01:00
|
|
|
|
result = uid->flags.revoked? "1":"0";
|
2017-03-03 09:22:40 +01:00
|
|
|
|
}
|
2016-07-01 16:24:04 +02:00
|
|
|
|
else
|
|
|
|
|
result = NULL;
|
|
|
|
|
}
|
2022-11-25 16:04:54 +01:00
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& (!scope || scope == scpSig))
|
2016-08-18 16:15:49 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_signature *sig = node->pkt->pkt.signature;
|
|
|
|
|
|
|
|
|
|
if (!strcmp (propname, "sig_created"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)sig->timestamp);
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "sig_created_d"))
|
|
|
|
|
{
|
2020-02-13 14:01:07 +01:00
|
|
|
|
result = dateonlystr_from_sig (sig);
|
2016-08-18 16:15:49 +02:00
|
|
|
|
}
|
2023-09-02 18:59:43 +02:00
|
|
|
|
else if (!strcmp (propname, "sig_expires"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)sig->expiredate);
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "sig_expires_d"))
|
|
|
|
|
{
|
|
|
|
|
static char exdatestr[MK_DATESTR_SIZE];
|
|
|
|
|
|
|
|
|
|
if (sig->expiredate)
|
|
|
|
|
result = mk_datestr (exdatestr, sizeof exdatestr, sig->expiredate);
|
|
|
|
|
else
|
|
|
|
|
result = "";
|
|
|
|
|
}
|
2016-08-18 16:15:49 +02:00
|
|
|
|
else if (!strcmp (propname, "sig_algo"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%d", sig->pubkey_algo);
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "sig_digest_algo"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%d", sig->digest_algo);
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
2017-03-03 09:22:40 +01:00
|
|
|
|
else if (!strcmp (propname, "expired"))
|
|
|
|
|
{
|
|
|
|
|
result = sig->flags.expired? "1":"0";
|
|
|
|
|
}
|
2016-08-18 16:15:49 +02:00
|
|
|
|
else
|
|
|
|
|
result = NULL;
|
|
|
|
|
}
|
2022-11-25 16:04:54 +01:00
|
|
|
|
else if (((node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_KEY)
|
|
|
|
|
&& (!scope || scope == scpPub))
|
|
|
|
|
|| ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
&& (!scope || scope == scpSub)))
|
2016-09-05 09:51:16 +02:00
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk = node->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
|
|
if (!strcmp (propname, "secret"))
|
|
|
|
|
{
|
|
|
|
|
result = (node->pkt->pkttype == PKT_SECRET_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)? "1":"0";
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "key_algo"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%d", pk->pubkey_algo);
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
2022-11-25 16:04:54 +01:00
|
|
|
|
else if (!strcmp (propname, "key_size"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%u", nbits_from_pk (pk));
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "algostr"))
|
|
|
|
|
{
|
|
|
|
|
pubkey_string (pk, parm->hexfpr, sizeof parm->hexfpr);
|
|
|
|
|
result = parm->hexfpr;
|
|
|
|
|
}
|
2017-04-17 02:08:31 +02:00
|
|
|
|
else if (!strcmp (propname, "key_created"))
|
2016-09-05 09:51:16 +02:00
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->timestamp);
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "key_created_d"))
|
|
|
|
|
{
|
2020-02-13 14:01:07 +01:00
|
|
|
|
result = dateonlystr_from_pk (pk);
|
2016-09-05 09:51:16 +02:00
|
|
|
|
}
|
2023-06-09 16:16:56 +02:00
|
|
|
|
else if (!strcmp (propname, "key_expires"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->expiredate);
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "key_expires_d"))
|
|
|
|
|
{
|
|
|
|
|
static char exdatestr[MK_DATESTR_SIZE];
|
|
|
|
|
|
|
|
|
|
if (pk->expiredate)
|
|
|
|
|
result = mk_datestr (exdatestr, sizeof exdatestr, pk->expiredate);
|
|
|
|
|
else
|
|
|
|
|
result = "";
|
|
|
|
|
}
|
2017-03-03 09:22:40 +01:00
|
|
|
|
else if (!strcmp (propname, "expired"))
|
|
|
|
|
{
|
|
|
|
|
result = pk->has_expired? "1":"0";
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "revoked"))
|
|
|
|
|
{
|
|
|
|
|
result = pk->flags.revoked? "1":"0";
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "disabled"))
|
|
|
|
|
{
|
|
|
|
|
result = pk_is_disabled (pk)? "1":"0";
|
|
|
|
|
}
|
2018-06-12 06:41:59 +02:00
|
|
|
|
else if (!strcmp (propname, "usage"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%s%s%s%s%s",
|
|
|
|
|
(pk->pubkey_usage & PUBKEY_USAGE_ENC)?"e":"",
|
|
|
|
|
(pk->pubkey_usage & PUBKEY_USAGE_SIG)?"s":"",
|
|
|
|
|
(pk->pubkey_usage & PUBKEY_USAGE_CERT)?"c":"",
|
|
|
|
|
(pk->pubkey_usage & PUBKEY_USAGE_AUTH)?"a":"",
|
|
|
|
|
(pk->pubkey_usage & PUBKEY_USAGE_UNKNOWN)?"?":"");
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
2020-03-13 13:17:51 +01:00
|
|
|
|
else if (!strcmp (propname, "fpr"))
|
|
|
|
|
{
|
|
|
|
|
hexfingerprint (pk, parm->hexfpr, sizeof parm->hexfpr);
|
|
|
|
|
result = parm->hexfpr;
|
|
|
|
|
}
|
2022-11-25 16:04:54 +01:00
|
|
|
|
else if (!strcmp (propname, "origin"))
|
|
|
|
|
{
|
|
|
|
|
result = key_origin_string (pk->keyorg);
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "lastupd"))
|
|
|
|
|
{
|
|
|
|
|
snprintf (numbuf, sizeof numbuf, "%lu", (ulong)pk->keyupdate);
|
|
|
|
|
result = numbuf;
|
|
|
|
|
}
|
|
|
|
|
else if (!strcmp (propname, "url"))
|
|
|
|
|
{
|
|
|
|
|
if (pk->updateurl && *pk->updateurl)
|
|
|
|
|
{
|
|
|
|
|
/* Fixme: This might get truncated. */
|
|
|
|
|
mem2str (parm->hexfpr, pk->updateurl, sizeof parm->hexfpr);
|
|
|
|
|
result = parm->hexfpr;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
result = "";
|
|
|
|
|
}
|
2016-09-05 09:51:16 +02:00
|
|
|
|
else
|
|
|
|
|
result = NULL;
|
|
|
|
|
}
|
2016-07-01 16:24:04 +02:00
|
|
|
|
else
|
|
|
|
|
result = NULL;
|
|
|
|
|
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-18 16:15:49 +02:00
|
|
|
|
|
2016-07-01 16:24:04 +02:00
|
|
|
|
/*
|
|
|
|
|
* Apply the keep-uid filter to the keyblock. The deleted nodes are
|
|
|
|
|
* marked and thus the caller should call commit_kbnode afterwards.
|
|
|
|
|
* KEYBLOCK must not have any blocks marked as deleted.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2017-03-31 20:03:52 +02:00
|
|
|
|
apply_keep_uid_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector)
|
2016-07-01 16:24:04 +02:00
|
|
|
|
{
|
|
|
|
|
kbnode_t node;
|
2017-03-31 20:03:52 +02:00
|
|
|
|
struct impex_filter_parm_s parm;
|
|
|
|
|
|
|
|
|
|
parm.ctrl = ctrl;
|
2016-07-01 16:24:04 +02:00
|
|
|
|
|
|
|
|
|
for (node = keyblock->next; node; node = node->next )
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
parm.node = node;
|
|
|
|
|
if (!recsel_select (selector, impex_filter_getval, &parm))
|
2016-07-01 16:24:04 +02:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
/* log_debug ("keep-uid: deleting '%s'\n", */
|
|
|
|
|
/* node->pkt->pkt.user_id->name); */
|
|
|
|
|
/* The UID packet and all following packets up to the
|
|
|
|
|
* next UID or a subkey. */
|
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
for (; node->next
|
|
|
|
|
&& node->next->pkt->pkttype != PKT_USER_ID
|
|
|
|
|
&& node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& node->next->pkt->pkttype != PKT_SECRET_SUBKEY ;
|
|
|
|
|
node = node->next)
|
|
|
|
|
delete_kbnode (node->next);
|
|
|
|
|
}
|
|
|
|
|
/* else */
|
|
|
|
|
/* log_debug ("keep-uid: keeping '%s'\n", */
|
|
|
|
|
/* node->pkt->pkt.user_id->name); */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-08-18 16:15:49 +02:00
|
|
|
|
/*
|
|
|
|
|
* Apply the drop-sig filter to the keyblock. The deleted nodes are
|
|
|
|
|
* marked and thus the caller should call commit_kbnode afterwards.
|
|
|
|
|
* KEYBLOCK must not have any blocks marked as deleted.
|
|
|
|
|
*/
|
|
|
|
|
static void
|
2017-03-31 20:03:52 +02:00
|
|
|
|
apply_drop_sig_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector)
|
2016-08-18 16:15:49 +02:00
|
|
|
|
{
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
int active = 0;
|
|
|
|
|
u32 main_keyid[2];
|
|
|
|
|
PKT_signature *sig;
|
2017-03-31 20:03:52 +02:00
|
|
|
|
struct impex_filter_parm_s parm;
|
|
|
|
|
|
|
|
|
|
parm.ctrl = ctrl;
|
2016-08-18 16:15:49 +02:00
|
|
|
|
|
|
|
|
|
keyid_from_pk (keyblock->pkt->pkt.public_key, main_keyid);
|
|
|
|
|
|
|
|
|
|
/* Loop over all signatures for user id and attribute packets which
|
|
|
|
|
* are not self signatures. */
|
|
|
|
|
for (node = keyblock->next; node; node = node->next )
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
break; /* ready. */
|
2017-03-03 09:50:40 +01:00
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
|| node->pkt->pkttype == PKT_ATTRIBUTE)
|
2016-08-18 16:15:49 +02:00
|
|
|
|
active = 1;
|
|
|
|
|
if (!active)
|
|
|
|
|
continue;
|
2017-03-03 09:50:40 +01:00
|
|
|
|
if (node->pkt->pkttype != PKT_SIGNATURE)
|
2016-08-18 16:15:49 +02:00
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
sig = node->pkt->pkt.signature;
|
|
|
|
|
if (main_keyid[0] == sig->keyid[0] || main_keyid[1] == sig->keyid[1])
|
|
|
|
|
continue; /* Skip self-signatures. */
|
|
|
|
|
|
|
|
|
|
if (IS_UID_SIG(sig) || IS_UID_REV(sig))
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
parm.node = node;
|
|
|
|
|
if (recsel_select (selector, impex_filter_getval, &parm))
|
2016-08-18 16:15:49 +02:00
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
/* Insert a key origin into a public key packet. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
insert_key_origin_pk (PKT_public_key *pk, u32 curtime,
|
|
|
|
|
int origin, const char *url)
|
|
|
|
|
{
|
|
|
|
|
if (origin == KEYORG_WKD || origin == KEYORG_DANE)
|
|
|
|
|
{
|
|
|
|
|
/* For WKD and DANE we insert origin information also for the
|
|
|
|
|
* key but we don't record the URL because we have have no use
|
|
|
|
|
* for that: An update using a keyserver has higher precedence
|
|
|
|
|
* and will thus update this origin info. For refresh using WKD
|
|
|
|
|
* or DANE we need to go via the User ID anyway. Recall that we
|
|
|
|
|
* are only inserting a new key. */
|
|
|
|
|
pk->keyorg = origin;
|
|
|
|
|
pk->keyupdate = curtime;
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_KS && url)
|
|
|
|
|
{
|
|
|
|
|
/* If the key was retrieved from a keyserver using a fingerprint
|
|
|
|
|
* request we add the meta information. Note that the use of a
|
|
|
|
|
* fingerprint needs to be enforced by the caller of the import
|
|
|
|
|
* function. This is commonly triggered by verifying a modern
|
|
|
|
|
* signature which has an Issuer Fingerprint signature
|
|
|
|
|
* subpacket. */
|
|
|
|
|
pk->keyorg = origin;
|
|
|
|
|
pk->keyupdate = curtime;
|
|
|
|
|
xfree (pk->updateurl);
|
|
|
|
|
pk->updateurl = xtrystrdup (url);
|
|
|
|
|
if (!pk->updateurl)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_FILE)
|
|
|
|
|
{
|
|
|
|
|
pk->keyorg = origin;
|
|
|
|
|
pk->keyupdate = curtime;
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_URL)
|
|
|
|
|
{
|
|
|
|
|
pk->keyorg = origin;
|
|
|
|
|
pk->keyupdate = curtime;
|
|
|
|
|
if (url)
|
|
|
|
|
{
|
|
|
|
|
xfree (pk->updateurl);
|
|
|
|
|
pk->updateurl = xtrystrdup (url);
|
|
|
|
|
if (!pk->updateurl)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Insert a key origin into a user id packet. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
insert_key_origin_uid (PKT_user_id *uid, u32 curtime,
|
|
|
|
|
int origin, const char *url)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
if (origin == KEYORG_WKD || origin == KEYORG_DANE)
|
|
|
|
|
{
|
|
|
|
|
/* We insert origin information on a UID only when we received
|
|
|
|
|
* them via the Web Key Directory or a DANE record. The key we
|
|
|
|
|
* receive here from the WKD has been filtered to contain only
|
|
|
|
|
* the user ID as looked up in the WKD. For a DANE origin we
|
|
|
|
|
* this should also be the case. Thus we will see here only one
|
|
|
|
|
* user id. */
|
|
|
|
|
uid->keyorg = origin;
|
|
|
|
|
uid->keyupdate = curtime;
|
|
|
|
|
if (url)
|
|
|
|
|
{
|
|
|
|
|
xfree (uid->updateurl);
|
|
|
|
|
uid->updateurl = xtrystrdup (url);
|
|
|
|
|
if (!uid->updateurl)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_KS && url)
|
|
|
|
|
{
|
|
|
|
|
/* If the key was retrieved from a keyserver using a fingerprint
|
|
|
|
|
* request we mark that also in the user ID. However we do not
|
|
|
|
|
* store the keyserver URL in the UID. A later update (merge)
|
|
|
|
|
* from a more trusted source will replace this info. */
|
|
|
|
|
uid->keyorg = origin;
|
|
|
|
|
uid->keyupdate = curtime;
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_FILE)
|
|
|
|
|
{
|
|
|
|
|
uid->keyorg = origin;
|
|
|
|
|
uid->keyupdate = curtime;
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_URL)
|
|
|
|
|
{
|
|
|
|
|
uid->keyorg = origin;
|
|
|
|
|
uid->keyupdate = curtime;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-07-13 18:22:36 +02:00
|
|
|
|
/* Apply meta data to KEYBLOCK. This sets the origin of the key to
|
2017-07-24 20:05:28 +02:00
|
|
|
|
* ORIGIN and the updateurl to URL. Note that this function is only
|
|
|
|
|
* used for a new key, that is not when we are merging keys. */
|
2017-07-13 18:22:36 +02:00
|
|
|
|
static gpg_error_t
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
insert_key_origin (kbnode_t keyblock, int origin, const char *url)
|
2017-07-13 18:22:36 +02:00
|
|
|
|
{
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
gpg_error_t err;
|
2017-07-24 20:05:28 +02:00
|
|
|
|
kbnode_t node;
|
|
|
|
|
u32 curtime = make_timestamp ();
|
|
|
|
|
|
|
|
|
|
for (node = keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (is_deleted_kbnode (node))
|
|
|
|
|
;
|
2017-07-24 20:47:41 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
2017-07-24 20:05:28 +02:00
|
|
|
|
{
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
err = insert_key_origin_pk (node->pkt->pkt.public_key, curtime,
|
|
|
|
|
origin, url);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2017-07-24 20:05:28 +02:00
|
|
|
|
}
|
2017-07-24 20:47:41 +02:00
|
|
|
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
2017-07-24 20:05:28 +02:00
|
|
|
|
{
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
err = insert_key_origin_uid (node->pkt->pkt.user_id, curtime,
|
|
|
|
|
origin, url);
|
|
|
|
|
if (err)
|
|
|
|
|
return err;
|
2017-07-24 20:05:28 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-13 18:22:36 +02:00
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-07-25 11:23:08 +02:00
|
|
|
|
/* Update meta data on KEYBLOCK. This updates the key origin on the
|
|
|
|
|
* public key according to ORIGIN and URL. The UIDs are already
|
|
|
|
|
* updated when this function is called. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url)
|
|
|
|
|
{
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
|
|
|
|
|
log_assert (keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
|
|
|
|
pk = keyblock->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
|
|
if (pk->keyupdate > curtime)
|
|
|
|
|
; /* Don't do it for a time warp. */
|
|
|
|
|
else if (origin == KEYORG_WKD || origin == KEYORG_DANE)
|
|
|
|
|
{
|
|
|
|
|
/* We only update the origin info if they either have never been
|
|
|
|
|
* set or are the origin was the same as the new one. If this
|
|
|
|
|
* is WKD we also update the UID to show from which user id this
|
|
|
|
|
* was updated. */
|
|
|
|
|
if (!pk->keyorg || pk->keyorg == KEYORG_WKD || pk->keyorg == KEYORG_DANE)
|
|
|
|
|
{
|
|
|
|
|
pk->keyorg = origin;
|
|
|
|
|
pk->keyupdate = curtime;
|
|
|
|
|
xfree (pk->updateurl);
|
|
|
|
|
pk->updateurl = NULL;
|
|
|
|
|
if (origin == KEYORG_WKD && url)
|
|
|
|
|
{
|
|
|
|
|
pk->updateurl = xtrystrdup (url);
|
|
|
|
|
if (!pk->updateurl)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_KS)
|
|
|
|
|
{
|
|
|
|
|
/* All updates from a keyserver are considered to have the
|
|
|
|
|
* freshed key. Thus we always set the new key origin. */
|
|
|
|
|
pk->keyorg = origin;
|
|
|
|
|
pk->keyupdate = curtime;
|
|
|
|
|
xfree (pk->updateurl);
|
|
|
|
|
pk->updateurl = NULL;
|
|
|
|
|
if (url)
|
|
|
|
|
{
|
|
|
|
|
pk->updateurl = xtrystrdup (url);
|
|
|
|
|
if (!pk->updateurl)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_FILE)
|
|
|
|
|
{
|
|
|
|
|
/* Updates from a file are considered to be fresh. */
|
|
|
|
|
pk->keyorg = origin;
|
|
|
|
|
pk->keyupdate = curtime;
|
|
|
|
|
xfree (pk->updateurl);
|
|
|
|
|
pk->updateurl = NULL;
|
|
|
|
|
}
|
|
|
|
|
else if (origin == KEYORG_URL)
|
|
|
|
|
{
|
|
|
|
|
/* Updates from a URL are considered to be fresh. */
|
|
|
|
|
pk->keyorg = origin;
|
|
|
|
|
pk->keyupdate = curtime;
|
|
|
|
|
xfree (pk->updateurl);
|
|
|
|
|
pk->updateurl = NULL;
|
|
|
|
|
if (url)
|
|
|
|
|
{
|
|
|
|
|
pk->updateurl = xtrystrdup (url);
|
|
|
|
|
if (!pk->updateurl)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/*
|
2014-06-05 11:19:59 +02:00
|
|
|
|
* Try to import one keyblock. Return an error only in serious cases,
|
|
|
|
|
* but never for an invalid keyblock. It uses log_error to increase
|
|
|
|
|
* the internal errorcount, so that invalid input can be detected by
|
|
|
|
|
* programs which called gpg. If SILENT is no messages are printed -
|
2017-07-13 18:22:36 +02:00
|
|
|
|
* even most error messages are suppressed. ORIGIN is the origin of
|
2019-03-15 19:11:32 +01:00
|
|
|
|
* the key (0 for unknown) and URL the corresponding URL. FROM_SK
|
2019-03-15 19:50:37 +01:00
|
|
|
|
* indicates that the key has been made from a secret key. If R_SAVED
|
2022-10-28 09:29:30 +02:00
|
|
|
|
* is not NULL a boolean will be stored indicating whether the
|
|
|
|
|
* keyblock has valid parts. Unless OTHERREVSIGS is NULL it is
|
|
|
|
|
* updated with encountered new revocation signatures.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
2017-10-18 13:09:47 +02:00
|
|
|
|
static gpg_error_t
|
2019-07-01 21:53:55 +02:00
|
|
|
|
import_one_real (ctrl_t ctrl,
|
|
|
|
|
kbnode_t keyblock, struct import_stats_s *stats,
|
|
|
|
|
unsigned char **fpr, size_t *fpr_len, unsigned int options,
|
|
|
|
|
int from_sk, int silent,
|
|
|
|
|
import_screener_t screener, void *screener_arg,
|
2022-10-28 09:29:30 +02:00
|
|
|
|
int origin, const char *url, int *r_valid,
|
|
|
|
|
kbnode_t *otherrevsigs)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
gpg_error_t err = 0;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
kbnode_t node, uidnode;
|
|
|
|
|
kbnode_t keyblock_orig = NULL;
|
|
|
|
|
byte fpr2[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t fpr2len;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
int new_key = 0;
|
|
|
|
|
int mod_key = 0;
|
|
|
|
|
int same_key = 0;
|
|
|
|
|
int non_self = 0;
|
|
|
|
|
size_t an;
|
|
|
|
|
char pkstrbuf[PUBKEY_STRING_SIZE];
|
2016-06-24 13:11:37 +02:00
|
|
|
|
int merge_keys_done = 0;
|
2016-09-28 15:32:04 +02:00
|
|
|
|
int any_filter = 0;
|
2017-10-18 13:09:47 +02:00
|
|
|
|
KEYDB_HANDLE hd = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2019-03-15 19:50:37 +01:00
|
|
|
|
if (r_valid)
|
|
|
|
|
*r_valid = 0;
|
|
|
|
|
|
2018-06-06 11:50:58 +02:00
|
|
|
|
/* If show-only is active we don't won't any extra output. */
|
|
|
|
|
if ((options & (IMPORT_SHOW | IMPORT_DRY_RUN)))
|
|
|
|
|
silent = 1;
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* Get the key and print some info about it. */
|
|
|
|
|
node = find_kbnode( keyblock, PKT_PUBLIC_KEY );
|
|
|
|
|
if (!node )
|
|
|
|
|
BUG();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
pk = node->pkt->pkt.public_key;
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
fingerprint_from_pk (pk, fpr2, &fpr2len);
|
|
|
|
|
for (an = fpr2len; an < MAX_FINGERPRINT_LEN; an++)
|
|
|
|
|
fpr2[an] = 0;
|
|
|
|
|
keyid_from_pk( pk, keyid );
|
|
|
|
|
uidnode = find_next_kbnode( keyblock, PKT_USER_ID );
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2019-03-15 19:11:32 +01:00
|
|
|
|
if (opt.verbose && !opt.interactive && !silent && !from_sk)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2019-03-15 19:11:32 +01:00
|
|
|
|
/* Note that we do not print this info in FROM_SK mode
|
2019-03-15 19:50:37 +01:00
|
|
|
|
* because import_secret_one already printed that. */
|
2019-03-15 19:11:32 +01:00
|
|
|
|
log_info ("pub %s/%s %s ",
|
2014-12-04 10:45:53 +01:00
|
|
|
|
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
|
|
|
|
|
keystr_from_pk(pk), datestr_from_pk(pk) );
|
|
|
|
|
if (uidnode)
|
|
|
|
|
print_utf8_buffer (log_get_stream (),
|
|
|
|
|
uidnode->pkt->pkt.user_id->name,
|
|
|
|
|
uidnode->pkt->pkt.user_id->len );
|
|
|
|
|
log_printf ("\n");
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2008-04-08 13:04:16 +02:00
|
|
|
|
|
2021-02-02 12:57:00 +01:00
|
|
|
|
if (!uidnode)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
if (!silent)
|
|
|
|
|
log_error( _("key %s: no user ID\n"), keystr_from_pk(pk));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (screener && screener (keyblock, screener_arg))
|
|
|
|
|
{
|
|
|
|
|
log_error (_("key %s: %s\n"), keystr_from_pk (pk),
|
|
|
|
|
_("rejected by import screener"));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2014-08-14 15:20:53 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (opt.interactive && !silent)
|
|
|
|
|
{
|
|
|
|
|
if (is_status_enabled())
|
|
|
|
|
print_import_check (pk, uidnode->pkt->pkt.user_id);
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
tty_printf ("\n");
|
2019-03-15 19:11:32 +01:00
|
|
|
|
show_basic_key_info (ctrl, keyblock, from_sk);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
tty_printf ("\n");
|
|
|
|
|
if (!cpr_get_answer_is_yes ("import.okay",
|
|
|
|
|
"Do you want to import this key? (y/N) "))
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
Spelling cleanup.
No functional changes, just fixing minor spelling issues.
---
Most of these were identified from the command line by running:
codespell \
--ignore-words-list fpr,stati,keyserver,keyservers,asign,cas,iff,ifset \
--skip '*.po,ChangeLog*,help.*.txt,*.jpg,*.eps,*.pdf,*.png,*.gpg,*.asc' \
doc g13 g10 kbx agent artwork scd tests tools am common dirmngr sm \
NEWS README README.maint TODO
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2020-02-18 15:34:42 +01:00
|
|
|
|
/* Remove all non-self-sigs if requested. Note that this is a NOP if
|
2019-07-01 21:53:55 +02:00
|
|
|
|
* that option has been globally set but we may also be called
|
|
|
|
|
* latter with the already parsed keyblock and a locally changed
|
|
|
|
|
* option. This is why we need to remove them here as well. */
|
|
|
|
|
if ((options & IMPORT_SELF_SIGS_ONLY))
|
|
|
|
|
remove_all_non_self_sigs (&keyblock, keyid);
|
|
|
|
|
|
2018-10-02 11:02:08 +02:00
|
|
|
|
/* Remove or collapse the user ids. */
|
2021-02-02 12:57:00 +01:00
|
|
|
|
if ((options & IMPORT_COLLAPSE_UIDS))
|
2018-10-02 11:02:08 +02:00
|
|
|
|
collapse_uids (&keyblock);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2020-08-25 10:33:57 +02:00
|
|
|
|
if ((options & IMPORT_COLLAPSE_SUBKEYS))
|
|
|
|
|
collapse_subkeys (&keyblock);
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* Clean the key that we're about to import, to cut down on things
|
|
|
|
|
that we have to clean later. This has no practical impact on the
|
|
|
|
|
end result, but does result in less logging which might confuse
|
|
|
|
|
the user. */
|
2018-07-06 11:48:38 +02:00
|
|
|
|
if ((options & IMPORT_CLEAN))
|
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
|
|
|
|
clean_all_uids (ctrl, keyblock,
|
2024-03-04 14:22:42 +01:00
|
|
|
|
opt.verbose,
|
|
|
|
|
(options&IMPORT_MINIMAL)? EXPORT_MINIMAL : 0,
|
|
|
|
|
NULL, NULL);
|
2018-07-09 09:49:09 +02:00
|
|
|
|
clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
|
|
|
|
|
NULL, NULL);
|
2018-07-06 11:48:38 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
clear_kbnode_flags( keyblock );
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if ((options&IMPORT_REPAIR_PKS_SUBKEY_BUG)
|
|
|
|
|
&& fix_pks_corruption (ctrl, keyblock)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
&& opt.verbose)
|
|
|
|
|
log_info (_("key %s: PKS subkey corruption repaired\n"),
|
|
|
|
|
keystr_from_pk(pk));
|
|
|
|
|
|
2017-06-13 15:35:01 +02:00
|
|
|
|
if ((options & IMPORT_REPAIR_KEYS))
|
2017-07-27 11:37:00 +02:00
|
|
|
|
key_check_all_keysigs (ctrl, 1, keyblock, 0, 0);
|
2017-06-13 15:35:01 +02:00
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
if (chk_self_sigs (ctrl, keyblock, keyid, &non_self))
|
2016-07-06 10:35:36 +02:00
|
|
|
|
return 0; /* Invalid keyblock - error already printed. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
/* If we allow such a thing, mark unsigned uids as valid */
|
|
|
|
|
if (opt.allow_non_selfsigned_uid)
|
|
|
|
|
{
|
|
|
|
|
for (node=keyblock; node; node = node->next )
|
2016-07-06 10:35:36 +02:00
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& !(node->flag & NODE_GOOD_SELFSIG)
|
|
|
|
|
&& !(node->flag & NODE_BAD_SELFSIG) )
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
char *user=utf8_to_native(node->pkt->pkt.user_id->name,
|
|
|
|
|
node->pkt->pkt.user_id->len,0);
|
2016-07-06 10:35:36 +02:00
|
|
|
|
/* Fake a good signature status for the user id. */
|
|
|
|
|
node->flag |= NODE_GOOD_SELFSIG;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_info( _("key %s: accepted non self-signed user ID \"%s\"\n"),
|
|
|
|
|
keystr_from_pk(pk),user);
|
|
|
|
|
xfree(user);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2021-02-02 12:57:00 +01:00
|
|
|
|
/* Delete invalid parts and bail out if there are no user ids left. */
|
2022-10-28 09:29:30 +02:00
|
|
|
|
if (!delete_inv_parts (ctrl, keyblock, keyid, options, otherrevsigs))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
if (!silent)
|
|
|
|
|
{
|
2021-02-02 12:57:00 +01:00
|
|
|
|
log_error ( _("key %s: no valid user IDs\n"), keystr_from_pk(pk));
|
|
|
|
|
if (!opt.quiet)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_info(_("this may be caused by a missing self-signature\n"));
|
2014-06-05 11:19:59 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
stats->no_user_id++;
|
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-23 19:25:53 +02:00
|
|
|
|
/* Get rid of deleted nodes. */
|
|
|
|
|
commit_kbnode (&keyblock);
|
|
|
|
|
|
2016-07-01 16:24:04 +02:00
|
|
|
|
/* Apply import filter. */
|
2016-09-28 13:39:09 +02:00
|
|
|
|
if (import_filter.keep_uid)
|
2016-07-01 16:24:04 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
apply_keep_uid_filter (ctrl, keyblock, import_filter.keep_uid);
|
2016-07-01 16:24:04 +02:00
|
|
|
|
commit_kbnode (&keyblock);
|
2016-09-28 15:32:04 +02:00
|
|
|
|
any_filter = 1;
|
2016-07-01 16:24:04 +02:00
|
|
|
|
}
|
2016-09-28 13:39:09 +02:00
|
|
|
|
if (import_filter.drop_sig)
|
2016-08-18 16:15:49 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
apply_drop_sig_filter (ctrl, keyblock, import_filter.drop_sig);
|
2016-08-18 16:15:49 +02:00
|
|
|
|
commit_kbnode (&keyblock);
|
2016-09-28 15:32:04 +02:00
|
|
|
|
any_filter = 1;
|
2016-08-18 16:15:49 +02:00
|
|
|
|
}
|
2016-07-01 16:24:04 +02:00
|
|
|
|
|
2016-09-28 15:32:04 +02:00
|
|
|
|
/* If we ran any filter we need to check that at least one user id
|
|
|
|
|
* is left in the keyring. Note that we do not use log_error in
|
|
|
|
|
* this case. */
|
|
|
|
|
if (any_filter && !any_uid_left (keyblock))
|
|
|
|
|
{
|
|
|
|
|
if (!opt.quiet )
|
|
|
|
|
log_info ( _("key %s: no valid user IDs\n"), keystr_from_pk (pk));
|
|
|
|
|
stats->no_user_id++;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2016-07-01 16:24:04 +02:00
|
|
|
|
|
2019-03-15 19:50:37 +01:00
|
|
|
|
/* The keyblock is valid and ready for real import. */
|
|
|
|
|
if (r_valid)
|
|
|
|
|
*r_valid = 1;
|
|
|
|
|
|
2016-06-24 13:11:37 +02:00
|
|
|
|
/* Show the key in the form it is merged or inserted. We skip this
|
|
|
|
|
* if "import-export" is also active without --armor or the output
|
|
|
|
|
* file has explicily been given. */
|
|
|
|
|
if ((options & IMPORT_SHOW)
|
|
|
|
|
&& !((options & IMPORT_EXPORT) && !opt.armor && !opt.outfile))
|
2016-06-23 19:25:53 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2016-06-24 13:11:37 +02:00
|
|
|
|
merge_keys_done = 1;
|
2016-06-23 19:25:53 +02:00
|
|
|
|
/* Note that we do not want to show the validity because the key
|
|
|
|
|
* has not yet imported. */
|
2024-05-15 09:56:40 +02:00
|
|
|
|
err = list_keyblock_direct (ctrl, keyblock, from_sk, 0,
|
2017-08-04 17:09:17 +02:00
|
|
|
|
opt.fingerprint || opt.with_fingerprint, 1);
|
2016-06-23 19:25:53 +02:00
|
|
|
|
es_fflush (es_stdout);
|
2023-05-08 13:10:47 +02:00
|
|
|
|
no_usable_encr_subkeys_warning (keyblock);
|
2024-05-15 09:56:40 +02:00
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
2016-06-23 19:25:53 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-24 13:11:37 +02:00
|
|
|
|
/* Write the keyblock to the output and do not actually import. */
|
|
|
|
|
if ((options & IMPORT_EXPORT))
|
|
|
|
|
{
|
|
|
|
|
if (!merge_keys_done)
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2016-06-24 13:11:37 +02:00
|
|
|
|
merge_keys_done = 1;
|
|
|
|
|
}
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = write_keyblock_to_output (keyblock, opt.armor, opt.export_options);
|
2016-06-24 13:11:37 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-04 17:03:03 +02:00
|
|
|
|
if (opt.dry_run || (options & IMPORT_DRY_RUN))
|
2016-06-23 19:25:53 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* Do we have this key already in one of our pubrings ? */
|
2024-06-04 15:25:51 +02:00
|
|
|
|
err = get_keyblock_byfpr_fast (ctrl, &keyblock_orig, &hd,
|
|
|
|
|
fpr2, fpr2len, 1/*locked*/);
|
2017-10-18 17:52:41 +02:00
|
|
|
|
if ((err
|
|
|
|
|
&& gpg_err_code (err) != GPG_ERR_NO_PUBKEY
|
|
|
|
|
&& gpg_err_code (err) != GPG_ERR_UNUSABLE_PUBKEY)
|
|
|
|
|
|| !hd)
|
|
|
|
|
{
|
|
|
|
|
/* The !hd above is to catch a misbehaving function which
|
|
|
|
|
* returns NO_PUBKEY for failing to allocate a handle. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!silent)
|
|
|
|
|
log_error (_("key %s: public key not found: %s\n"),
|
2017-10-18 13:09:47 +02:00
|
|
|
|
keystr(keyid), gpg_strerror (err));
|
2014-12-04 10:45:53 +01:00
|
|
|
|
}
|
2017-10-18 13:09:47 +02:00
|
|
|
|
else if (err && (opt.import_options&IMPORT_MERGE_ONLY) )
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
if (opt.verbose && !silent )
|
|
|
|
|
log_info( _("key %s: new key - skipped\n"), keystr(keyid));
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = 0;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
stats->skipped_new_keys++;
|
|
|
|
|
}
|
2017-10-18 13:09:47 +02:00
|
|
|
|
else if (err) /* Insert this key. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2017-10-18 17:52:41 +02:00
|
|
|
|
/* Note: ERR can only be NO_PUBKEY or UNUSABLE_PUBKEY. */
|
2017-07-21 16:03:04 +02:00
|
|
|
|
int n_sigs_cleaned, n_uids_cleaned;
|
2015-12-03 12:18:32 +01:00
|
|
|
|
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = keydb_locate_writable (hd);
|
|
|
|
|
if (err)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
log_error (_("no writable keyring found: %s\n"), gpg_strerror (err));
|
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (opt.verbose > 1 )
|
|
|
|
|
log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) );
|
|
|
|
|
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
if ((options & IMPORT_CLEAN))
|
2018-07-06 11:48:38 +02:00
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock);
|
2024-03-04 14:22:42 +01:00
|
|
|
|
clean_all_uids (ctrl, keyblock, opt.verbose,
|
|
|
|
|
(options&IMPORT_MINIMAL)? EXPORT_MINIMAL : 0,
|
2018-07-06 11:48:38 +02:00
|
|
|
|
&n_uids_cleaned,&n_sigs_cleaned);
|
2018-07-09 09:49:09 +02:00
|
|
|
|
clean_all_subkeys (ctrl, keyblock, opt.verbose, KEY_CLEAN_NONE,
|
|
|
|
|
NULL, NULL);
|
2018-07-06 11:48:38 +02:00
|
|
|
|
}
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
|
2017-07-13 18:22:36 +02:00
|
|
|
|
/* Unless we are in restore mode apply meta data to the
|
|
|
|
|
* keyblock. Note that this will never change the first packet
|
|
|
|
|
* and thus the address of KEYBLOCK won't change. */
|
|
|
|
|
if ( !(options & IMPORT_RESTORE) )
|
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = insert_key_origin (keyblock, origin, url);
|
|
|
|
|
if (err)
|
2017-07-14 11:17:49 +02:00
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
log_error ("insert_key_origin failed: %s\n", gpg_strerror (err));
|
|
|
|
|
err = gpg_error (GPG_ERR_GENERAL);
|
|
|
|
|
goto leave;
|
2017-07-14 11:17:49 +02:00
|
|
|
|
}
|
2017-07-13 18:22:36 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = keydb_insert_keyblock (hd, keyblock );
|
|
|
|
|
if (err)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_error (_("error writing keyring '%s': %s\n"),
|
2017-10-18 13:09:47 +02:00
|
|
|
|
keydb_get_resource_name (hd), gpg_strerror (err));
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (!(opt.import_options & IMPORT_KEEP_OWNERTTRUST))
|
|
|
|
|
{
|
|
|
|
|
/* This should not be possible since we delete the
|
|
|
|
|
ownertrust when a key is deleted, but it can happen if
|
|
|
|
|
the keyring and trustdb are out of sync. It can also
|
|
|
|
|
be made to happen with the trusted-key command and by
|
|
|
|
|
importing and locally exported key. */
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
clear_ownertrusts (ctrl, pk);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (non_self)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
revalidation_mark (ctrl);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
}
|
2017-10-18 13:09:47 +02:00
|
|
|
|
|
|
|
|
|
/* Release the handle and thus unlock the keyring asap. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
keydb_release (hd);
|
2017-10-18 13:09:47 +02:00
|
|
|
|
hd = NULL;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
/* We are ready. */
|
2019-07-01 21:53:55 +02:00
|
|
|
|
if (!err && !opt.quiet && !silent)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2019-04-05 17:02:43 +02:00
|
|
|
|
char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_info (_("key %s: public key \"%s\" imported\n"),
|
|
|
|
|
keystr(keyid), p);
|
|
|
|
|
xfree(p);
|
|
|
|
|
}
|
2019-07-01 21:53:55 +02:00
|
|
|
|
if (!err && is_status_enabled())
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
char *us = get_long_user_id_string (ctrl, keyid);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
write_status_text( STATUS_IMPORTED, us );
|
|
|
|
|
xfree(us);
|
|
|
|
|
print_import_ok (pk, 1);
|
|
|
|
|
}
|
2019-07-01 21:53:55 +02:00
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
stats->imported++;
|
|
|
|
|
new_key = 1;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2017-10-18 17:52:41 +02:00
|
|
|
|
else /* Key already exists - merge. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
int n_uids, n_sigs, n_subk, n_sigs_cleaned, n_uids_cleaned;
|
2017-07-25 11:23:08 +02:00
|
|
|
|
u32 curtime = make_timestamp ();
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* Compare the original against the new key; just to be sure nothing
|
|
|
|
|
* weird is going on */
|
2017-10-18 17:52:41 +02:00
|
|
|
|
if (cmp_public_keys (keyblock_orig->pkt->pkt.public_key, pk))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
if (!silent)
|
|
|
|
|
log_error( _("key %s: doesn't match our copy\n"),keystr(keyid));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* Make sure the original direct key sigs are all sane. */
|
2017-03-31 20:03:52 +02:00
|
|
|
|
n_sigs_cleaned = fix_bad_direct_key_sigs (ctrl, keyblock_orig, keyid);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (n_sigs_cleaned)
|
|
|
|
|
commit_kbnode (&keyblock_orig);
|
|
|
|
|
|
2017-10-18 17:52:41 +02:00
|
|
|
|
/* Try to merge KEYBLOCK into KEYBLOCK_ORIG. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
clear_kbnode_flags( keyblock_orig );
|
|
|
|
|
clear_kbnode_flags( keyblock );
|
|
|
|
|
n_uids = n_sigs = n_subk = n_uids_cleaned = 0;
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = merge_blocks (ctrl, options, keyblock_orig, keyblock, keyid,
|
|
|
|
|
curtime, origin, url,
|
|
|
|
|
&n_uids, &n_sigs, &n_subk );
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2019-11-07 15:07:25 +01:00
|
|
|
|
/* Clean the final keyblock again if requested. we can't do
|
|
|
|
|
* this if only self-signatures are imported; see bug #4628. */
|
|
|
|
|
if ((options & IMPORT_CLEAN)
|
|
|
|
|
&& !(options & IMPORT_SELF_SIGS_ONLY))
|
2018-07-06 11:48:38 +02:00
|
|
|
|
{
|
|
|
|
|
merge_keys_and_selfsig (ctrl, keyblock_orig);
|
|
|
|
|
clean_all_uids (ctrl, keyblock_orig, opt.verbose,
|
2024-03-04 14:22:42 +01:00
|
|
|
|
(options&IMPORT_MINIMAL)? EXPORT_MINIMAL : 0,
|
2018-07-06 11:48:38 +02:00
|
|
|
|
&n_uids_cleaned,&n_sigs_cleaned);
|
2018-07-09 09:49:09 +02:00
|
|
|
|
clean_all_subkeys (ctrl, keyblock_orig, opt.verbose, KEY_CLEAN_NONE,
|
|
|
|
|
NULL, NULL);
|
2018-07-06 11:48:38 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
if (n_uids || n_sigs || n_subk || n_sigs_cleaned || n_uids_cleaned)
|
|
|
|
|
{
|
2017-07-25 11:23:08 +02:00
|
|
|
|
/* Unless we are in restore mode apply meta data to the
|
|
|
|
|
* keyblock. Note that this will never change the first packet
|
|
|
|
|
* and thus the address of KEYBLOCK won't change. */
|
|
|
|
|
if ( !(options & IMPORT_RESTORE) )
|
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = update_key_origin (keyblock_orig, curtime, origin, url);
|
|
|
|
|
if (err)
|
2017-07-25 11:23:08 +02:00
|
|
|
|
{
|
|
|
|
|
log_error ("update_key_origin failed: %s\n",
|
2017-10-18 13:09:47 +02:00
|
|
|
|
gpg_strerror (err));
|
2017-07-25 11:23:08 +02:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
mod_key = 1;
|
|
|
|
|
/* KEYBLOCK_ORIG has been updated; write */
|
2017-10-18 13:09:47 +02:00
|
|
|
|
err = keydb_update_keyblock (ctrl, hd, keyblock_orig);
|
|
|
|
|
if (err)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_error (_("error writing keyring '%s': %s\n"),
|
2017-10-18 13:09:47 +02:00
|
|
|
|
keydb_get_resource_name (hd), gpg_strerror (err));
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (non_self)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
revalidation_mark (ctrl);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2017-10-18 13:09:47 +02:00
|
|
|
|
/* Release the handle and thus unlock the keyring asap. */
|
|
|
|
|
keydb_release (hd);
|
|
|
|
|
hd = NULL;
|
|
|
|
|
|
2019-07-01 21:53:55 +02:00
|
|
|
|
/* We are ready. Print and update stats if we got no error.
|
|
|
|
|
* An error here comes from writing the keyblock and thus
|
|
|
|
|
* very likely means that no update happened. */
|
|
|
|
|
if (!err && !opt.quiet && !silent)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2019-04-05 17:02:43 +02:00
|
|
|
|
char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (n_uids == 1 )
|
|
|
|
|
log_info( _("key %s: \"%s\" 1 new user ID\n"),
|
|
|
|
|
keystr(keyid),p);
|
|
|
|
|
else if (n_uids )
|
|
|
|
|
log_info( _("key %s: \"%s\" %d new user IDs\n"),
|
|
|
|
|
keystr(keyid),p,n_uids);
|
|
|
|
|
if (n_sigs == 1 )
|
|
|
|
|
log_info( _("key %s: \"%s\" 1 new signature\n"),
|
|
|
|
|
keystr(keyid), p);
|
|
|
|
|
else if (n_sigs )
|
|
|
|
|
log_info( _("key %s: \"%s\" %d new signatures\n"),
|
|
|
|
|
keystr(keyid), p, n_sigs );
|
|
|
|
|
if (n_subk == 1 )
|
|
|
|
|
log_info( _("key %s: \"%s\" 1 new subkey\n"),
|
|
|
|
|
keystr(keyid), p);
|
|
|
|
|
else if (n_subk )
|
|
|
|
|
log_info( _("key %s: \"%s\" %d new subkeys\n"),
|
|
|
|
|
keystr(keyid), p, n_subk );
|
|
|
|
|
if (n_sigs_cleaned==1)
|
|
|
|
|
log_info(_("key %s: \"%s\" %d signature cleaned\n"),
|
|
|
|
|
keystr(keyid),p,n_sigs_cleaned);
|
|
|
|
|
else if (n_sigs_cleaned)
|
|
|
|
|
log_info(_("key %s: \"%s\" %d signatures cleaned\n"),
|
|
|
|
|
keystr(keyid),p,n_sigs_cleaned);
|
|
|
|
|
if (n_uids_cleaned==1)
|
|
|
|
|
log_info(_("key %s: \"%s\" %d user ID cleaned\n"),
|
|
|
|
|
keystr(keyid),p,n_uids_cleaned);
|
|
|
|
|
else if (n_uids_cleaned)
|
|
|
|
|
log_info(_("key %s: \"%s\" %d user IDs cleaned\n"),
|
|
|
|
|
keystr(keyid),p,n_uids_cleaned);
|
|
|
|
|
xfree(p);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2019-07-01 21:53:55 +02:00
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
stats->n_uids +=n_uids;
|
|
|
|
|
stats->n_sigs +=n_sigs;
|
|
|
|
|
stats->n_subk +=n_subk;
|
|
|
|
|
stats->n_sigs_cleaned +=n_sigs_cleaned;
|
|
|
|
|
stats->n_uids_cleaned +=n_uids_cleaned;
|
|
|
|
|
|
|
|
|
|
if (is_status_enabled () && !silent)
|
|
|
|
|
print_import_ok (pk, ((n_uids?2:0)|(n_sigs?4:0)|(n_subk?8:0)));
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else
|
|
|
|
|
{
|
2017-10-18 13:09:47 +02:00
|
|
|
|
/* Release the handle and thus unlock the keyring asap. */
|
|
|
|
|
keydb_release (hd);
|
|
|
|
|
hd = NULL;
|
|
|
|
|
|
2018-08-28 15:22:35 +02:00
|
|
|
|
/* FIXME: We do not track the time we last checked a key for
|
2017-07-25 11:23:08 +02:00
|
|
|
|
* updates. To do this we would need to rewrite even the
|
2018-08-28 15:22:35 +02:00
|
|
|
|
* keys which have no changes. Adding this would be useful
|
|
|
|
|
* for the automatic update of expired keys via the WKD in
|
|
|
|
|
* case the WKD still carries the expired key. See
|
|
|
|
|
* get_best_pubkey_byname. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
same_key = 1;
|
|
|
|
|
if (is_status_enabled ())
|
|
|
|
|
print_import_ok (pk, 0);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!opt.quiet && !silent)
|
|
|
|
|
{
|
2019-04-05 17:02:43 +02:00
|
|
|
|
char *p = get_user_id_byfpr_native (ctrl, fpr2, fpr2len);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_info( _("key %s: \"%s\" not changed\n"),keystr(keyid),p);
|
|
|
|
|
xfree(p);
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
stats->unchanged++;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-06-23 19:25:53 +02:00
|
|
|
|
leave:
|
2017-10-18 13:09:47 +02:00
|
|
|
|
keydb_release (hd);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (mod_key || new_key || same_key)
|
|
|
|
|
{
|
|
|
|
|
/* A little explanation for this: we fill in the fingerprint
|
|
|
|
|
when importing keys as it can be useful to know the
|
|
|
|
|
fingerprint in certain keyserver-related cases (a keyserver
|
|
|
|
|
asked for a particular name, but the key doesn't have that
|
|
|
|
|
name). However, in cases where we're importing more than
|
|
|
|
|
one key at a time, we cannot know which key to fingerprint.
|
|
|
|
|
In these cases, rather than guessing, we do not
|
|
|
|
|
fingerprinting at all, and we must hope the user ID on the
|
|
|
|
|
keys are useful. Note that we need to do this for new
|
|
|
|
|
keys, merged keys and even for unchanged keys. This is
|
|
|
|
|
required because for example the --auto-key-locate feature
|
|
|
|
|
may import an already imported key and needs to know the
|
|
|
|
|
fingerprint of the key in all cases. */
|
|
|
|
|
if (fpr)
|
|
|
|
|
{
|
|
|
|
|
/* Note that we need to compare against 0 here because
|
2016-04-27 08:34:29 +02:00
|
|
|
|
COUNT gets only incremented after returning from this
|
2014-12-04 10:45:53 +01:00
|
|
|
|
function. */
|
|
|
|
|
if (!stats->count)
|
2019-04-11 09:43:33 +02:00
|
|
|
|
{
|
|
|
|
|
xfree (*fpr);
|
|
|
|
|
*fpr = fingerprint_from_pk (pk, NULL, fpr_len);
|
|
|
|
|
}
|
|
|
|
|
else if (origin != KEYORG_WKD)
|
|
|
|
|
{
|
|
|
|
|
xfree (*fpr);
|
|
|
|
|
*fpr = NULL;
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* Now that the key is definitely incorporated into the keydb, we
|
|
|
|
|
need to check if a designated revocation is present or if the
|
|
|
|
|
prefs are not rational so we can warn the user. */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (mod_key)
|
|
|
|
|
{
|
|
|
|
|
revocation_present (ctrl, keyblock_orig);
|
2019-09-09 14:34:09 +02:00
|
|
|
|
if (!from_sk && have_secret_key_with_kid (ctrl, keyid))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
check_prefs (ctrl, keyblock_orig);
|
|
|
|
|
}
|
|
|
|
|
else if (new_key)
|
|
|
|
|
{
|
|
|
|
|
revocation_present (ctrl, keyblock);
|
2019-09-09 14:34:09 +02:00
|
|
|
|
if (!from_sk && have_secret_key_with_kid (ctrl, keyid))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
check_prefs (ctrl, keyblock);
|
|
|
|
|
}
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
release_kbnode( keyblock_orig );
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2017-10-18 13:09:47 +02:00
|
|
|
|
return err;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
|
2019-07-01 21:53:55 +02:00
|
|
|
|
/* Wrapper around import_one_real to retry the import in some cases. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
import_one (ctrl_t ctrl,
|
|
|
|
|
kbnode_t keyblock, struct import_stats_s *stats,
|
|
|
|
|
unsigned char **fpr, size_t *fpr_len, unsigned int options,
|
|
|
|
|
int from_sk, int silent,
|
|
|
|
|
import_screener_t screener, void *screener_arg,
|
|
|
|
|
int origin, const char *url, int *r_valid)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
2022-10-28 09:29:30 +02:00
|
|
|
|
kbnode_t otherrevsigs = NULL;
|
|
|
|
|
kbnode_t node;
|
2019-07-01 21:53:55 +02:00
|
|
|
|
|
|
|
|
|
err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options,
|
|
|
|
|
from_sk, silent, screener, screener_arg,
|
2022-10-28 09:29:30 +02:00
|
|
|
|
origin, url, r_valid, &otherrevsigs);
|
2019-07-01 21:53:55 +02:00
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_TOO_LARGE
|
2019-07-09 11:13:51 +02:00
|
|
|
|
&& gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX
|
|
|
|
|
&& ((options & (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN))
|
|
|
|
|
!= (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN)))
|
2019-07-01 21:53:55 +02:00
|
|
|
|
{
|
|
|
|
|
/* We hit the maximum image length. Ask the wrapper to do
|
|
|
|
|
* everything again but this time with some extra options. */
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
|
|
|
|
keyid_from_pk (keyblock->pkt->pkt.public_key, keyid);
|
|
|
|
|
log_info ("key %s: keyblock too large, retrying with self-sigs-only\n",
|
|
|
|
|
keystr (keyid));
|
|
|
|
|
options |= IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN;
|
|
|
|
|
err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options,
|
|
|
|
|
from_sk, silent, screener, screener_arg,
|
2022-10-28 09:29:30 +02:00
|
|
|
|
origin, url, r_valid, &otherrevsigs);
|
2019-07-01 21:53:55 +02:00
|
|
|
|
}
|
2022-10-28 09:29:30 +02:00
|
|
|
|
|
|
|
|
|
/* Finally try to import other revocation certificates. For example
|
|
|
|
|
* those of a former key appended to the current key. */
|
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
for (node = otherrevsigs; node; node = node->next)
|
|
|
|
|
import_revoke_cert (ctrl, node, options, stats);
|
|
|
|
|
}
|
|
|
|
|
release_kbnode (otherrevsigs);
|
2019-07-01 21:53:55 +02:00
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
/* Transfer all the secret keys in SEC_KEYBLOCK to the gpg-agent. The
|
2019-03-18 13:07:14 +01:00
|
|
|
|
* function prints diagnostics and returns an error code. If BATCH is
|
|
|
|
|
* true the secret keys are stored by gpg-agent in the transfer format
|
|
|
|
|
* (i.e. no re-protection and aksing for passphrases). If ONLY_MARKED
|
|
|
|
|
* is set, only those nodes with flag NODE_TRANSFER_SECKEY are
|
|
|
|
|
* processed. */
|
2015-12-24 01:54:23 +01:00
|
|
|
|
gpg_error_t
|
2015-12-24 06:15:58 +01:00
|
|
|
|
transfer_secret_keys (ctrl_t ctrl, struct import_stats_s *stats,
|
2019-03-18 13:07:14 +01:00
|
|
|
|
kbnode_t sec_keyblock, int batch, int force,
|
|
|
|
|
int only_marked)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-08-31 17:58:39 +02:00
|
|
|
|
gpg_error_t err = 0;
|
|
|
|
|
void *kek = NULL;
|
|
|
|
|
size_t keklen;
|
|
|
|
|
kbnode_t ctx = NULL;
|
|
|
|
|
kbnode_t node;
|
2010-09-06 21:57:42 +02:00
|
|
|
|
PKT_public_key *main_pk, *pk;
|
|
|
|
|
struct seckey_info *ski;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
int nskey;
|
|
|
|
|
membuf_t mbuf;
|
|
|
|
|
int i, j;
|
|
|
|
|
void *format_args[2*PUBKEY_MAX_NSKEY];
|
|
|
|
|
gcry_sexp_t skey, prot, tmpsexp;
|
2014-05-07 13:16:32 +02:00
|
|
|
|
gcry_sexp_t curve = NULL;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
unsigned char *transferkey = NULL;
|
|
|
|
|
size_t transferkeylen;
|
|
|
|
|
gcry_cipher_hd_t cipherhd = NULL;
|
|
|
|
|
unsigned char *wrappedkey = NULL;
|
|
|
|
|
size_t wrappedkeylen;
|
2010-09-01 11:48:35 +02:00
|
|
|
|
char *cache_nonce = NULL;
|
2015-11-02 06:33:38 +01:00
|
|
|
|
int stub_key_skipped = 0;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
|
|
|
|
|
/* Get the current KEK. */
|
|
|
|
|
err = agent_keywrap_key (ctrl, 0, &kek, &keklen);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("error getting the KEK: %s\n", gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
/* Prepare a cipher context. */
|
|
|
|
|
err = gcry_cipher_open (&cipherhd, GCRY_CIPHER_AES128,
|
|
|
|
|
GCRY_CIPHER_MODE_AESWRAP, 0);
|
|
|
|
|
if (!err)
|
|
|
|
|
err = gcry_cipher_setkey (cipherhd, kek, keklen);
|
|
|
|
|
if (err)
|
2011-02-02 15:48:54 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
xfree (kek);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
kek = NULL;
|
|
|
|
|
|
2019-03-18 13:07:14 +01:00
|
|
|
|
/* Note: We need to use walk_kbnode so that we skip nodes which are
|
|
|
|
|
* marked as deleted. */
|
2010-09-06 21:57:42 +02:00
|
|
|
|
main_pk = NULL;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
while ((node = walk_kbnode (sec_keyblock, &ctx, 0)))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-08-31 17:58:39 +02:00
|
|
|
|
if (node->pkt->pkttype != PKT_SECRET_KEY
|
|
|
|
|
&& node->pkt->pkttype != PKT_SECRET_SUBKEY)
|
|
|
|
|
continue;
|
2019-03-18 13:07:14 +01:00
|
|
|
|
if (only_marked && !(node->flag & NODE_TRANSFER_SECKEY))
|
|
|
|
|
continue;
|
2010-09-06 21:57:42 +02:00
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
if (!main_pk)
|
|
|
|
|
main_pk = pk;
|
|
|
|
|
|
2011-02-02 15:48:54 +01:00
|
|
|
|
/* Make sure the keyids are available. */
|
|
|
|
|
keyid_from_pk (pk, NULL);
|
|
|
|
|
if (node->pkt->pkttype == PKT_SECRET_KEY)
|
|
|
|
|
{
|
|
|
|
|
pk->main_keyid[0] = pk->keyid[0];
|
|
|
|
|
pk->main_keyid[1] = pk->keyid[1];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
pk->main_keyid[0] = main_pk->keyid[0];
|
|
|
|
|
pk->main_keyid[1] = main_pk->keyid[1];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
ski = pk->seckey_info;
|
|
|
|
|
if (!ski)
|
|
|
|
|
BUG ();
|
2010-08-31 17:58:39 +02:00
|
|
|
|
|
2015-12-24 01:54:23 +01:00
|
|
|
|
if (stats)
|
|
|
|
|
{
|
|
|
|
|
stats->count++;
|
|
|
|
|
stats->secret_read++;
|
|
|
|
|
}
|
2010-09-02 17:11:51 +02:00
|
|
|
|
|
2010-10-13 17:57:08 +02:00
|
|
|
|
/* We ignore stub keys. The way we handle them in other parts
|
|
|
|
|
of the code is by asking the agent whether any secret key is
|
|
|
|
|
available for a given keyblock and then concluding that we
|
|
|
|
|
have a secret key; all secret (sub)keys of the keyblock the
|
|
|
|
|
agent does not know of are then stub keys. This works also
|
|
|
|
|
for card stub keys. The learn command or the card-status
|
|
|
|
|
command may be used to check with the agent whether a card
|
|
|
|
|
has been inserted and a stub key is in turn generated by the
|
|
|
|
|
agent. */
|
2010-10-06 13:29:10 +02:00
|
|
|
|
if (ski->s2k.mode == 1001 || ski->s2k.mode == 1002)
|
2015-11-02 06:33:38 +01:00
|
|
|
|
{
|
|
|
|
|
stub_key_skipped = 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2010-10-06 13:29:10 +02:00
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
/* Convert our internal secret key object into an S-expression. */
|
2010-09-06 21:57:42 +02:00
|
|
|
|
nskey = pubkey_get_nskey (pk->pubkey_algo);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
if (!nskey || nskey > PUBKEY_MAX_NSKEY)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error (GPG_ERR_BAD_SECKEY);
|
|
|
|
|
log_error ("internal error: %s\n", gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
init_membuf (&mbuf, 50);
|
|
|
|
|
put_membuf_str (&mbuf, "(skey");
|
2011-02-02 15:48:54 +01:00
|
|
|
|
if (pk->pubkey_algo == PUBKEY_ALGO_ECDSA
|
gpg: Use only OpenPGP public key algo ids and add the EdDSA algo id.
* common/sexputil.c (get_pk_algo_from_canon_sexp): Change to return a
string.
* g10/keygen.c (check_keygrip): Adjust for change.
* sm/certreqgen-ui.c (check_keygrip): Likewise.
* agent/pksign.c (do_encode_dsa): Remove bogus map_pk_openpgp_to_gcry.
* g10/misc.c (map_pk_openpgp_to_gcry): Remove.
(openpgp_pk_test_algo): Change to a wrapper for openpgp_pk_test_algo2.
(openpgp_pk_test_algo2): Rewrite.
(openpgp_pk_algo_usage, pubkey_nbits): Add support for EdDSA.
(openpgp_pk_algo_name): Rewrite to remove need for gcry calls.
(pubkey_get_npkey, pubkey_get_nskey): Ditto.
(pubkey_get_nsig, pubkey_get_nenc): Ditto.
* g10/keygen.c(do_create_from_keygrip): Support EdDSA.
(common_gen, gen_ecc, ask_keysize, generate_keypair): Ditto.
* g10/build-packet.c (do_key): Ditto.
* g10/export.c (transfer_format_to_openpgp): Ditto.
* g10/getkey.c (cache_public_key): Ditto.
* g10/import.c (transfer_secret_keys): Ditto.
* g10/keylist.c (list_keyblock_print, list_keyblock_colon): Ditto.
* g10/mainproc.c (proc_pubkey_enc): Ditto.
* g10/parse-packet.c (parse_key): Ditto,
* g10/sign.c (hash_for, sign_file, make_keysig_packet): Ditto.
* g10/keyserver.c (print_keyrec): Use openpgp_pk_algo_name.
* g10/pkglue.c (pk_verify, pk_encrypt, pk_check_secret_key): Use only
OpenPGP algo ids and support EdDSA.
* g10/pubkey-enc.c (get_it): Use only OpenPGP algo ids.
* g10/seskey.c (encode_md_value): Ditto.
--
This patch separates Libgcrypt and OpenPGP public key algorithms ids
and in most cases completely removes the Libgcrypt ones. This is
useful because for Libgcrypt we specify the algorithm in the
S-expressions and the public key ids are not anymore needed.
This patch also adds some support for PUBKEY_ALGO_EDDSA which will
eventually be used instead of merging EdDSA with ECDSA. As of now an
experimental algorithm id is used but the plan is to write an I-D so
that we can get a new id from the IETF. Note that EdDSA (Ed25519)
does not yet work and that more changes are required.
The ECC support is still broken right now. Needs to be fixed.
Signed-off-by: Werner Koch <wk@gnupg.org>
2014-01-30 18:48:37 +01:00
|
|
|
|
|| pk->pubkey_algo == PUBKEY_ALGO_EDDSA
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|| pk->pubkey_algo == PUBKEY_ALGO_ECDH)
|
2010-08-31 17:58:39 +02:00
|
|
|
|
{
|
2014-05-07 13:16:32 +02:00
|
|
|
|
/* The ECC case. */
|
|
|
|
|
char *curvestr = openpgp_oid_to_str (pk->pkey[0]);
|
|
|
|
|
if (!curvestr)
|
2011-02-02 15:48:54 +01:00
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
else
|
2010-08-31 17:58:39 +02:00
|
|
|
|
{
|
2015-08-06 09:44:03 +02:00
|
|
|
|
const char *curvename = openpgp_oid_to_curve (curvestr, 1);
|
2016-07-01 13:43:01 +02:00
|
|
|
|
gcry_sexp_release (curve);
|
2015-07-08 08:05:06 +02:00
|
|
|
|
err = gcry_sexp_build (&curve, NULL, "(curve %s)",
|
|
|
|
|
curvename?curvename:curvestr);
|
2014-05-07 13:16:32 +02:00
|
|
|
|
if (!err)
|
2011-02-02 15:48:54 +01:00
|
|
|
|
{
|
2014-05-07 13:16:32 +02:00
|
|
|
|
j = 0;
|
|
|
|
|
/* Append the public key element Q. */
|
|
|
|
|
put_membuf_str (&mbuf, " _ %m");
|
|
|
|
|
format_args[j++] = pk->pkey + 1;
|
|
|
|
|
|
|
|
|
|
/* Append the secret key element D. For ECDH we
|
|
|
|
|
skip PKEY[2] because this holds the KEK which is
|
|
|
|
|
not needed by gpg-agent. */
|
|
|
|
|
i = pk->pubkey_algo == PUBKEY_ALGO_ECDH? 3 : 2;
|
|
|
|
|
if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1))
|
|
|
|
|
put_membuf_str (&mbuf, " e %m");
|
|
|
|
|
else
|
|
|
|
|
put_membuf_str (&mbuf, " _ %m");
|
|
|
|
|
format_args[j++] = pk->pkey + i;
|
2021-09-14 13:00:40 +02:00
|
|
|
|
|
|
|
|
|
/* Simple hack to print a warning for an invalid key
|
|
|
|
|
* 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")
|
2023-04-06 04:32:52 +02:00
|
|
|
|
&& !gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1)
|
2021-09-14 13:00:40 +02:00
|
|
|
|
&& gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_OPAQUE))
|
|
|
|
|
{
|
|
|
|
|
const unsigned char *pp;
|
|
|
|
|
unsigned int nn;
|
|
|
|
|
|
|
|
|
|
pp = gcry_mpi_get_opaque (pk->pkey[i], &nn);
|
|
|
|
|
nn = (nn+7)/8;
|
|
|
|
|
if (pp && nn && (pp[nn-1] & 7))
|
|
|
|
|
log_info ("warning: lower 3 bits of the secret key"
|
|
|
|
|
" are not cleared\n");
|
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
}
|
2021-09-14 13:00:40 +02:00
|
|
|
|
xfree (curvestr);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* Standard case for the old (non-ECC) algorithms. */
|
|
|
|
|
for (i=j=0; i < nskey; i++)
|
2010-08-31 17:58:39 +02:00
|
|
|
|
{
|
2011-02-02 15:48:54 +01:00
|
|
|
|
if (!pk->pkey[i])
|
2014-05-07 13:16:32 +02:00
|
|
|
|
continue; /* Protected keys only have NPKEY+1 elements. */
|
|
|
|
|
|
|
|
|
|
if (gcry_mpi_get_flag (pk->pkey[i], GCRYMPI_FLAG_USER1))
|
|
|
|
|
put_membuf_str (&mbuf, " e %m");
|
2011-02-02 15:48:54 +01:00
|
|
|
|
else
|
2014-05-07 13:16:32 +02:00
|
|
|
|
put_membuf_str (&mbuf, " _ %m");
|
|
|
|
|
format_args[j++] = pk->pkey + i;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-05-07 13:16:32 +02:00
|
|
|
|
put_membuf_str (&mbuf, ")");
|
2010-08-31 17:58:39 +02:00
|
|
|
|
put_membuf (&mbuf, "", 1);
|
2011-02-02 15:48:54 +01:00
|
|
|
|
if (err)
|
|
|
|
|
xfree (get_membuf (&mbuf, NULL));
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *format = get_membuf (&mbuf, NULL);
|
|
|
|
|
if (!format)
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
else
|
|
|
|
|
err = gcry_sexp_build_array (&skey, NULL, format, format_args);
|
|
|
|
|
xfree (format);
|
|
|
|
|
}
|
2010-08-31 17:58:39 +02:00
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("error building skey array: %s\n", gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
if (ski->is_protected)
|
2010-08-31 17:58:39 +02:00
|
|
|
|
{
|
|
|
|
|
char countbuf[35];
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2018-01-23 12:07:25 +01:00
|
|
|
|
/* FIXME: Support AEAD */
|
2010-10-06 13:29:10 +02:00
|
|
|
|
/* Note that the IVLEN may be zero if we are working on a
|
|
|
|
|
dummy key. We can't express that in an S-expression and
|
|
|
|
|
thus we send dummy data for the IV. */
|
2010-08-31 17:58:39 +02:00
|
|
|
|
snprintf (countbuf, sizeof countbuf, "%lu",
|
2010-09-06 21:57:42 +02:00
|
|
|
|
(unsigned long)ski->s2k.count);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
err = gcry_sexp_build
|
|
|
|
|
(&prot, NULL,
|
|
|
|
|
" (protection %s %s %b %d %s %b %s)\n",
|
2010-09-06 21:57:42 +02:00
|
|
|
|
ski->sha1chk? "sha1":"sum",
|
|
|
|
|
openpgp_cipher_algo_name (ski->algo),
|
2010-10-06 13:29:10 +02:00
|
|
|
|
ski->ivlen? (int)ski->ivlen:1,
|
|
|
|
|
ski->ivlen? ski->iv: (const unsigned char*)"X",
|
2010-09-06 21:57:42 +02:00
|
|
|
|
ski->s2k.mode,
|
|
|
|
|
openpgp_md_algo_name (ski->s2k.hash_algo),
|
|
|
|
|
(int)sizeof (ski->s2k.salt), ski->s2k.salt,
|
2010-08-31 17:58:39 +02:00
|
|
|
|
countbuf);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
err = gcry_sexp_build (&prot, NULL, " (protection none)\n");
|
|
|
|
|
|
|
|
|
|
tmpsexp = NULL;
|
|
|
|
|
xfree (transferkey);
|
|
|
|
|
transferkey = NULL;
|
|
|
|
|
if (!err)
|
|
|
|
|
err = gcry_sexp_build (&tmpsexp, NULL,
|
|
|
|
|
"(openpgp-private-key\n"
|
|
|
|
|
" (version %d)\n"
|
|
|
|
|
" (algo %s)\n"
|
2014-05-07 13:16:32 +02:00
|
|
|
|
" %S%S\n"
|
2010-08-31 17:58:39 +02:00
|
|
|
|
" (csum %d)\n"
|
|
|
|
|
" %S)\n",
|
2010-09-06 21:57:42 +02:00
|
|
|
|
pk->version,
|
|
|
|
|
openpgp_pk_algo_name (pk->pubkey_algo),
|
2014-05-07 13:16:32 +02:00
|
|
|
|
curve, skey,
|
|
|
|
|
(int)(unsigned long)ski->csum, prot);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
gcry_sexp_release (skey);
|
|
|
|
|
gcry_sexp_release (prot);
|
|
|
|
|
if (!err)
|
|
|
|
|
err = make_canon_sexp_pad (tmpsexp, 1, &transferkey, &transferkeylen);
|
|
|
|
|
gcry_sexp_release (tmpsexp);
|
|
|
|
|
if (err)
|
|
|
|
|
{
|
|
|
|
|
log_error ("error building transfer key: %s\n", gpg_strerror (err));
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
/* Wrap the key. */
|
|
|
|
|
wrappedkeylen = transferkeylen + 8;
|
|
|
|
|
xfree (wrappedkey);
|
|
|
|
|
wrappedkey = xtrymalloc (wrappedkeylen);
|
|
|
|
|
if (!wrappedkey)
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
else
|
|
|
|
|
err = gcry_cipher_encrypt (cipherhd, wrappedkey, wrappedkeylen,
|
|
|
|
|
transferkey, transferkeylen);
|
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
xfree (transferkey);
|
|
|
|
|
transferkey = NULL;
|
|
|
|
|
|
|
|
|
|
/* Send the wrapped key to the agent. */
|
2011-02-02 15:48:54 +01:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
char *desc = gpg_format_keydesc (ctrl, pk, FORMAT_KEYDESC_IMPORT, 1);
|
2011-02-02 15:48:54 +01:00
|
|
|
|
err = agent_import_key (ctrl, desc, &cache_nonce,
|
2017-07-24 17:18:42 +02:00
|
|
|
|
wrappedkey, wrappedkeylen, batch, force,
|
2020-08-19 13:43:16 +02:00
|
|
|
|
pk->keyid, pk->main_keyid, pk->pubkey_algo,
|
|
|
|
|
pk->timestamp);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
xfree (desc);
|
|
|
|
|
}
|
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
log_info (_("key %s: secret key imported\n"),
|
2010-09-06 21:57:42 +02:00
|
|
|
|
keystr_from_pk_with_sub (main_pk, pk));
|
2015-12-24 01:54:23 +01:00
|
|
|
|
if (stats)
|
|
|
|
|
stats->secret_imported++;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
else if ( gpg_err_code (err) == GPG_ERR_EEXIST )
|
|
|
|
|
{
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
log_info (_("key %s: secret key already exists\n"),
|
2010-09-06 21:57:42 +02:00
|
|
|
|
keystr_from_pk_with_sub (main_pk, pk));
|
2010-08-31 17:58:39 +02:00
|
|
|
|
err = 0;
|
2015-12-24 01:54:23 +01:00
|
|
|
|
if (stats)
|
|
|
|
|
stats->secret_dups++;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
log_error (_("key %s: error sending to agent: %s\n"),
|
2010-09-06 21:57:42 +02:00
|
|
|
|
keystr_from_pk_with_sub (main_pk, pk),
|
2010-08-31 17:58:39 +02:00
|
|
|
|
gpg_strerror (err));
|
2010-10-13 17:57:08 +02:00
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_CANCELED
|
|
|
|
|
|| gpg_err_code (err) == GPG_ERR_FULLY_CANCELED)
|
2010-08-31 17:58:39 +02:00
|
|
|
|
break; /* Don't try the other subkeys. */
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-11-02 06:33:38 +01:00
|
|
|
|
if (!err && stub_key_skipped)
|
|
|
|
|
/* We need to notify user how to migrate stub keys. */
|
|
|
|
|
err = gpg_error (GPG_ERR_NOT_PROCESSED);
|
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
leave:
|
2014-05-07 13:16:32 +02:00
|
|
|
|
gcry_sexp_release (curve);
|
2010-09-01 11:48:35 +02:00
|
|
|
|
xfree (cache_nonce);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
xfree (wrappedkey);
|
|
|
|
|
xfree (transferkey);
|
|
|
|
|
gcry_cipher_close (cipherhd);
|
|
|
|
|
xfree (kek);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Walk a secret keyblock and produce a public keyblock out of it.
|
2019-03-15 19:50:37 +01:00
|
|
|
|
* Returns a new node or NULL on error. Modifies the tag field of the
|
|
|
|
|
* nodes. */
|
2010-08-31 17:58:39 +02:00
|
|
|
|
static kbnode_t
|
|
|
|
|
sec_to_pub_keyblock (kbnode_t sec_keyblock)
|
|
|
|
|
{
|
|
|
|
|
kbnode_t pub_keyblock = NULL;
|
|
|
|
|
kbnode_t ctx = NULL;
|
|
|
|
|
kbnode_t secnode, pubnode;
|
2019-07-10 08:42:07 +02:00
|
|
|
|
kbnode_t lastnode = NULL;
|
2019-03-15 19:50:37 +01:00
|
|
|
|
unsigned int tag = 0;
|
|
|
|
|
|
|
|
|
|
/* Set a tag to all nodes. */
|
|
|
|
|
for (secnode = sec_keyblock; secnode; secnode = secnode->next)
|
|
|
|
|
secnode->tag = ++tag;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
|
2019-03-15 19:50:37 +01:00
|
|
|
|
/* Copy. */
|
2010-08-31 17:58:39 +02:00
|
|
|
|
while ((secnode = walk_kbnode (sec_keyblock, &ctx, 0)))
|
|
|
|
|
{
|
|
|
|
|
if (secnode->pkt->pkttype == PKT_SECRET_KEY
|
|
|
|
|
|| secnode->pkt->pkttype == PKT_SECRET_SUBKEY)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
|
/* Make a public key. */
|
2010-08-31 17:58:39 +02:00
|
|
|
|
PACKET *pkt;
|
2010-09-06 21:57:42 +02:00
|
|
|
|
PKT_public_key *pk;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
pkt = xtrycalloc (1, sizeof *pkt);
|
|
|
|
|
pk = pkt? copy_public_key (NULL, secnode->pkt->pkt.public_key): NULL;
|
|
|
|
|
if (!pk)
|
|
|
|
|
{
|
|
|
|
|
xfree (pkt);
|
|
|
|
|
release_kbnode (pub_keyblock);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2010-08-31 17:58:39 +02:00
|
|
|
|
if (secnode->pkt->pkttype == PKT_SECRET_KEY)
|
|
|
|
|
pkt->pkttype = PKT_PUBLIC_KEY;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
else
|
2010-08-31 17:58:39 +02:00
|
|
|
|
pkt->pkttype = PKT_PUBLIC_SUBKEY;
|
|
|
|
|
pkt->pkt.public_key = pk;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
pubnode = new_kbnode (pkt);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2010-08-31 17:58:39 +02:00
|
|
|
|
pubnode = clone_kbnode (secnode);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2019-03-15 19:50:37 +01:00
|
|
|
|
pubnode->tag = secnode->tag;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
if (!pub_keyblock)
|
2019-07-10 08:42:07 +02:00
|
|
|
|
pub_keyblock = lastnode = pubnode;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
else
|
2019-07-10 08:42:07 +02:00
|
|
|
|
{
|
|
|
|
|
lastnode->next = pubnode;
|
|
|
|
|
lastnode = pubnode;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return pub_keyblock;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-15 19:50:37 +01:00
|
|
|
|
|
|
|
|
|
/* Delete all notes in the keyblock at R_KEYBLOCK which are not in
|
|
|
|
|
* PUB_KEYBLOCK. Modifies the tags of both keyblock's nodes. */
|
|
|
|
|
static gpg_error_t
|
2019-03-18 13:07:14 +01:00
|
|
|
|
resync_sec_with_pub_keyblock (kbnode_t *r_keyblock, kbnode_t pub_keyblock,
|
|
|
|
|
kbnode_t *r_removedsecs)
|
2019-03-15 19:50:37 +01:00
|
|
|
|
{
|
|
|
|
|
kbnode_t sec_keyblock = *r_keyblock;
|
2019-03-18 13:07:14 +01:00
|
|
|
|
kbnode_t node, prevnode;
|
2019-03-15 19:50:37 +01:00
|
|
|
|
unsigned int *taglist;
|
|
|
|
|
unsigned int ntaglist, n;
|
2019-03-18 13:07:14 +01:00
|
|
|
|
kbnode_t attic = NULL;
|
|
|
|
|
kbnode_t *attic_head = &attic;
|
2019-03-15 19:50:37 +01:00
|
|
|
|
|
|
|
|
|
/* Collect all tags in an array for faster searching. */
|
|
|
|
|
for (ntaglist = 0, node = pub_keyblock; node; node = node->next)
|
|
|
|
|
ntaglist++;
|
|
|
|
|
taglist = xtrycalloc (ntaglist, sizeof *taglist);
|
|
|
|
|
if (!taglist)
|
|
|
|
|
return gpg_error_from_syserror ();
|
|
|
|
|
for (ntaglist = 0, node = pub_keyblock; node; node = node->next)
|
|
|
|
|
taglist[ntaglist++] = node->tag;
|
|
|
|
|
|
|
|
|
|
/* Walks over the secret keyblock and delete all nodes which are not
|
2019-03-18 13:07:14 +01:00
|
|
|
|
* in the tag list. Those nodes have been deleted in the
|
|
|
|
|
* pub_keyblock. Sequential search is a bit lazy and could be
|
|
|
|
|
* optimized by sorting and bsearch; however secret keyrings are
|
|
|
|
|
* short and there are easier ways to DoS the import. */
|
|
|
|
|
again:
|
|
|
|
|
for (prevnode=NULL, node=sec_keyblock; node; prevnode=node, node=node->next)
|
2019-03-15 19:50:37 +01:00
|
|
|
|
{
|
|
|
|
|
for (n=0; n < ntaglist; n++)
|
|
|
|
|
if (taglist[n] == node->tag)
|
|
|
|
|
break;
|
2019-03-18 13:07:14 +01:00
|
|
|
|
if (n == ntaglist) /* Not in public keyblock. */
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_SECRET_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
if (!prevnode)
|
|
|
|
|
sec_keyblock = node->next;
|
|
|
|
|
else
|
|
|
|
|
prevnode->next = node->next;
|
|
|
|
|
node->next = NULL;
|
|
|
|
|
*attic_head = node;
|
|
|
|
|
attic_head = &node->next;
|
|
|
|
|
goto again; /* That's lame; I know. */
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
}
|
2019-03-15 19:50:37 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
xfree (taglist);
|
|
|
|
|
|
|
|
|
|
/* Commit the as deleted marked nodes and return the possibly
|
2019-03-18 13:07:14 +01:00
|
|
|
|
* modified keyblock and a list of removed secret key nodes. */
|
2019-03-15 19:50:37 +01:00
|
|
|
|
commit_kbnode (&sec_keyblock);
|
|
|
|
|
*r_keyblock = sec_keyblock;
|
2019-03-18 13:07:14 +01:00
|
|
|
|
*r_removedsecs = attic;
|
2019-03-15 19:50:37 +01:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-03-18 13:07:14 +01:00
|
|
|
|
/* Helper for import_secret_one. */
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
do_transfer (ctrl_t ctrl, kbnode_t keyblock, PKT_public_key *pk,
|
|
|
|
|
struct import_stats_s *stats, int batch, int only_marked)
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
struct import_stats_s subkey_stats = {0};
|
2023-04-18 02:53:24 +02:00
|
|
|
|
int force = 0;
|
|
|
|
|
int already_exist = agent_probe_secret_key (ctrl, pk);
|
|
|
|
|
|
2023-04-25 06:47:49 +02:00
|
|
|
|
if (already_exist == 2 || already_exist == 4)
|
2023-04-18 02:53:24 +02:00
|
|
|
|
{
|
|
|
|
|
if (!opt.quiet)
|
|
|
|
|
log_info (_("key %s: card reference is overridden by key material\n"),
|
|
|
|
|
keystr_from_pk (pk));
|
|
|
|
|
force = 1;
|
|
|
|
|
}
|
2019-03-18 13:07:14 +01:00
|
|
|
|
|
|
|
|
|
err = transfer_secret_keys (ctrl, &subkey_stats, keyblock,
|
2023-04-18 02:53:24 +02:00
|
|
|
|
batch, force, only_marked);
|
2019-03-18 13:07:14 +01:00
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_NOT_PROCESSED)
|
|
|
|
|
{
|
|
|
|
|
/* TRANSLATORS: For a smartcard, each private key on host has a
|
|
|
|
|
* reference (stub) to a smartcard and actual private key data
|
|
|
|
|
* is stored on the card. A single smartcard can have up to
|
|
|
|
|
* three private key data. Importing private key stub is always
|
|
|
|
|
* skipped in 2.1, and it returns GPG_ERR_NOT_PROCESSED.
|
|
|
|
|
* Instead, user should be suggested to run 'gpg --card-status',
|
|
|
|
|
* then, references to a card will be automatically created
|
|
|
|
|
* again. */
|
|
|
|
|
log_info (_("To migrate '%s', with each smartcard, "
|
|
|
|
|
"run: %s\n"), "secring.gpg", "gpg --card-status");
|
|
|
|
|
err = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!err)
|
|
|
|
|
{
|
|
|
|
|
int status = 16;
|
|
|
|
|
|
|
|
|
|
if (!opt.quiet)
|
|
|
|
|
log_info (_("key %s: secret key imported\n"), keystr_from_pk (pk));
|
|
|
|
|
if (subkey_stats.secret_imported)
|
|
|
|
|
{
|
|
|
|
|
status |= 1;
|
|
|
|
|
stats->secret_imported += 1;
|
|
|
|
|
}
|
|
|
|
|
if (subkey_stats.secret_dups)
|
|
|
|
|
stats->secret_dups += 1;
|
|
|
|
|
|
|
|
|
|
if (is_status_enabled ())
|
|
|
|
|
print_import_ok (pk, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* If the secret keys (main or subkey) in SECKEYS have a corresponding
|
|
|
|
|
* public key in the public key described by (FPR,FPRLEN) import these
|
|
|
|
|
* parts.
|
|
|
|
|
*/
|
|
|
|
|
static gpg_error_t
|
|
|
|
|
import_matching_seckeys (ctrl_t ctrl, kbnode_t seckeys,
|
|
|
|
|
const byte *mainfpr, size_t mainfprlen,
|
|
|
|
|
struct import_stats_s *stats, int batch)
|
|
|
|
|
{
|
|
|
|
|
gpg_error_t err;
|
|
|
|
|
kbnode_t pub_keyblock = NULL;
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
struct { byte fpr[MAX_FINGERPRINT_LEN]; size_t fprlen; } *fprlist = NULL;
|
|
|
|
|
size_t n, nfprlist;
|
|
|
|
|
byte fpr[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t fprlen;
|
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
|
|
|
|
|
/* Get the entire public key block from our keystore and put all its
|
|
|
|
|
* fingerprints into an array. */
|
2024-06-04 15:25:51 +02:00
|
|
|
|
err = get_pubkey_byfpr (ctrl, NULL, &pub_keyblock, mainfpr, mainfprlen);
|
2019-03-18 13:07:14 +01:00
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
log_assert (pub_keyblock && pub_keyblock->pkt->pkttype == PKT_PUBLIC_KEY);
|
|
|
|
|
pk = pub_keyblock->pkt->pkt.public_key;
|
|
|
|
|
|
|
|
|
|
for (nfprlist = 0, node = pub_keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
nfprlist++;
|
|
|
|
|
log_assert (nfprlist);
|
|
|
|
|
fprlist = xtrycalloc (nfprlist, sizeof *fprlist);
|
|
|
|
|
if (!fprlist)
|
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
for (n = 0, node = pub_keyblock; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_KEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
fingerprint_from_pk (node->pkt->pkt.public_key,
|
|
|
|
|
fprlist[n].fpr, &fprlist[n].fprlen);
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
log_assert (n == nfprlist);
|
|
|
|
|
|
|
|
|
|
/* for (n=0; n < nfprlist; n++) */
|
|
|
|
|
/* log_printhex (fprlist[n].fpr, fprlist[n].fprlen, "pubkey %zu:", n); */
|
|
|
|
|
|
|
|
|
|
/* Mark all secret keys which have a matching public key part in
|
|
|
|
|
* PUB_KEYBLOCK. */
|
|
|
|
|
for (node = seckeys; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype != PKT_SECRET_KEY
|
|
|
|
|
&& node->pkt->pkttype != PKT_SECRET_SUBKEY)
|
|
|
|
|
continue; /* Should not happen. */
|
|
|
|
|
fingerprint_from_pk (node->pkt->pkt.public_key, fpr, &fprlen);
|
|
|
|
|
node->flag &= ~NODE_TRANSFER_SECKEY;
|
|
|
|
|
for (n=0; n < nfprlist; n++)
|
|
|
|
|
if (fprlist[n].fprlen == fprlen && !memcmp (fprlist[n].fpr,fpr,fprlen))
|
|
|
|
|
{
|
|
|
|
|
node->flag |= NODE_TRANSFER_SECKEY;
|
|
|
|
|
/* log_debug ("found matching seckey\n"); */
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Transfer all marked keys. */
|
|
|
|
|
err = do_transfer (ctrl, seckeys, pk, stats, batch, 1);
|
|
|
|
|
|
|
|
|
|
leave:
|
|
|
|
|
xfree (fprlist);
|
|
|
|
|
release_kbnode (pub_keyblock);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Import function for a single secret keyblock. Handling is simpler
|
|
|
|
|
* than for public keys. We allow secret key importing only when
|
|
|
|
|
* allow is true, this is so that a secret key can not be imported
|
|
|
|
|
* accidentally and thereby tampering with the trust calculation.
|
|
|
|
|
*
|
|
|
|
|
* Ownership of KEYBLOCK is transferred to this function!
|
|
|
|
|
*
|
|
|
|
|
* If R_SECATTIC is not null the last special sec_keyblock is stored
|
|
|
|
|
* there.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
2019-03-15 19:50:37 +01:00
|
|
|
|
static gpg_error_t
|
2016-07-06 10:35:36 +02:00
|
|
|
|
import_secret_one (ctrl_t ctrl, kbnode_t keyblock,
|
2019-03-15 19:50:37 +01:00
|
|
|
|
struct import_stats_s *stats, int batch,
|
|
|
|
|
unsigned int options, int for_migration,
|
2019-03-18 13:07:14 +01:00
|
|
|
|
import_screener_t screener, void *screener_arg,
|
|
|
|
|
kbnode_t *r_secattic)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-09-06 21:57:42 +02:00
|
|
|
|
PKT_public_key *pk;
|
|
|
|
|
struct seckey_info *ski;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t node, uidnode;
|
2010-08-31 17:58:39 +02:00
|
|
|
|
u32 keyid[2];
|
2019-03-15 19:50:37 +01:00
|
|
|
|
gpg_error_t err = 0;
|
2011-04-29 12:02:46 +02:00
|
|
|
|
int nr_prev;
|
|
|
|
|
kbnode_t pub_keyblock;
|
2019-03-18 13:07:14 +01:00
|
|
|
|
kbnode_t attic = NULL;
|
|
|
|
|
byte fpr[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t fprlen;
|
2014-02-05 10:37:59 +01:00
|
|
|
|
char pkstrbuf[PUBKEY_STRING_SIZE];
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
/* Get the key and print some info about it */
|
|
|
|
|
node = find_kbnode (keyblock, PKT_SECRET_KEY);
|
|
|
|
|
if (!node)
|
|
|
|
|
BUG ();
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
|
2019-03-18 13:07:14 +01:00
|
|
|
|
fingerprint_from_pk (pk, fpr, &fprlen);
|
2010-09-06 21:57:42 +02:00
|
|
|
|
keyid_from_pk (pk, keyid);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
uidnode = find_next_kbnode (keyblock, PKT_USER_ID);
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2014-08-14 15:20:53 +02:00
|
|
|
|
if (screener && screener (keyblock, screener_arg))
|
|
|
|
|
{
|
|
|
|
|
log_error (_("secret key %s: %s\n"), keystr_from_pk (pk),
|
|
|
|
|
_("rejected by import screener"));
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2014-08-14 15:20:53 +02:00
|
|
|
|
return 0;
|
2020-08-25 10:33:57 +02:00
|
|
|
|
}
|
2014-08-14 15:20:53 +02:00
|
|
|
|
|
2014-06-05 11:19:59 +02:00
|
|
|
|
if (opt.verbose && !for_migration)
|
2010-08-31 17:58:39 +02:00
|
|
|
|
{
|
2019-03-15 19:50:37 +01:00
|
|
|
|
log_info ("sec %s/%s %s ",
|
2014-02-05 10:37:59 +01:00
|
|
|
|
pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
|
2010-09-06 21:57:42 +02:00
|
|
|
|
keystr_from_pk (pk), datestr_from_pk (pk));
|
2010-08-31 17:58:39 +02:00
|
|
|
|
if (uidnode)
|
2010-09-01 11:48:35 +02:00
|
|
|
|
print_utf8_buffer (log_get_stream (), uidnode->pkt->pkt.user_id->name,
|
2010-08-31 17:58:39 +02:00
|
|
|
|
uidnode->pkt->pkt.user_id->len);
|
|
|
|
|
log_printf ("\n");
|
|
|
|
|
}
|
|
|
|
|
stats->secret_read++;
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2024-06-24 11:49:05 +02:00
|
|
|
|
if ((options & IMPORT_ONLY_PUBKEYS))
|
2013-10-04 13:44:39 +02:00
|
|
|
|
{
|
2014-06-05 11:19:59 +02:00
|
|
|
|
if (!for_migration)
|
|
|
|
|
log_error (_("importing secret keys not allowed\n"));
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2013-10-04 13:44:39 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
if (!uidnode)
|
|
|
|
|
{
|
2014-06-05 11:19:59 +02:00
|
|
|
|
if (!for_migration)
|
|
|
|
|
log_error( _("key %s: no user ID\n"), keystr_from_pk (pk));
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-09-06 21:57:42 +02:00
|
|
|
|
|
|
|
|
|
ski = pk->seckey_info;
|
|
|
|
|
if (!ski)
|
|
|
|
|
{
|
|
|
|
|
/* Actually an internal error. */
|
|
|
|
|
log_error ("key %s: secret key info missing\n", keystr_from_pk (pk));
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2010-09-06 21:57:42 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
/* A quick check to not import keys with an invalid protection
|
|
|
|
|
cipher algorithm (only checks the primary key, though). */
|
2010-09-06 21:57:42 +02:00
|
|
|
|
if (ski->algo > 110)
|
2010-08-31 17:58:39 +02:00
|
|
|
|
{
|
2014-06-05 11:19:59 +02:00
|
|
|
|
if (!for_migration)
|
|
|
|
|
log_error (_("key %s: secret key with invalid cipher %d"
|
|
|
|
|
" - skipped\n"), keystr_from_pk (pk), ski->algo);
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2006-04-19 13:26:11 +02:00
|
|
|
|
#ifdef ENABLE_SELINUX_HACKS
|
2010-08-31 17:58:39 +02:00
|
|
|
|
if (1)
|
|
|
|
|
{
|
More cleanup of "allow to".
* README, agent/command.c, agent/keyformat.txt, common/i18n.c,
common/iobuf.c, common/keyserver.h, dirmngr/cdblib.c,
dirmngr/ldap-wrapper.c, doc/DETAILS, doc/TRANSLATE,
doc/announce-2.1.txt, doc/gpg.texi, doc/gpgsm.texi,
doc/scdaemon.texi, doc/tools.texi, doc/whats-new-in-2.1.txt,
g10/export.c, g10/getkey.c, g10/import.c, g10/keyedit.c, m4/ksba.m4,
m4/libgcrypt.m4, m4/ntbtls.m4, po/ca.po, po/cs.po, po/da.po,
po/de.po, po/el.po, po/eo.po, po/es.po, po/et.po, po/fi.po,
po/fr.po, po/gl.po, po/hu.po, po/id.po, po/it.po, po/ja.po,
po/nb.po, po/pl.po, po/pt.po, po/ro.po, po/ru.po, po/sk.po,
po/sv.po, po/tr.po, po/uk.po, po/zh_CN.po, po/zh_TW.po,
scd/app-p15.c, scd/ccid-driver.c, scd/command.c, sm/gpgsm.c,
sm/sign.c, tools/gpgconf-comp.c, tools/gpgtar.h: replace "Allow to"
with clearer text.
In standard English, the normal construction is "${XXX} allows ${YYY}
to" -- that is, the subject (${XXX}) of the sentence is allowing the
object (${YYY}) to do something. When the object is missing, the
phrasing sounds awkward, even if the object is implied by context.
There's almost always a better construction that isn't as awkward.
These changes should make the language a bit clearer.
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2016-08-02 04:19:17 +02:00
|
|
|
|
/* We don't allow importing secret keys because that may be used
|
2010-08-31 17:58:39 +02:00
|
|
|
|
to put a secret key into the keyring and the user might later
|
|
|
|
|
be tricked into signing stuff with that key. */
|
|
|
|
|
log_error (_("importing secret keys not allowed\n"));
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
#endif
|
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
clear_kbnode_flags (keyblock);
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2011-04-29 12:02:46 +02:00
|
|
|
|
nr_prev = stats->skipped_new_keys;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2011-04-29 12:02:46 +02:00
|
|
|
|
/* Make a public key out of the key. */
|
|
|
|
|
pub_keyblock = sec_to_pub_keyblock (keyblock);
|
|
|
|
|
if (!pub_keyblock)
|
2019-03-15 19:50:37 +01:00
|
|
|
|
{
|
|
|
|
|
err = gpg_error_from_syserror ();
|
|
|
|
|
log_error ("key %s: failed to create public key from secret key\n",
|
|
|
|
|
keystr_from_pk (pk));
|
|
|
|
|
}
|
2011-04-29 12:02:46 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2019-03-15 19:50:37 +01:00
|
|
|
|
int valid;
|
|
|
|
|
|
2011-04-29 12:02:46 +02:00
|
|
|
|
/* Note that this outputs an IMPORT_OK status message for the
|
|
|
|
|
public key block, and below we will output another one for
|
|
|
|
|
the secret keys. FIXME? */
|
2016-07-06 10:35:36 +02:00
|
|
|
|
import_one (ctrl, pub_keyblock, stats,
|
2014-08-14 15:20:53 +02:00
|
|
|
|
NULL, NULL, options, 1, for_migration,
|
2019-03-15 19:50:37 +01:00
|
|
|
|
screener, screener_arg, 0, NULL, &valid);
|
2011-04-29 12:02:46 +02:00
|
|
|
|
|
2019-03-15 19:50:37 +01:00
|
|
|
|
/* The secret keyblock may not have nodes which are deleted in
|
|
|
|
|
* the public keyblock. Otherwise we would import just the
|
|
|
|
|
* secret key without having the public key. That would be
|
2019-07-01 21:53:55 +02:00
|
|
|
|
* surprising and clutters our private-keys-v1.d. */
|
2019-03-18 13:07:14 +01:00
|
|
|
|
err = resync_sec_with_pub_keyblock (&keyblock, pub_keyblock, &attic);
|
2019-03-15 19:50:37 +01:00
|
|
|
|
if (err)
|
|
|
|
|
goto leave;
|
|
|
|
|
|
|
|
|
|
if (!valid)
|
|
|
|
|
{
|
2019-03-18 13:07:14 +01:00
|
|
|
|
/* If the block was not valid the primary key is left in the
|
|
|
|
|
* original keyblock because we require that for the first
|
|
|
|
|
* node. Move it to ATTIC. */
|
|
|
|
|
if (keyblock && keyblock->pkt->pkttype == PKT_SECRET_KEY)
|
|
|
|
|
{
|
|
|
|
|
node = keyblock;
|
|
|
|
|
keyblock = node->next;
|
|
|
|
|
node->next = NULL;
|
|
|
|
|
if (attic)
|
|
|
|
|
{
|
|
|
|
|
node->next = attic;
|
|
|
|
|
attic = node;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
attic = node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to import the secret key iff we have a public key. */
|
|
|
|
|
if (attic && !(opt.dry_run || (options & IMPORT_DRY_RUN)))
|
|
|
|
|
err = import_matching_seckeys (ctrl, attic, fpr, fprlen,
|
|
|
|
|
stats, batch);
|
|
|
|
|
else
|
|
|
|
|
err = gpg_error (GPG_ERR_NO_SECKEY);
|
2019-03-15 19:50:37 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2011-04-29 12:02:46 +02:00
|
|
|
|
|
2019-03-18 13:07:14 +01:00
|
|
|
|
/* log_debug ("attic is:\n"); */
|
|
|
|
|
/* dump_kbnode (attic); */
|
|
|
|
|
|
|
|
|
|
/* Proceed with the valid parts of PUBKEYBLOCK. */
|
|
|
|
|
|
2011-04-29 12:02:46 +02:00
|
|
|
|
/* At least we cancel the secret key import when the public key
|
|
|
|
|
import was skipped due to MERGE_ONLY option and a new
|
|
|
|
|
key. */
|
2017-10-19 17:05:39 +02:00
|
|
|
|
if (!(opt.dry_run || (options & IMPORT_DRY_RUN))
|
|
|
|
|
&& stats->skipped_new_keys <= nr_prev)
|
2011-04-29 12:02:46 +02:00
|
|
|
|
{
|
2019-03-15 19:50:37 +01:00
|
|
|
|
/* Read the keyblock again to get the effects of a merge for
|
|
|
|
|
* the public key. */
|
2024-06-04 15:25:51 +02:00
|
|
|
|
err = get_pubkey_byfpr (ctrl, NULL, &node, fpr, fprlen);
|
2019-03-18 13:07:14 +01:00
|
|
|
|
if (err || !node)
|
|
|
|
|
log_error ("key %s: failed to re-lookup public key: %s\n",
|
|
|
|
|
keystr_from_pk (pk), gpg_strerror (err));
|
2010-08-31 17:58:39 +02:00
|
|
|
|
else
|
|
|
|
|
{
|
2019-03-18 13:07:14 +01:00
|
|
|
|
err = do_transfer (ctrl, keyblock, pk, stats, batch, 0);
|
2015-11-02 06:33:38 +01:00
|
|
|
|
if (!err)
|
2019-03-18 13:07:14 +01:00
|
|
|
|
check_prefs (ctrl, node);
|
|
|
|
|
release_kbnode (node);
|
|
|
|
|
|
|
|
|
|
if (!err && attic)
|
2010-08-31 17:58:39 +02:00
|
|
|
|
{
|
2019-03-18 13:07:14 +01:00
|
|
|
|
/* Try to import invalid subkeys. This can be the
|
|
|
|
|
* case if the primary secret key was imported due
|
|
|
|
|
* to --allow-non-selfsigned-uid. */
|
|
|
|
|
err = import_matching_seckeys (ctrl, attic, fpr, fprlen,
|
|
|
|
|
stats, batch);
|
2010-08-31 17:58:39 +02:00
|
|
|
|
}
|
2019-03-18 13:07:14 +01:00
|
|
|
|
|
2010-08-31 17:58:39 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2019-03-15 19:50:37 +01:00
|
|
|
|
leave:
|
2019-03-18 13:07:14 +01:00
|
|
|
|
release_kbnode (keyblock);
|
2019-03-15 19:50:37 +01:00
|
|
|
|
release_kbnode (pub_keyblock);
|
2019-03-18 13:07:14 +01:00
|
|
|
|
if (r_secattic)
|
|
|
|
|
*r_secattic = attic;
|
|
|
|
|
else
|
|
|
|
|
release_kbnode (attic);
|
2019-03-15 19:50:37 +01:00
|
|
|
|
return err;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-06-21 15:06:30 +02:00
|
|
|
|
|
2018-06-21 18:32:13 +02:00
|
|
|
|
/* Return the recocation reason from signature SIG. If no revocation
|
Spelling cleanup.
No functional changes, just fixing minor spelling issues.
---
Most of these were identified from the command line by running:
codespell \
--ignore-words-list fpr,stati,keyserver,keyservers,asign,cas,iff,ifset \
--skip '*.po,ChangeLog*,help.*.txt,*.jpg,*.eps,*.pdf,*.png,*.gpg,*.asc' \
doc g13 g10 kbx agent artwork scd tests tools am common dirmngr sm \
NEWS README README.maint TODO
Signed-off-by: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
2020-02-18 15:34:42 +01:00
|
|
|
|
* reason is available 0 is returned, in other cases the reason
|
2018-06-21 18:32:13 +02:00
|
|
|
|
* (0..255). If R_REASON is not NULL a malloced textual
|
|
|
|
|
* representation of the code is stored there. If R_COMMENT is not
|
|
|
|
|
* NULL the comment from the reason is stored there and its length at
|
|
|
|
|
* R_COMMENTLEN. Note that the value at R_COMMENT is not filtered but
|
|
|
|
|
* user supplied data in UTF8; thus it needs to be escaped for display
|
|
|
|
|
* purposes. Both return values are either NULL or a malloced
|
|
|
|
|
* string/buffer. */
|
|
|
|
|
int
|
|
|
|
|
get_revocation_reason (PKT_signature *sig, char **r_reason,
|
|
|
|
|
char **r_comment, size_t *r_commentlen)
|
|
|
|
|
{
|
|
|
|
|
int reason_seq = 0;
|
|
|
|
|
size_t reason_n;
|
|
|
|
|
const byte *reason_p;
|
|
|
|
|
char reason_code_buf[20];
|
|
|
|
|
const char *reason_text = NULL;
|
|
|
|
|
int reason_code = 0;
|
|
|
|
|
|
|
|
|
|
if (r_reason)
|
|
|
|
|
*r_reason = NULL;
|
|
|
|
|
if (r_comment)
|
|
|
|
|
*r_comment = NULL;
|
|
|
|
|
|
|
|
|
|
/* Skip over empty reason packets. */
|
2019-09-05 20:36:38 +02:00
|
|
|
|
while ((reason_p = enum_sig_subpkt (sig, 1, SIGSUBPKT_REVOC_REASON,
|
2018-06-21 18:32:13 +02:00
|
|
|
|
&reason_n, &reason_seq, NULL))
|
|
|
|
|
&& !reason_n)
|
|
|
|
|
;
|
|
|
|
|
if (reason_p)
|
|
|
|
|
{
|
|
|
|
|
reason_code = *reason_p;
|
|
|
|
|
reason_n--; reason_p++;
|
|
|
|
|
switch (reason_code)
|
|
|
|
|
{
|
|
|
|
|
case 0x00: reason_text = _("No reason specified"); break;
|
|
|
|
|
case 0x01: reason_text = _("Key is superseded"); break;
|
|
|
|
|
case 0x02: reason_text = _("Key has been compromised"); break;
|
|
|
|
|
case 0x03: reason_text = _("Key is no longer used"); break;
|
|
|
|
|
case 0x20: reason_text = _("User ID is no longer valid"); break;
|
|
|
|
|
default:
|
|
|
|
|
snprintf (reason_code_buf, sizeof reason_code_buf,
|
|
|
|
|
"code=%02x", reason_code);
|
|
|
|
|
reason_text = reason_code_buf;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r_reason)
|
|
|
|
|
*r_reason = xstrdup (reason_text);
|
|
|
|
|
|
|
|
|
|
if (r_comment && reason_n)
|
|
|
|
|
{
|
|
|
|
|
*r_comment = xmalloc (reason_n);
|
|
|
|
|
memcpy (*r_comment, reason_p, reason_n);
|
|
|
|
|
*r_commentlen = reason_n;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return reason_code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-06-21 15:06:30 +02:00
|
|
|
|
/* List the recocation signature as a "rvs" record. SIGRC shows the
|
|
|
|
|
* character from the signature verification or 0 if no public key was
|
|
|
|
|
* found. */
|
|
|
|
|
static void
|
|
|
|
|
list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc)
|
|
|
|
|
{
|
|
|
|
|
char *siguid = NULL;
|
|
|
|
|
size_t siguidlen = 0;
|
|
|
|
|
char *issuer_fpr = NULL;
|
2018-06-21 18:32:13 +02:00
|
|
|
|
int reason_code = 0;
|
|
|
|
|
char *reason_text = NULL;
|
|
|
|
|
char *reason_comment = NULL;
|
|
|
|
|
size_t reason_commentlen;
|
2018-06-21 15:06:30 +02:00
|
|
|
|
|
|
|
|
|
if (sigrc != '%' && sigrc != '?' && !opt.fast_list_mode)
|
|
|
|
|
{
|
|
|
|
|
int nouid;
|
|
|
|
|
siguid = get_user_id (ctrl, sig->keyid, &siguidlen, &nouid);
|
|
|
|
|
if (nouid)
|
|
|
|
|
sigrc = '?';
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-21 18:32:13 +02:00
|
|
|
|
reason_code = get_revocation_reason (sig, &reason_text,
|
|
|
|
|
&reason_comment, &reason_commentlen);
|
|
|
|
|
|
2018-06-21 15:06:30 +02:00
|
|
|
|
if (opt.with_colons)
|
|
|
|
|
{
|
|
|
|
|
es_fputs ("rvs:", es_stdout);
|
|
|
|
|
if (sigrc)
|
|
|
|
|
es_putc (sigrc, es_stdout);
|
|
|
|
|
es_fprintf (es_stdout, "::%d:%08lX%08lX:%s:%s:::",
|
|
|
|
|
sig->pubkey_algo,
|
|
|
|
|
(ulong) sig->keyid[0], (ulong) sig->keyid[1],
|
|
|
|
|
colon_datestr_from_sig (sig),
|
|
|
|
|
colon_expirestr_from_sig (sig));
|
|
|
|
|
|
|
|
|
|
if (siguid)
|
|
|
|
|
es_write_sanitized (es_stdout, siguid, siguidlen, ":", NULL);
|
|
|
|
|
|
2018-06-21 18:32:13 +02:00
|
|
|
|
es_fprintf (es_stdout, ":%02x%c", sig->sig_class,
|
2018-06-21 15:06:30 +02:00
|
|
|
|
sig->flags.exportable ? 'x' : 'l');
|
2018-06-21 18:32:13 +02:00
|
|
|
|
if (reason_text)
|
|
|
|
|
es_fprintf (es_stdout, ",%02x", reason_code);
|
|
|
|
|
es_fputs ("::", es_stdout);
|
2018-06-21 15:06:30 +02:00
|
|
|
|
|
|
|
|
|
if ((issuer_fpr = issuer_fpr_string (sig)))
|
|
|
|
|
es_fputs (issuer_fpr, es_stdout);
|
|
|
|
|
|
2018-06-21 18:32:13 +02:00
|
|
|
|
es_fprintf (es_stdout, ":::%d:", sig->digest_algo);
|
|
|
|
|
|
|
|
|
|
if (reason_comment)
|
|
|
|
|
{
|
|
|
|
|
es_fputs ("::::", es_stdout);
|
|
|
|
|
es_write_sanitized (es_stdout, reason_comment, reason_commentlen,
|
|
|
|
|
":", NULL);
|
|
|
|
|
es_putc (':', es_stdout);
|
|
|
|
|
}
|
|
|
|
|
es_putc ('\n', es_stdout);
|
2018-06-21 15:06:30 +02:00
|
|
|
|
|
|
|
|
|
if (opt.show_subpackets)
|
|
|
|
|
print_subpackets_colon (sig);
|
|
|
|
|
}
|
|
|
|
|
else /* Human readable. */
|
|
|
|
|
{
|
|
|
|
|
es_fputs ("rvs", es_stdout);
|
|
|
|
|
es_fprintf (es_stdout, "%c%c %c%c%c%c%c%c %s %s",
|
|
|
|
|
sigrc, (sig->sig_class - 0x10 > 0 &&
|
|
|
|
|
sig->sig_class - 0x10 <
|
|
|
|
|
4) ? '0' + sig->sig_class - 0x10 : ' ',
|
|
|
|
|
sig->flags.exportable ? ' ' : 'L',
|
|
|
|
|
sig->flags.revocable ? ' ' : 'R',
|
|
|
|
|
sig->flags.policy_url ? 'P' : ' ',
|
|
|
|
|
sig->flags.notation ? 'N' : ' ',
|
|
|
|
|
sig->flags.expired ? 'X' : ' ',
|
|
|
|
|
(sig->trust_depth > 9) ? 'T' : (sig->trust_depth >
|
|
|
|
|
0) ? '0' +
|
|
|
|
|
sig->trust_depth : ' ', keystr (sig->keyid),
|
|
|
|
|
datestr_from_sig (sig));
|
|
|
|
|
if (siguid)
|
|
|
|
|
{
|
|
|
|
|
es_fprintf (es_stdout, " ");
|
|
|
|
|
print_utf8_buffer (es_stdout, siguid, siguidlen);
|
|
|
|
|
}
|
|
|
|
|
es_putc ('\n', es_stdout);
|
|
|
|
|
|
|
|
|
|
if (sig->flags.policy_url
|
|
|
|
|
&& (opt.list_options & LIST_SHOW_POLICY_URLS))
|
|
|
|
|
show_policy_url (sig, 3, 0);
|
|
|
|
|
|
|
|
|
|
if (sig->flags.notation && (opt.list_options & LIST_SHOW_NOTATIONS))
|
|
|
|
|
show_notation (sig, 3, 0,
|
|
|
|
|
((opt.list_options & LIST_SHOW_STD_NOTATIONS) ? 1 : 0)
|
|
|
|
|
+
|
|
|
|
|
((opt.list_options & LIST_SHOW_USER_NOTATIONS) ? 2 : 0));
|
|
|
|
|
|
|
|
|
|
if (sig->flags.pref_ks
|
|
|
|
|
&& (opt.list_options & LIST_SHOW_KEYSERVER_URLS))
|
|
|
|
|
show_keyserver_url (sig, 3, 0);
|
2018-06-21 18:32:13 +02:00
|
|
|
|
|
|
|
|
|
if (reason_text)
|
|
|
|
|
{
|
|
|
|
|
es_fprintf (es_stdout, " %s%s\n",
|
|
|
|
|
_("reason for revocation: "), reason_text);
|
|
|
|
|
if (reason_comment)
|
|
|
|
|
{
|
|
|
|
|
const byte *s, *s_lf;
|
|
|
|
|
size_t n, n_lf;
|
|
|
|
|
|
|
|
|
|
s = reason_comment;
|
|
|
|
|
n = reason_commentlen;
|
|
|
|
|
s_lf = NULL;
|
|
|
|
|
do
|
|
|
|
|
{
|
|
|
|
|
/* We don't want any empty lines, so we skip them. */
|
|
|
|
|
for (;n && *s == '\n'; s++, n--)
|
|
|
|
|
;
|
|
|
|
|
if (n)
|
|
|
|
|
{
|
|
|
|
|
s_lf = memchr (s, '\n', n);
|
|
|
|
|
n_lf = s_lf? s_lf - s : n;
|
|
|
|
|
es_fprintf (es_stdout, " %s",
|
|
|
|
|
_("revocation comment: "));
|
|
|
|
|
es_write_sanitized (es_stdout, s, n_lf, NULL, NULL);
|
|
|
|
|
es_putc ('\n', es_stdout);
|
|
|
|
|
s += n_lf; n -= n_lf;
|
|
|
|
|
}
|
|
|
|
|
} while (s_lf);
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-06-21 15:06:30 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
es_fflush (es_stdout);
|
|
|
|
|
|
2018-06-21 18:32:13 +02:00
|
|
|
|
xfree (reason_text);
|
|
|
|
|
xfree (reason_comment);
|
2018-06-21 15:06:30 +02:00
|
|
|
|
xfree (siguid);
|
|
|
|
|
xfree (issuer_fpr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2022-10-28 09:29:30 +02:00
|
|
|
|
/* Import a revocation certificate; only the first packet in the
|
|
|
|
|
* NODE-list is considered. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static int
|
2018-06-12 08:44:55 +02:00
|
|
|
|
import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options,
|
|
|
|
|
struct import_stats_s *stats)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
PKT_public_key *pk = NULL;
|
|
|
|
|
kbnode_t onode;
|
|
|
|
|
kbnode_t keyblock = NULL;
|
|
|
|
|
KEYDB_HANDLE hd = NULL;
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
int rc = 0;
|
2018-06-21 15:06:30 +02:00
|
|
|
|
int sigrc = 0;
|
|
|
|
|
int silent;
|
|
|
|
|
|
|
|
|
|
/* No error output for --show-keys. */
|
|
|
|
|
silent = (options & (IMPORT_SHOW | IMPORT_DRY_RUN));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (node->pkt->pkttype == PKT_SIGNATURE );
|
2017-07-21 17:38:03 +02:00
|
|
|
|
log_assert (IS_KEY_REV (node->pkt->pkt.signature));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2022-10-28 09:29:30 +02:00
|
|
|
|
/* FIXME: We can do better here by using the issuer fingerprint if
|
|
|
|
|
* available. We should also make use of get_keyblock_byfprint_fast. */
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
keyid[0] = node->pkt->pkt.signature->keyid[0];
|
|
|
|
|
keyid[1] = node->pkt->pkt.signature->keyid[1];
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
pk = xmalloc_clear( sizeof *pk );
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = get_pubkey (ctrl, pk, keyid );
|
2015-01-22 12:06:11 +01:00
|
|
|
|
if (gpg_err_code (rc) == GPG_ERR_NO_PUBKEY )
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2018-06-21 15:06:30 +02:00
|
|
|
|
if (!silent)
|
|
|
|
|
log_error (_("key %s: no public key -"
|
|
|
|
|
" can't apply revocation certificate\n"), keystr(keyid));
|
2014-12-04 10:45:53 +01:00
|
|
|
|
rc = 0;
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
else if (rc )
|
|
|
|
|
{
|
2018-06-21 15:06:30 +02:00
|
|
|
|
log_error (_("key %s: public key not found: %s\n"),
|
|
|
|
|
keystr(keyid), gpg_strerror (rc));
|
2014-12-04 10:45:53 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* Read the original keyblock. */
|
2019-09-09 14:34:09 +02:00
|
|
|
|
hd = keydb_new (ctrl);
|
2015-12-03 12:18:32 +01:00
|
|
|
|
if (!hd)
|
|
|
|
|
{
|
|
|
|
|
rc = gpg_error_from_syserror ();
|
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
byte afp[MAX_FINGERPRINT_LEN];
|
|
|
|
|
size_t an;
|
|
|
|
|
|
|
|
|
|
fingerprint_from_pk (pk, afp, &an);
|
2019-03-14 08:54:59 +01:00
|
|
|
|
rc = keydb_search_fpr (hd, afp, an);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
}
|
|
|
|
|
if (rc)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_error (_("key %s: can't locate original keyblock: %s\n"),
|
2015-01-22 12:06:11 +01:00
|
|
|
|
keystr(keyid), gpg_strerror (rc));
|
2014-12-04 10:45:53 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
|
|
|
|
rc = keydb_get_keyblock (hd, &keyblock );
|
|
|
|
|
if (rc)
|
|
|
|
|
{
|
|
|
|
|
log_error (_("key %s: can't read original keyblock: %s\n"),
|
2015-01-22 12:06:11 +01:00
|
|
|
|
keystr(keyid), gpg_strerror (rc));
|
2014-12-04 10:45:53 +01:00
|
|
|
|
goto leave;
|
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* it is okay, that node is not in keyblock because
|
2017-07-21 17:38:03 +02:00
|
|
|
|
* check_key_signature works fine for sig_class 0x20 (KEY_REV) in
|
2018-06-21 15:06:30 +02:00
|
|
|
|
* this special case. SIGRC is only used for IMPORT_SHOW. */
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = check_key_signature (ctrl, keyblock, node, NULL);
|
2018-06-21 15:06:30 +02:00
|
|
|
|
switch (gpg_err_code (rc))
|
|
|
|
|
{
|
|
|
|
|
case 0: sigrc = '!'; break;
|
|
|
|
|
case GPG_ERR_BAD_SIGNATURE: sigrc = '-'; break;
|
|
|
|
|
case GPG_ERR_NO_PUBKEY: sigrc = '?'; break;
|
|
|
|
|
case GPG_ERR_UNUSABLE_PUBKEY: sigrc = '?'; break;
|
|
|
|
|
default: sigrc = '%'; break;
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (rc )
|
|
|
|
|
{
|
2018-06-21 15:06:30 +02:00
|
|
|
|
if (!silent)
|
|
|
|
|
log_error (_("key %s: invalid revocation certificate"
|
|
|
|
|
": %s - rejected\n"), keystr(keyid), gpg_strerror (rc));
|
2014-12-04 10:45:53 +01:00
|
|
|
|
goto leave;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* check whether we already have this */
|
|
|
|
|
for(onode=keyblock->next; onode; onode=onode->next ) {
|
|
|
|
|
if (onode->pkt->pkttype == PKT_USER_ID )
|
|
|
|
|
break;
|
|
|
|
|
else if (onode->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& !cmp_signatures(node->pkt->pkt.signature,
|
|
|
|
|
onode->pkt->pkt.signature))
|
2006-04-19 13:26:11 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
rc = 0;
|
|
|
|
|
goto leave; /* yes, we already know about it */
|
2006-04-19 13:26:11 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* insert it */
|
|
|
|
|
insert_kbnode( keyblock, clone_kbnode(node), 0 );
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2018-06-12 08:44:55 +02:00
|
|
|
|
/* and write the keyblock back unless in dry run mode. */
|
|
|
|
|
if (!(opt.dry_run || (options & IMPORT_DRY_RUN)))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
2018-06-12 08:44:55 +02:00
|
|
|
|
rc = keydb_update_keyblock (ctrl, hd, keyblock );
|
|
|
|
|
if (rc)
|
|
|
|
|
log_error (_("error writing keyring '%s': %s\n"),
|
|
|
|
|
keydb_get_resource_name (hd), gpg_strerror (rc) );
|
|
|
|
|
keydb_release (hd);
|
|
|
|
|
hd = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2018-06-12 08:44:55 +02:00
|
|
|
|
/* we are ready */
|
|
|
|
|
if (!opt.quiet )
|
|
|
|
|
{
|
|
|
|
|
char *p=get_user_id_native (ctrl, keyid);
|
|
|
|
|
log_info( _("key %s: \"%s\" revocation certificate imported\n"),
|
|
|
|
|
keystr(keyid),p);
|
|
|
|
|
xfree(p);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2018-06-12 08:44:55 +02:00
|
|
|
|
/* If the key we just revoked was ultimately trusted, remove its
|
|
|
|
|
* ultimate trust. This doesn't stop the user from putting the
|
|
|
|
|
* ultimate trust back, but is a reasonable solution for now. */
|
|
|
|
|
if (get_ownertrust (ctrl, pk) == TRUST_ULTIMATE)
|
|
|
|
|
clear_ownertrusts (ctrl, pk);
|
|
|
|
|
|
|
|
|
|
revalidation_mark (ctrl);
|
|
|
|
|
}
|
|
|
|
|
stats->n_revoc++;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
leave:
|
2018-06-21 15:06:30 +02:00
|
|
|
|
if ((options & IMPORT_SHOW))
|
|
|
|
|
list_standalone_revocation (ctrl, node->pkt->pkt.signature, sigrc);
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
keydb_release (hd);
|
|
|
|
|
release_kbnode( keyblock );
|
|
|
|
|
free_public_key( pk );
|
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-06-07 10:30:07 +02:00
|
|
|
|
/* Loop over the KEYBLOCK and check all self signatures. KEYID is the
|
|
|
|
|
* keyid of the primary key for reporting purposes. On return the
|
|
|
|
|
* following bits in the node flags are set:
|
2016-07-06 10:35:36 +02:00
|
|
|
|
*
|
|
|
|
|
* - NODE_GOOD_SELFSIG :: User ID or subkey has a self-signature
|
|
|
|
|
* - NODE_BAD_SELFSIG :: Used ID or subkey has an invalid self-signature
|
|
|
|
|
* - NODE_DELETION_MARK :: This node shall be deleted
|
|
|
|
|
*
|
|
|
|
|
* NON_SELF is set to true if there are any sigs other than self-sigs
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* in this keyblock.
|
2016-07-06 10:35:36 +02:00
|
|
|
|
*
|
|
|
|
|
* Returns 0 on success or -1 (but not an error code) if the keyblock
|
|
|
|
|
* is invalid.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2018-06-07 10:30:07 +02:00
|
|
|
|
kbnode_t knode = NULL; /* The node of the current subkey. */
|
|
|
|
|
PKT_public_key *subpk = NULL; /* and its packet. */
|
|
|
|
|
kbnode_t bsnode = NULL; /* Subkey binding signature node. */
|
|
|
|
|
u32 bsdate = 0; /* Timestamp of that node. */
|
|
|
|
|
kbnode_t rsnode = NULL; /* Subkey recocation signature node. */
|
2018-10-25 22:52:58 +02:00
|
|
|
|
u32 rsdate = 0; /* Timestamp of that node. */
|
2010-05-07 15:13:56 +02:00
|
|
|
|
PKT_signature *sig;
|
|
|
|
|
int rc;
|
2018-06-07 10:30:07 +02:00
|
|
|
|
kbnode_t n;
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
|
|
|
|
for (n=keyblock; (n = find_next_kbnode (n, 0)); )
|
2010-05-07 15:13:56 +02:00
|
|
|
|
{
|
|
|
|
|
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-05-07 15:13:56 +02:00
|
|
|
|
knode = n;
|
2018-06-07 10:30:07 +02:00
|
|
|
|
subpk = knode->pkt->pkt.public_key;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
bsdate = 0;
|
|
|
|
|
rsdate = 0;
|
|
|
|
|
bsnode = NULL;
|
|
|
|
|
rsnode = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if ( n->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
|
continue;
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
sig = n->pkt->pkt.signature;
|
|
|
|
|
if ( keyid[0] != sig->keyid[0] || keyid[1] != sig->keyid[1] )
|
|
|
|
|
{
|
|
|
|
|
*non_self = 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
/* This just caches the sigs for later use. That way we
|
|
|
|
|
import a fully-cached key which speeds things up. */
|
|
|
|
|
if (!opt.no_sig_cache)
|
2017-03-31 20:03:52 +02:00
|
|
|
|
check_key_signature (ctrl, keyblock, n, NULL);
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if ( IS_UID_SIG(sig) || IS_UID_REV(sig) )
|
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t unode = find_prev_kbnode( keyblock, n, PKT_USER_ID );
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if ( !unode )
|
|
|
|
|
{
|
|
|
|
|
log_error( _("key %s: no user ID for signature\n"),
|
|
|
|
|
keystr(keyid));
|
|
|
|
|
return -1; /* The complete keyblock is invalid. */
|
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
/* If it hasn't been marked valid yet, keep trying. */
|
2016-07-06 10:35:36 +02:00
|
|
|
|
if (!(unode->flag & NODE_GOOD_SELFSIG))
|
2010-05-07 15:13:56 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = check_key_signature (ctrl, keyblock, n, NULL);
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if ( rc )
|
|
|
|
|
{
|
|
|
|
|
if ( opt.verbose )
|
|
|
|
|
{
|
2011-02-02 15:48:54 +01:00
|
|
|
|
char *p = utf8_to_native
|
2010-05-07 15:13:56 +02:00
|
|
|
|
(unode->pkt->pkt.user_id->name,
|
|
|
|
|
strlen (unode->pkt->pkt.user_id->name),0);
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_info (gpg_err_code(rc) == GPG_ERR_PUBKEY_ALGO ?
|
2010-05-07 15:13:56 +02:00
|
|
|
|
_("key %s: unsupported public key "
|
|
|
|
|
"algorithm on user ID \"%s\"\n"):
|
|
|
|
|
_("key %s: invalid self-signature "
|
|
|
|
|
"on user ID \"%s\"\n"),
|
|
|
|
|
keystr (keyid),p);
|
|
|
|
|
xfree (p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-07-06 10:35:36 +02:00
|
|
|
|
unode->flag |= NODE_GOOD_SELFSIG;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (IS_KEY_SIG (sig))
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = check_key_signature (ctrl, keyblock, n, NULL);
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if ( rc )
|
|
|
|
|
{
|
|
|
|
|
if (opt.verbose)
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ?
|
2010-05-07 15:13:56 +02:00
|
|
|
|
_("key %s: unsupported public key algorithm\n"):
|
|
|
|
|
_("key %s: invalid direct key signature\n"),
|
|
|
|
|
keystr (keyid));
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_DELETION_MARK;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
else if ( IS_SUBKEY_SIG (sig) )
|
2010-05-07 15:13:56 +02:00
|
|
|
|
{
|
|
|
|
|
/* Note that this works based solely on the timestamps like
|
|
|
|
|
the rest of gpg. If the standard gets revocation
|
|
|
|
|
targets, this may need to be revised. */
|
|
|
|
|
|
|
|
|
|
if ( !knode )
|
|
|
|
|
{
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
log_info (_("key %s: no subkey for key binding\n"),
|
|
|
|
|
keystr (keyid));
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_DELETION_MARK;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = check_key_signature (ctrl, keyblock, n, NULL);
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if ( rc )
|
|
|
|
|
{
|
|
|
|
|
if (opt.verbose)
|
2018-06-07 10:30:07 +02:00
|
|
|
|
{
|
|
|
|
|
keyid_from_pk (subpk, NULL);
|
|
|
|
|
log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ?
|
|
|
|
|
_("key %s: unsupported public key"
|
|
|
|
|
" algorithm\n"):
|
|
|
|
|
_("key %s: invalid subkey binding\n"),
|
|
|
|
|
keystr_with_sub (keyid, subpk->keyid));
|
|
|
|
|
}
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_DELETION_MARK;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* It's valid, so is it newer? */
|
2011-02-02 15:48:54 +01:00
|
|
|
|
if (sig->timestamp >= bsdate)
|
2010-05-07 15:13:56 +02:00
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
knode->flag |= NODE_GOOD_SELFSIG; /* Subkey is valid. */
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if (bsnode)
|
|
|
|
|
{
|
|
|
|
|
/* Delete the last binding sig since this
|
|
|
|
|
one is newer */
|
2016-07-06 10:35:36 +02:00
|
|
|
|
bsnode->flag |= NODE_DELETION_MARK;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if (opt.verbose)
|
2018-06-07 10:30:07 +02:00
|
|
|
|
{
|
|
|
|
|
keyid_from_pk (subpk, NULL);
|
|
|
|
|
log_info (_("key %s: removed multiple subkey"
|
|
|
|
|
" binding\n"),
|
|
|
|
|
keystr_with_sub (keyid, subpk->keyid));
|
|
|
|
|
}
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
bsnode = n;
|
|
|
|
|
bsdate = sig->timestamp;
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_DELETION_MARK; /* older */
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ( IS_SUBKEY_REV (sig) )
|
|
|
|
|
{
|
|
|
|
|
/* We don't actually mark the subkey as revoked right now,
|
|
|
|
|
so just check that the revocation sig is the most recent
|
|
|
|
|
valid one. Note that we don't care if the binding sig is
|
|
|
|
|
newer than the revocation sig. See the comment in
|
|
|
|
|
getkey.c:merge_selfsigs_subkey for more. */
|
|
|
|
|
if ( !knode )
|
|
|
|
|
{
|
|
|
|
|
if (opt.verbose)
|
|
|
|
|
log_info (_("key %s: no subkey for key revocation\n"),
|
|
|
|
|
keystr(keyid));
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_DELETION_MARK;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
rc = check_key_signature (ctrl, keyblock, n, NULL);
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if ( rc )
|
|
|
|
|
{
|
|
|
|
|
if(opt.verbose)
|
2015-01-22 12:06:11 +01:00
|
|
|
|
log_info (gpg_err_code (rc) == GPG_ERR_PUBKEY_ALGO ?
|
2010-05-07 15:13:56 +02:00
|
|
|
|
_("key %s: unsupported public"
|
|
|
|
|
" key algorithm\n"):
|
|
|
|
|
_("key %s: invalid subkey revocation\n"),
|
|
|
|
|
keystr(keyid));
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_DELETION_MARK;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* It's valid, so is it newer? */
|
|
|
|
|
if (sig->timestamp >= rsdate)
|
|
|
|
|
{
|
|
|
|
|
if (rsnode)
|
|
|
|
|
{
|
|
|
|
|
/* Delete the last revocation sig since
|
|
|
|
|
this one is newer. */
|
2016-07-06 10:35:36 +02:00
|
|
|
|
rsnode->flag |= NODE_DELETION_MARK;
|
2010-05-07 15:13:56 +02:00
|
|
|
|
if (opt.verbose)
|
|
|
|
|
log_info (_("key %s: removed multiple subkey"
|
|
|
|
|
" revocation\n"),keystr(keyid));
|
|
|
|
|
}
|
2011-02-02 15:48:54 +01:00
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
rsnode = n;
|
|
|
|
|
rsdate = sig->timestamp;
|
|
|
|
|
}
|
|
|
|
|
else
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_DELETION_MARK; /* older */
|
2010-05-07 15:13:56 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-05-07 15:13:56 +02:00
|
|
|
|
|
2016-07-06 10:35:36 +02:00
|
|
|
|
/* Delete all parts which are invalid and those signatures whose
|
2017-04-28 03:06:33 +02:00
|
|
|
|
* public key algorithm is not available in this implementation; but
|
2016-07-06 10:35:36 +02:00
|
|
|
|
* consider RSA as valid, because parse/build_packets knows about it.
|
2022-10-28 09:29:30 +02:00
|
|
|
|
* If R_OTHERREVSIGS is not NULL, it is used to return a list of
|
|
|
|
|
* revocation certificates which have been deleted from KEYBLOCK but
|
|
|
|
|
* should be handled later.
|
2016-07-06 10:35:36 +02:00
|
|
|
|
*
|
|
|
|
|
* Returns: True if at least one valid user-id is left over.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
2017-03-31 20:03:52 +02:00
|
|
|
|
delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
2022-10-28 09:29:30 +02:00
|
|
|
|
unsigned int options, kbnode_t *r_otherrevsigs)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t node;
|
|
|
|
|
int nvalid=0, uid_seen=0, subkey_seen=0;
|
2018-06-07 10:30:07 +02:00
|
|
|
|
PKT_public_key *pk;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
for (node=keyblock->next; node; node = node->next )
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
uid_seen = 1;
|
2016-07-06 10:35:36 +02:00
|
|
|
|
if ((node->flag & NODE_BAD_SELFSIG)
|
|
|
|
|
|| !(node->flag & NODE_GOOD_SELFSIG))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
if (opt.verbose )
|
|
|
|
|
{
|
|
|
|
|
char *p=utf8_to_native(node->pkt->pkt.user_id->name,
|
|
|
|
|
node->pkt->pkt.user_id->len,0);
|
|
|
|
|
log_info( _("key %s: skipped user ID \"%s\"\n"),
|
|
|
|
|
keystr(keyid),p);
|
|
|
|
|
xfree(p);
|
|
|
|
|
}
|
|
|
|
|
delete_kbnode( node ); /* the user-id */
|
|
|
|
|
/* and all following packets up to the next user-id */
|
|
|
|
|
while (node->next
|
|
|
|
|
&& node->next->pkt->pkttype != PKT_USER_ID
|
|
|
|
|
&& node->next->pkt->pkttype != PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& node->next->pkt->pkttype != PKT_SECRET_SUBKEY ){
|
|
|
|
|
delete_kbnode( node->next );
|
|
|
|
|
node = node->next;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else
|
|
|
|
|
nvalid++;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if ( node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY )
|
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
if ((node->flag & NODE_BAD_SELFSIG)
|
|
|
|
|
|| !(node->flag & NODE_GOOD_SELFSIG))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
if (opt.verbose )
|
2018-06-07 10:30:07 +02:00
|
|
|
|
{
|
|
|
|
|
pk = node->pkt->pkt.public_key;
|
|
|
|
|
keyid_from_pk (pk, NULL);
|
|
|
|
|
log_info (_("key %s: skipped subkey\n"),
|
|
|
|
|
keystr_with_sub (keyid, pk->keyid));
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
delete_kbnode( node ); /* the subkey */
|
|
|
|
|
/* and all following signature packets */
|
|
|
|
|
while (node->next
|
|
|
|
|
&& node->next->pkt->pkttype == PKT_SIGNATURE ) {
|
|
|
|
|
delete_kbnode( node->next );
|
|
|
|
|
node = node->next;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else
|
|
|
|
|
subkey_seen = 1;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& openpgp_pk_test_algo (node->pkt->pkt.signature->pubkey_algo)
|
|
|
|
|
&& node->pkt->pkt.signature->pubkey_algo != PUBKEY_ALGO_RSA )
|
|
|
|
|
{
|
|
|
|
|
delete_kbnode( node ); /* build_packet() can't handle this */
|
|
|
|
|
}
|
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& !node->pkt->pkt.signature->flags.exportable
|
|
|
|
|
&& !(options&IMPORT_LOCAL_SIGS)
|
2019-09-09 14:34:09 +02:00
|
|
|
|
&& !have_secret_key_with_kid (ctrl,
|
|
|
|
|
node->pkt->pkt.signature->keyid))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
/* here we violate the rfc a bit by still allowing
|
|
|
|
|
* to import non-exportable signature when we have the
|
|
|
|
|
* the secret key used to create this signature - it
|
|
|
|
|
* seems that this makes sense */
|
|
|
|
|
if(opt.verbose)
|
|
|
|
|
log_info( _("key %s: non exportable signature"
|
|
|
|
|
" (class 0x%02X) - skipped\n"),
|
|
|
|
|
keystr(keyid), node->pkt->pkt.signature->sig_class );
|
|
|
|
|
delete_kbnode( node );
|
|
|
|
|
}
|
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 17:38:03 +02:00
|
|
|
|
&& IS_KEY_REV (node->pkt->pkt.signature))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
if (uid_seen )
|
|
|
|
|
{
|
|
|
|
|
if(opt.verbose)
|
|
|
|
|
log_info( _("key %s: revocation certificate"
|
|
|
|
|
" at wrong place - skipped\n"),keystr(keyid));
|
2022-10-28 09:29:30 +02:00
|
|
|
|
if (r_otherrevsigs)
|
|
|
|
|
{
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
|
|
|
|
|
pkt = xcalloc (1, sizeof *pkt);
|
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = copy_signature
|
|
|
|
|
(NULL, node->pkt->pkt.signature);
|
|
|
|
|
*r_otherrevsigs = new_kbnode2 (*r_otherrevsigs, pkt);
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
delete_kbnode( node );
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* If the revocation cert is from a different key than
|
|
|
|
|
the one we're working on don't check it - it's
|
|
|
|
|
probably from a revocation key and won't be
|
|
|
|
|
verifiable with this key anyway. */
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if(node->pkt->pkt.signature->keyid[0]==keyid[0]
|
|
|
|
|
&& node->pkt->pkt.signature->keyid[1]==keyid[1])
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
int rc = check_key_signature (ctrl, keyblock, node, NULL);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (rc )
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2006-04-19 13:26:11 +02:00
|
|
|
|
if(opt.verbose)
|
|
|
|
|
log_info( _("key %s: invalid revocation"
|
|
|
|
|
" certificate: %s - skipped\n"),
|
2015-01-22 12:06:11 +01:00
|
|
|
|
keystr(keyid), gpg_strerror (rc));
|
2003-06-05 09:14:21 +02:00
|
|
|
|
delete_kbnode( node );
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-28 09:29:30 +02:00
|
|
|
|
else if (r_otherrevsigs)
|
|
|
|
|
{
|
|
|
|
|
PACKET *pkt;
|
|
|
|
|
|
|
|
|
|
pkt = xcalloc (1, sizeof *pkt);
|
|
|
|
|
pkt->pkttype = PKT_SIGNATURE;
|
|
|
|
|
pkt->pkt.signature = copy_signature
|
|
|
|
|
(NULL, node->pkt->pkt.signature);
|
|
|
|
|
*r_otherrevsigs = new_kbnode2 (*r_otherrevsigs, pkt);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 17:38:03 +02:00
|
|
|
|
&& (IS_SUBKEY_SIG (node->pkt->pkt.signature)
|
|
|
|
|
|| IS_SUBKEY_REV (node->pkt->pkt.signature))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
&& !subkey_seen )
|
|
|
|
|
{
|
|
|
|
|
if(opt.verbose)
|
|
|
|
|
log_info( _("key %s: subkey signature"
|
|
|
|
|
" in wrong place - skipped\n"), keystr(keyid));
|
|
|
|
|
delete_kbnode( node );
|
|
|
|
|
}
|
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& !IS_CERT(node->pkt->pkt.signature))
|
|
|
|
|
{
|
|
|
|
|
if(opt.verbose)
|
|
|
|
|
log_info(_("key %s: unexpected signature class (0x%02X) -"
|
|
|
|
|
" skipped\n"),keystr(keyid),
|
|
|
|
|
node->pkt->pkt.signature->sig_class);
|
|
|
|
|
delete_kbnode(node);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2016-07-06 10:35:36 +02:00
|
|
|
|
else if ((node->flag & NODE_DELETION_MARK))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
delete_kbnode( node );
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* note: because keyblock is the public key, it is never marked
|
|
|
|
|
* for deletion and so keyblock cannot change */
|
|
|
|
|
commit_kbnode( &keyblock );
|
|
|
|
|
return nvalid;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-28 15:32:04 +02:00
|
|
|
|
/* This function returns true if any UID is left in the keyring. */
|
|
|
|
|
static int
|
|
|
|
|
any_uid_left (kbnode_t keyblock)
|
|
|
|
|
{
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
|
|
|
|
|
for (node=keyblock->next; node; node = node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
return 1;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2019-07-01 21:53:55 +02:00
|
|
|
|
/* Delete all non-self-sigs from KEYBLOCK.
|
|
|
|
|
* Returns: True if the keyblock has changed. */
|
|
|
|
|
static void
|
|
|
|
|
remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid)
|
|
|
|
|
{
|
|
|
|
|
kbnode_t node;
|
|
|
|
|
unsigned int dropped = 0;
|
|
|
|
|
|
|
|
|
|
for (node = *keyblock; node; node = node->next)
|
|
|
|
|
{
|
|
|
|
|
if (is_deleted_kbnode (node))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (node->pkt->pkttype != PKT_SIGNATURE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (node->pkt->pkt.signature->keyid[0] == keyid[0]
|
|
|
|
|
&& node->pkt->pkt.signature->keyid[1] == keyid[1])
|
|
|
|
|
continue;
|
|
|
|
|
delete_kbnode (node);
|
|
|
|
|
dropped++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dropped)
|
|
|
|
|
commit_kbnode (keyblock);
|
|
|
|
|
|
|
|
|
|
if (dropped && opt.verbose)
|
|
|
|
|
log_info ("key %s: number of dropped non-self-signatures: %u\n",
|
|
|
|
|
keystr (keyid), dropped);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-02 11:02:08 +02:00
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* It may happen that the imported keyblock has duplicated user IDs.
|
|
|
|
|
* We check this here and collapse those user IDs together with their
|
|
|
|
|
* sigs into one.
|
2007-10-25 11:06:21 +02:00
|
|
|
|
* Returns: True if the keyblock has changed.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
int
|
2018-10-02 11:02:08 +02:00
|
|
|
|
collapse_uids (kbnode_t *keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t uid1;
|
2007-10-25 11:06:21 +02:00
|
|
|
|
int any=0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
for(uid1=*keyblock;uid1;uid1=uid1->next)
|
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t uid2;
|
2007-10-25 11:06:21 +02:00
|
|
|
|
|
2008-03-25 09:33:31 +01:00
|
|
|
|
if(is_deleted_kbnode(uid1))
|
|
|
|
|
continue;
|
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
if(uid1->pkt->pkttype!=PKT_USER_ID)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for(uid2=uid1->next;uid2;uid2=uid2->next)
|
|
|
|
|
{
|
2008-03-25 09:33:31 +01:00
|
|
|
|
if(is_deleted_kbnode(uid2))
|
|
|
|
|
continue;
|
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
if(uid2->pkt->pkttype!=PKT_USER_ID)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
continue;
|
2007-10-25 11:06:21 +02:00
|
|
|
|
|
|
|
|
|
if(cmp_user_ids(uid1->pkt->pkt.user_id,
|
|
|
|
|
uid2->pkt->pkt.user_id)==0)
|
|
|
|
|
{
|
|
|
|
|
/* We have a duplicated uid */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t sig1,last;
|
2007-10-25 11:06:21 +02:00
|
|
|
|
|
|
|
|
|
any=1;
|
|
|
|
|
|
|
|
|
|
/* Now take uid2's signatures, and attach them to
|
|
|
|
|
uid1 */
|
|
|
|
|
for(last=uid2;last->next;last=last->next)
|
|
|
|
|
{
|
2008-03-25 09:33:31 +01:00
|
|
|
|
if(is_deleted_kbnode(last))
|
|
|
|
|
continue;
|
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
if(last->next->pkt->pkttype==PKT_USER_ID
|
|
|
|
|
|| last->next->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| last->next->pkt->pkttype==PKT_SECRET_SUBKEY)
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
/* Snip out uid2 */
|
|
|
|
|
(find_prev_kbnode(*keyblock,uid2,0))->next=last->next;
|
|
|
|
|
|
|
|
|
|
/* Now put uid2 in place as part of uid1 */
|
|
|
|
|
last->next=uid1->next;
|
|
|
|
|
uid1->next=uid2;
|
2008-03-25 09:33:31 +01:00
|
|
|
|
delete_kbnode(uid2);
|
2007-10-25 11:06:21 +02:00
|
|
|
|
|
|
|
|
|
/* Now dedupe uid1 */
|
|
|
|
|
for(sig1=uid1->next;sig1;sig1=sig1->next)
|
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t sig2;
|
2007-10-25 11:06:21 +02:00
|
|
|
|
|
2008-03-25 09:33:31 +01:00
|
|
|
|
if(is_deleted_kbnode(sig1))
|
|
|
|
|
continue;
|
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
if(sig1->pkt->pkttype==PKT_USER_ID
|
|
|
|
|
|| sig1->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| sig1->pkt->pkttype==PKT_SECRET_SUBKEY)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if(sig1->pkt->pkttype!=PKT_SIGNATURE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
for(sig2=sig1->next,last=sig1;sig2;last=sig2,sig2=sig2->next)
|
|
|
|
|
{
|
2008-03-25 09:33:31 +01:00
|
|
|
|
if(is_deleted_kbnode(sig2))
|
|
|
|
|
continue;
|
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
if(sig2->pkt->pkttype==PKT_USER_ID
|
|
|
|
|
|| sig2->pkt->pkttype==PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| sig2->pkt->pkttype==PKT_SECRET_SUBKEY)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
break;
|
2007-10-25 11:06:21 +02:00
|
|
|
|
|
|
|
|
|
if(sig2->pkt->pkttype!=PKT_SIGNATURE)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if(cmp_signatures(sig1->pkt->pkt.signature,
|
|
|
|
|
sig2->pkt->pkt.signature)==0)
|
|
|
|
|
{
|
|
|
|
|
/* We have a match, so delete the second
|
|
|
|
|
signature */
|
2008-03-25 09:33:31 +01:00
|
|
|
|
delete_kbnode(sig2);
|
2007-10-25 11:06:21 +02:00
|
|
|
|
sig2=last;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2007-10-25 11:06:21 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2008-03-25 09:33:31 +01:00
|
|
|
|
commit_kbnode(keyblock);
|
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
if(any && !opt.quiet)
|
|
|
|
|
{
|
|
|
|
|
const char *key="???";
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
if ((uid1 = find_kbnode (*keyblock, PKT_PUBLIC_KEY)) )
|
|
|
|
|
key = keystr_from_pk (uid1->pkt->pkt.public_key);
|
|
|
|
|
else if ((uid1 = find_kbnode( *keyblock, PKT_SECRET_KEY)) )
|
|
|
|
|
key = keystr_from_pk (uid1->pkt->pkt.public_key);
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
log_info (_("key %s: duplicated user ID detected - merged\n"), key);
|
2007-10-25 11:06:21 +02:00
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2007-10-25 11:06:21 +02:00
|
|
|
|
return any;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2020-08-25 10:33:57 +02:00
|
|
|
|
/*
|
|
|
|
|
* It may happen that the imported keyblock has duplicated subkeys.
|
|
|
|
|
* We check this here and collapse those subkeys along with their
|
|
|
|
|
* binding self-signatures.
|
|
|
|
|
* Returns: True if the keyblock has changed.
|
|
|
|
|
*/
|
|
|
|
|
int
|
|
|
|
|
collapse_subkeys (kbnode_t *keyblock)
|
|
|
|
|
{
|
|
|
|
|
kbnode_t kb1, kb2, sig1, sig2, last;
|
|
|
|
|
int any = 0;
|
|
|
|
|
|
|
|
|
|
for (kb1 = *keyblock; kb1; kb1 = kb1->next)
|
|
|
|
|
{
|
|
|
|
|
if (is_deleted_kbnode (kb1))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (kb1->pkt->pkttype != PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& kb1->pkt->pkttype != PKT_SECRET_SUBKEY)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* We assume just a few duplicates and use a straightforward
|
|
|
|
|
* algorithm. */
|
|
|
|
|
for (kb2 = kb1->next; kb2; kb2 = kb2->next)
|
|
|
|
|
{
|
|
|
|
|
if (is_deleted_kbnode (kb2))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (kb2->pkt->pkttype != PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& kb2->pkt->pkttype != PKT_SECRET_SUBKEY)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (cmp_public_keys (kb1->pkt->pkt.public_key,
|
|
|
|
|
kb2->pkt->pkt.public_key))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* We have a duplicated subkey. */
|
|
|
|
|
any = 1;
|
|
|
|
|
|
|
|
|
|
/* Take subkey-2's signatures, and attach them to subkey-1. */
|
|
|
|
|
for (last = kb2; last->next; last = last->next)
|
|
|
|
|
{
|
|
|
|
|
if (is_deleted_kbnode (last))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (last->next->pkt->pkttype != PKT_SIGNATURE)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Snip out subkye-2 */
|
|
|
|
|
find_prev_kbnode (*keyblock, kb2, 0)->next = last->next;
|
|
|
|
|
|
|
|
|
|
/* Put subkey-2 in place as part of subkey-1 */
|
|
|
|
|
last->next = kb1->next;
|
|
|
|
|
kb1->next = kb2;
|
|
|
|
|
delete_kbnode (kb2);
|
|
|
|
|
|
|
|
|
|
/* Now dedupe kb1 */
|
|
|
|
|
for (sig1 = kb1->next; sig1; sig1 = sig1->next)
|
|
|
|
|
{
|
|
|
|
|
if (is_deleted_kbnode (sig1))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (sig1->pkt->pkttype != PKT_SIGNATURE)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
for (sig2 = sig1->next, last = sig1;
|
|
|
|
|
sig2;
|
|
|
|
|
last = sig2, sig2 = sig2->next)
|
|
|
|
|
{
|
|
|
|
|
if (is_deleted_kbnode (sig2))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (sig2->pkt->pkttype != PKT_SIGNATURE)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (!cmp_signatures (sig1->pkt->pkt.signature,
|
|
|
|
|
sig2->pkt->pkt.signature))
|
|
|
|
|
{
|
|
|
|
|
/* We have a match, so delete the second
|
|
|
|
|
signature */
|
|
|
|
|
delete_kbnode (sig2);
|
|
|
|
|
sig2 = last;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
commit_kbnode (keyblock);
|
|
|
|
|
|
|
|
|
|
if (any && !opt.quiet)
|
|
|
|
|
{
|
|
|
|
|
const char *key="???";
|
|
|
|
|
|
|
|
|
|
if ((kb1 = find_kbnode (*keyblock, PKT_PUBLIC_KEY)) )
|
|
|
|
|
key = keystr_from_pk (kb1->pkt->pkt.public_key);
|
|
|
|
|
else if ((kb1 = find_kbnode (*keyblock, PKT_SECRET_KEY)) )
|
|
|
|
|
key = keystr_from_pk (kb1->pkt->pkt.public_key);
|
|
|
|
|
|
|
|
|
|
log_info (_("key %s: duplicated subkeys detected - merged\n"), key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return any;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* Check for a 0x20 revocation from a revocation key that is not
|
2006-04-19 13:26:11 +02:00
|
|
|
|
present. This may be called without the benefit of merge_xxxx so
|
|
|
|
|
you can't rely on pk->revkey and friends. */
|
2003-06-05 09:14:21 +02:00
|
|
|
|
static void
|
2010-10-01 22:33:53 +02:00
|
|
|
|
revocation_present (ctrl_t ctrl, kbnode_t keyblock)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2010-10-01 22:33:53 +02:00
|
|
|
|
kbnode_t onode, inode;
|
|
|
|
|
PKT_public_key *pk = keyblock->pkt->pkt.public_key;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
for(onode=keyblock->next;onode;onode=onode->next)
|
|
|
|
|
{
|
|
|
|
|
/* If we reach user IDs, we're done. */
|
|
|
|
|
if(onode->pkt->pkttype==PKT_USER_ID)
|
|
|
|
|
break;
|
|
|
|
|
|
2017-07-21 17:38:03 +02:00
|
|
|
|
if (onode->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& IS_KEY_SIG (onode->pkt->pkt.signature)
|
|
|
|
|
&& onode->pkt->pkt.signature->revkey)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
int idx;
|
|
|
|
|
PKT_signature *sig=onode->pkt->pkt.signature;
|
|
|
|
|
|
|
|
|
|
for(idx=0;idx<sig->numrevkeys;idx++)
|
|
|
|
|
{
|
|
|
|
|
u32 keyid[2];
|
|
|
|
|
|
2017-03-31 20:03:52 +02:00
|
|
|
|
keyid_from_fingerprint (ctrl, sig->revkey[idx].fpr,
|
2018-12-04 15:43:19 +01:00
|
|
|
|
sig->revkey[idx].fprlen, keyid);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
for(inode=keyblock->next;inode;inode=inode->next)
|
|
|
|
|
{
|
|
|
|
|
/* If we reach user IDs, we're done. */
|
|
|
|
|
if(inode->pkt->pkttype==PKT_USER_ID)
|
|
|
|
|
break;
|
|
|
|
|
|
2017-07-21 17:38:03 +02:00
|
|
|
|
if (inode->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& IS_KEY_REV (inode->pkt->pkt.signature)
|
|
|
|
|
&& inode->pkt->pkt.signature->keyid[0]==keyid[0]
|
|
|
|
|
&& inode->pkt->pkt.signature->keyid[1]==keyid[1])
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
|
|
|
|
/* Okay, we have a revocation key, and a
|
2017-07-21 17:38:03 +02:00
|
|
|
|
* revocation issued by it. Do we have the key
|
|
|
|
|
* itself? */
|
2017-10-18 17:52:41 +02:00
|
|
|
|
gpg_error_t err;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2024-06-04 15:25:51 +02:00
|
|
|
|
err = get_pubkey_byfpr_fast (ctrl, NULL,
|
|
|
|
|
sig->revkey[idx].fpr,
|
|
|
|
|
sig->revkey[idx].fprlen);
|
2017-10-18 17:52:41 +02:00
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY
|
|
|
|
|
|| gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2017-10-18 17:52:41 +02:00
|
|
|
|
char *tempkeystr = xstrdup (keystr_from_pk (pk));
|
2006-04-19 13:26:11 +02:00
|
|
|
|
|
2003-06-05 09:14:21 +02:00
|
|
|
|
/* No, so try and get it */
|
2016-01-21 11:49:27 +01:00
|
|
|
|
if ((opt.keyserver_options.options
|
|
|
|
|
& KEYSERVER_AUTO_KEY_RETRIEVE)
|
|
|
|
|
&& keyserver_any_configured (ctrl))
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2006-04-19 13:26:11 +02:00
|
|
|
|
log_info(_("WARNING: key %s may be revoked:"
|
|
|
|
|
" fetching revocation key %s\n"),
|
|
|
|
|
tempkeystr,keystr(keyid));
|
2024-06-04 15:25:51 +02:00
|
|
|
|
keyserver_import_fpr (ctrl,
|
|
|
|
|
sig->revkey[idx].fpr,
|
|
|
|
|
sig->revkey[idx].fprlen,
|
|
|
|
|
opt.keyserver, 0);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
|
|
|
|
/* Do we have it now? */
|
2024-06-04 15:25:51 +02:00
|
|
|
|
err = get_pubkey_byfpr_fast (ctrl, NULL,
|
2015-08-21 10:38:41 +02:00
|
|
|
|
sig->revkey[idx].fpr,
|
2018-12-04 15:43:19 +01:00
|
|
|
|
sig->revkey[idx].fprlen);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2017-10-18 17:52:41 +02:00
|
|
|
|
if (gpg_err_code (err) == GPG_ERR_NO_PUBKEY
|
|
|
|
|
|| gpg_err_code (err) == GPG_ERR_UNUSABLE_PUBKEY)
|
2006-04-19 13:26:11 +02:00
|
|
|
|
log_info(_("WARNING: key %s may be revoked:"
|
|
|
|
|
" revocation key %s not present.\n"),
|
|
|
|
|
tempkeystr,keystr(keyid));
|
|
|
|
|
|
|
|
|
|
xfree(tempkeystr);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
/*
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* compare and merge the blocks
|
|
|
|
|
*
|
|
|
|
|
* o compare the signatures: If we already have this signature, check
|
|
|
|
|
* that they compare okay; if not, issue a warning and ask the user.
|
|
|
|
|
* o Simply add the signature. Can't verify here because we may not have
|
|
|
|
|
* the signature's public key yet; verification is done when putting it
|
|
|
|
|
* into the trustdb, which is done automagically as soon as this pubkey
|
|
|
|
|
* is used.
|
2016-07-06 10:35:36 +02:00
|
|
|
|
* Note: We indicate newly inserted packets with NODE_FLAG_A.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
|
|
|
|
static int
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
merge_blocks (ctrl_t ctrl, unsigned int options,
|
|
|
|
|
kbnode_t keyblock_orig, kbnode_t keyblock,
|
2017-07-25 11:23:08 +02:00
|
|
|
|
u32 *keyid, u32 curtime, int origin, const char *url,
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
int *n_uids, int *n_sigs, int *n_subk )
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t onode, node;
|
|
|
|
|
int rc, found;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* 1st: handle revocation certificates */
|
|
|
|
|
for (node=keyblock->next; node; node=node->next )
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID )
|
|
|
|
|
break;
|
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 17:38:03 +02:00
|
|
|
|
&& IS_KEY_REV (node->pkt->pkt.signature))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
/* check whether we already have this */
|
|
|
|
|
found = 0;
|
|
|
|
|
for (onode=keyblock_orig->next; onode; onode=onode->next)
|
|
|
|
|
{
|
|
|
|
|
if (onode->pkt->pkttype == PKT_USER_ID )
|
|
|
|
|
break;
|
|
|
|
|
else if (onode->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 17:38:03 +02:00
|
|
|
|
&& IS_KEY_REV (onode->pkt->pkt.signature)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
&& !cmp_signatures(onode->pkt->pkt.signature,
|
|
|
|
|
node->pkt->pkt.signature))
|
|
|
|
|
{
|
|
|
|
|
found = 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!found)
|
|
|
|
|
{
|
|
|
|
|
kbnode_t n2 = clone_kbnode(node);
|
|
|
|
|
insert_kbnode( keyblock_orig, n2, 0 );
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n2->flag |= NODE_FLAG_A;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
++*n_sigs;
|
|
|
|
|
if(!opt.quiet)
|
|
|
|
|
{
|
2017-03-31 20:03:52 +02:00
|
|
|
|
char *p = get_user_id_native (ctrl, keyid);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
log_info(_("key %s: \"%s\" revocation"
|
|
|
|
|
" certificate added\n"), keystr(keyid),p);
|
|
|
|
|
xfree(p);
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* 2nd: merge in any direct key (0x1F) sigs */
|
|
|
|
|
for(node=keyblock->next; node; node=node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID )
|
|
|
|
|
break;
|
|
|
|
|
else if (node->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 17:38:03 +02:00
|
|
|
|
&& IS_KEY_SIG (node->pkt->pkt.signature))
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
/* check whether we already have this */
|
|
|
|
|
found = 0;
|
|
|
|
|
for (onode=keyblock_orig->next; onode; onode=onode->next)
|
|
|
|
|
{
|
|
|
|
|
if (onode->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
break;
|
|
|
|
|
else if (onode->pkt->pkttype == PKT_SIGNATURE
|
2017-07-21 17:38:03 +02:00
|
|
|
|
&& IS_KEY_SIG (onode->pkt->pkt.signature)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
&& !cmp_signatures(onode->pkt->pkt.signature,
|
|
|
|
|
node->pkt->pkt.signature))
|
|
|
|
|
{
|
|
|
|
|
found = 1;
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!found )
|
|
|
|
|
{
|
|
|
|
|
kbnode_t n2 = clone_kbnode(node);
|
|
|
|
|
insert_kbnode( keyblock_orig, n2, 0 );
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n2->flag |= NODE_FLAG_A;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
++*n_sigs;
|
|
|
|
|
if(!opt.quiet)
|
|
|
|
|
log_info( _("key %s: direct key signature added\n"),
|
|
|
|
|
keystr(keyid));
|
|
|
|
|
}
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* 3rd: try to merge new certificates in */
|
|
|
|
|
for (onode=keyblock_orig->next; onode; onode=onode->next)
|
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
if (!(onode->flag & NODE_FLAG_A) && onode->pkt->pkttype == PKT_USER_ID)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
{
|
|
|
|
|
/* find the user id in the imported keyblock */
|
|
|
|
|
for (node=keyblock->next; node; node=node->next)
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& !cmp_user_ids( onode->pkt->pkt.user_id,
|
|
|
|
|
node->pkt->pkt.user_id ) )
|
|
|
|
|
break;
|
|
|
|
|
if (node ) /* found: merge */
|
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
rc = merge_sigs (onode, node, n_sigs);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (rc )
|
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* 4th: add new user-ids */
|
|
|
|
|
for (node=keyblock->next; node; node=node->next)
|
|
|
|
|
{
|
|
|
|
|
if (node->pkt->pkttype == PKT_USER_ID)
|
|
|
|
|
{
|
|
|
|
|
/* do we have this in the original keyblock */
|
|
|
|
|
for (onode=keyblock_orig->next; onode; onode=onode->next )
|
|
|
|
|
if (onode->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& !cmp_user_ids( onode->pkt->pkt.user_id,
|
|
|
|
|
node->pkt->pkt.user_id ) )
|
|
|
|
|
break;
|
|
|
|
|
if (!onode ) /* this is a new user id: append */
|
|
|
|
|
{
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
rc = append_new_uid (options, keyblock_orig, node,
|
|
|
|
|
curtime, origin, url, n_sigs);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (rc )
|
|
|
|
|
return rc;
|
|
|
|
|
++*n_uids;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* 5th: add new subkeys */
|
|
|
|
|
for (node=keyblock->next; node; node=node->next)
|
|
|
|
|
{
|
|
|
|
|
onode = NULL;
|
|
|
|
|
if (node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
/* do we have this in the original keyblock? */
|
|
|
|
|
for(onode=keyblock_orig->next; onode; onode=onode->next)
|
|
|
|
|
if (onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
&& !cmp_public_keys( onode->pkt->pkt.public_key,
|
|
|
|
|
node->pkt->pkt.public_key))
|
|
|
|
|
break;
|
|
|
|
|
if (!onode ) /* This is a new subkey: append. */
|
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
rc = append_key (keyblock_orig, node, n_sigs);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (rc)
|
|
|
|
|
return rc;
|
|
|
|
|
++*n_subk;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else if (node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
{
|
|
|
|
|
/* do we have this in the original keyblock? */
|
|
|
|
|
for (onode=keyblock_orig->next; onode; onode=onode->next )
|
|
|
|
|
if (onode->pkt->pkttype == PKT_SECRET_SUBKEY
|
|
|
|
|
&& !cmp_public_keys (onode->pkt->pkt.public_key,
|
|
|
|
|
node->pkt->pkt.public_key) )
|
|
|
|
|
break;
|
|
|
|
|
if (!onode ) /* This is a new subkey: append. */
|
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
rc = append_key (keyblock_orig, node, n_sigs);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (rc )
|
|
|
|
|
return rc;
|
|
|
|
|
++*n_subk;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
/* 6th: merge subkey certificates */
|
|
|
|
|
for (onode=keyblock_orig->next; onode; onode=onode->next)
|
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
if (!(onode->flag & NODE_FLAG_A)
|
2014-12-04 10:45:53 +01:00
|
|
|
|
&& (onode->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| onode->pkt->pkttype == PKT_SECRET_SUBKEY))
|
|
|
|
|
{
|
|
|
|
|
/* find the subkey in the imported keyblock */
|
|
|
|
|
for(node=keyblock->next; node; node=node->next)
|
|
|
|
|
{
|
|
|
|
|
if ((node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY)
|
|
|
|
|
&& !cmp_public_keys( onode->pkt->pkt.public_key,
|
|
|
|
|
node->pkt->pkt.public_key ) )
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (node) /* Found: merge. */
|
|
|
|
|
{
|
2016-07-06 10:35:36 +02:00
|
|
|
|
rc = merge_keysigs( onode, node, n_sigs);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (rc )
|
|
|
|
|
return rc;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-07-06 10:35:36 +02:00
|
|
|
|
/* Helper function for merge_blocks.
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
*
|
|
|
|
|
* Append the new userid starting with NODE and all signatures to
|
|
|
|
|
* KEYBLOCK. ORIGIN and URL conveys the usual key origin info. The
|
|
|
|
|
* integer at N_SIGS is updated with the number of new signatures.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
*/
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
static gpg_error_t
|
|
|
|
|
append_new_uid (unsigned int options,
|
|
|
|
|
kbnode_t keyblock, kbnode_t node, u32 curtime,
|
|
|
|
|
int origin, const char *url, int *n_sigs)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
gpg_error_t err;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t n;
|
|
|
|
|
kbnode_t n_where = NULL;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
log_assert (node->pkt->pkttype == PKT_USER_ID);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
/* Find the right position for the new user id and its signatures. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
for (n = keyblock; n; n_where = n, n = n->next)
|
|
|
|
|
{
|
|
|
|
|
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| n->pkt->pkttype == PKT_SECRET_SUBKEY )
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!n)
|
|
|
|
|
n_where = NULL;
|
|
|
|
|
|
|
|
|
|
/* and append/insert */
|
|
|
|
|
while (node)
|
|
|
|
|
{
|
|
|
|
|
/* we add a clone to the original keyblock, because this
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
* one is released first. */
|
2014-12-04 10:45:53 +01:00
|
|
|
|
n = clone_kbnode(node);
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
if (n->pkt->pkttype == PKT_USER_ID
|
|
|
|
|
&& !(options & IMPORT_RESTORE) )
|
|
|
|
|
{
|
|
|
|
|
err = insert_key_origin_uid (n->pkt->pkt.user_id,
|
|
|
|
|
curtime, origin, url);
|
|
|
|
|
if (err)
|
2021-05-20 10:13:51 +02:00
|
|
|
|
{
|
|
|
|
|
release_kbnode (n);
|
|
|
|
|
return err;
|
|
|
|
|
}
|
gpg: Store key origin for new userids during import merge.
* g10/import.c (apply_meta_data): Rename to ...
(insert_key_origin): this. Factor code out to ...
(insert_key_origin_pk, insert_key_origin_uid): new funcs.
(import_one): Move insert_key_origin behind clean_key.
(merge_blocks): Add args options, origin, and url.
(append_uid): Rename to ...
(append_new_uid): this. Add args options, curtime, origin, and url.
Call insert_key_origin_uid for new UIDs.
--
This is a straightforward change to handle new user ids.
How to test:
With an empty keyring run
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@gnupg.org
and then append a new keyid using
gpg --with-key-origin --locate-key \
--auto-key-locate clear,nodefault,wkd wk@g10code.com
Works with my current key 80615870F5BAD690333686D0F2AD85AC1E42B367.
Signed-off-by: Werner Koch <wk@gnupg.org>
2017-07-25 10:19:12 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (n_where)
|
|
|
|
|
{
|
|
|
|
|
insert_kbnode( n_where, n, 0 );
|
|
|
|
|
n_where = n;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
else
|
|
|
|
|
add_kbnode( keyblock, n );
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_FLAG_A;
|
|
|
|
|
node->flag |= NODE_FLAG_A;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (n->pkt->pkttype == PKT_SIGNATURE )
|
|
|
|
|
++*n_sigs;
|
|
|
|
|
|
|
|
|
|
node = node->next;
|
|
|
|
|
if (node && node->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2016-07-06 10:35:36 +02:00
|
|
|
|
/* Helper function for merge_blocks
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Merge the sigs from SRC onto DST. SRC and DST are both a PKT_USER_ID.
|
|
|
|
|
* (how should we handle comment packets here?)
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2016-07-06 10:35:36 +02:00
|
|
|
|
merge_sigs (kbnode_t dst, kbnode_t src, int *n_sigs)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t n, n2;
|
|
|
|
|
int found = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (dst->pkt->pkttype == PKT_USER_ID);
|
|
|
|
|
log_assert (src->pkt->pkttype == PKT_USER_ID);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
for (n=src->next; n && n->pkt->pkttype != PKT_USER_ID; n = n->next)
|
|
|
|
|
{
|
|
|
|
|
if (n->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
|
continue;
|
2017-07-21 17:38:03 +02:00
|
|
|
|
if (IS_SUBKEY_SIG (n->pkt->pkt.signature)
|
|
|
|
|
|| IS_SUBKEY_REV (n->pkt->pkt.signature) )
|
2014-12-04 10:45:53 +01:00
|
|
|
|
continue; /* skip signatures which are only valid on subkeys */
|
|
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
|
for (n2=dst->next; n2 && n2->pkt->pkttype != PKT_USER_ID; n2 = n2->next)
|
|
|
|
|
if (!cmp_signatures(n->pkt->pkt.signature,n2->pkt->pkt.signature))
|
|
|
|
|
{
|
|
|
|
|
found++;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (!found )
|
|
|
|
|
{
|
|
|
|
|
/* This signature is new or newer, append N to DST.
|
|
|
|
|
* We add a clone to the original keyblock, because this
|
|
|
|
|
* one is released first */
|
|
|
|
|
n2 = clone_kbnode(n);
|
|
|
|
|
insert_kbnode( dst, n2, PKT_SIGNATURE );
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n2->flag |= NODE_FLAG_A;
|
|
|
|
|
n->flag |= NODE_FLAG_A;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
++*n_sigs;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
2016-07-06 10:35:36 +02:00
|
|
|
|
/* Helper function for merge_blocks
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Merge the sigs from SRC onto DST. SRC and DST are both a PKT_xxx_SUBKEY.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2016-07-06 10:35:36 +02:00
|
|
|
|
merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t n, n2;
|
|
|
|
|
int found = 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (dst->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| dst->pkt->pkttype == PKT_SECRET_SUBKEY);
|
2003-06-05 09:14:21 +02:00
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
for (n=src->next; n ; n = n->next)
|
|
|
|
|
{
|
|
|
|
|
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| n->pkt->pkttype == PKT_PUBLIC_KEY )
|
|
|
|
|
break;
|
|
|
|
|
if (n->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
found = 0;
|
|
|
|
|
for (n2=dst->next; n2; n2 = n2->next)
|
|
|
|
|
{
|
|
|
|
|
if (n2->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| n2->pkt->pkttype == PKT_PUBLIC_KEY )
|
|
|
|
|
break;
|
|
|
|
|
if (n2->pkt->pkttype == PKT_SIGNATURE
|
|
|
|
|
&& (n->pkt->pkt.signature->keyid[0]
|
|
|
|
|
== n2->pkt->pkt.signature->keyid[0])
|
|
|
|
|
&& (n->pkt->pkt.signature->keyid[1]
|
|
|
|
|
== n2->pkt->pkt.signature->keyid[1])
|
|
|
|
|
&& (n->pkt->pkt.signature->timestamp
|
|
|
|
|
<= n2->pkt->pkt.signature->timestamp)
|
|
|
|
|
&& (n->pkt->pkt.signature->sig_class
|
|
|
|
|
== n2->pkt->pkt.signature->sig_class))
|
|
|
|
|
{
|
|
|
|
|
found++;
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (!found )
|
|
|
|
|
{
|
|
|
|
|
/* This signature is new or newer, append N to DST.
|
|
|
|
|
* We add a clone to the original keyblock, because this
|
|
|
|
|
* one is released first */
|
|
|
|
|
n2 = clone_kbnode(n);
|
|
|
|
|
insert_kbnode( dst, n2, PKT_SIGNATURE );
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n2->flag |= NODE_FLAG_A;
|
|
|
|
|
n->flag |= NODE_FLAG_A;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
++*n_sigs;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2010-09-06 21:57:42 +02:00
|
|
|
|
|
2016-07-06 10:35:36 +02:00
|
|
|
|
/* Helper function for merge_blocks.
|
2010-09-06 21:57:42 +02:00
|
|
|
|
* Append the subkey starting with NODE and all signatures to KEYBLOCK.
|
2003-06-05 09:14:21 +02:00
|
|
|
|
* Mark all new and copied packets by setting flag bit 0.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
2016-07-06 10:35:36 +02:00
|
|
|
|
append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs)
|
2003-06-05 09:14:21 +02:00
|
|
|
|
{
|
2014-12-04 10:45:53 +01:00
|
|
|
|
kbnode_t n;
|
|
|
|
|
|
2016-04-29 11:05:24 +02:00
|
|
|
|
log_assert (node->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
|
|
|
|
|| node->pkt->pkttype == PKT_SECRET_SUBKEY);
|
2014-12-04 10:45:53 +01:00
|
|
|
|
|
|
|
|
|
while (node)
|
|
|
|
|
{
|
|
|
|
|
/* we add a clone to the original keyblock, because this
|
|
|
|
|
* one is released first */
|
|
|
|
|
n = clone_kbnode(node);
|
|
|
|
|
add_kbnode( keyblock, n );
|
2016-07-06 10:35:36 +02:00
|
|
|
|
n->flag |= NODE_FLAG_A;
|
|
|
|
|
node->flag |= NODE_FLAG_A;
|
2014-12-04 10:45:53 +01:00
|
|
|
|
if (n->pkt->pkttype == PKT_SIGNATURE )
|
|
|
|
|
++*n_sigs;
|
|
|
|
|
|
|
|
|
|
node = node->next;
|
|
|
|
|
if (node && node->pkt->pkttype != PKT_SIGNATURE )
|
|
|
|
|
break;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|
|
|
|
|
|
2014-12-04 10:45:53 +01:00
|
|
|
|
return 0;
|
2003-06-05 09:14:21 +02:00
|
|
|
|
}
|