mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01: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>
This commit is contained in:
parent
d40b4a41a8
commit
84c993d932
262
g10/import.c
262
g10/import.c
@ -1,6 +1,6 @@
|
|||||||
/* import.c - import a key into our key storage.
|
/* import.c - import a key into our key storage.
|
||||||
* Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc.
|
* Copyright (C) 1998-2007, 2010-2011 Free Software Foundation, Inc.
|
||||||
* Copyright (C) 2014, 2016 Werner Koch
|
* Copyright (C) 2014, 2016, 2017 Werner Koch
|
||||||
*
|
*
|
||||||
* This file is part of GnuPG.
|
* This file is part of GnuPG.
|
||||||
*
|
*
|
||||||
@ -120,10 +120,15 @@ static int chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid,
|
|||||||
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
|
static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock,
|
||||||
u32 *keyid, unsigned int options);
|
u32 *keyid, unsigned int options);
|
||||||
static int any_uid_left (kbnode_t keyblock);
|
static int any_uid_left (kbnode_t keyblock);
|
||||||
static int merge_blocks (ctrl_t ctrl, kbnode_t keyblock_orig,
|
static int merge_blocks (ctrl_t ctrl, unsigned int options,
|
||||||
|
kbnode_t keyblock_orig,
|
||||||
kbnode_t keyblock, u32 *keyid,
|
kbnode_t keyblock, u32 *keyid,
|
||||||
|
int origin, const char *url,
|
||||||
int *n_uids, int *n_sigs, int *n_subk );
|
int *n_uids, int *n_sigs, int *n_subk );
|
||||||
static int append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs);
|
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);
|
||||||
static int append_key (kbnode_t keyblock, kbnode_t node, int *n_sigs);
|
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_sigs (kbnode_t dst, kbnode_t src, int *n_sigs);
|
||||||
static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs);
|
static int merge_keysigs (kbnode_t dst, kbnode_t src, int *n_sigs);
|
||||||
@ -1381,12 +1386,114 @@ apply_drop_sig_filter (ctrl_t ctrl, kbnode_t keyblock, recsel_expr_t selector)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Apply meta data to KEYBLOCK. This sets the origin of the key to
|
/* Apply meta data to KEYBLOCK. This sets the origin of the key to
|
||||||
* ORIGIN and the updateurl to URL. Note that this function is only
|
* 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. */
|
* used for a new key, that is not when we are merging keys. */
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
apply_meta_data (kbnode_t keyblock, int origin, const char *url)
|
insert_key_origin (kbnode_t keyblock, int origin, const char *url)
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
kbnode_t node;
|
kbnode_t node;
|
||||||
u32 curtime = make_timestamp ();
|
u32 curtime = make_timestamp ();
|
||||||
|
|
||||||
@ -1396,94 +1503,17 @@ apply_meta_data (kbnode_t keyblock, int origin, const char *url)
|
|||||||
;
|
;
|
||||||
else if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
else if (node->pkt->pkttype == PKT_PUBLIC_KEY)
|
||||||
{
|
{
|
||||||
PKT_public_key *pk = node->pkt->pkt.public_key;
|
err = insert_key_origin_pk (node->pkt->pkt.public_key, curtime,
|
||||||
|
origin, url);
|
||||||
if (origin == KEYORG_WKD || origin == KEYORG_DANE)
|
if (err)
|
||||||
{
|
return err;
|
||||||
/* 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;
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
pk->updateurl = xtrystrdup (url);
|
|
||||||
if (!pk->updateurl)
|
|
||||||
return gpg_error_from_syserror ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if (node->pkt->pkttype == PKT_USER_ID)
|
else if (node->pkt->pkttype == PKT_USER_ID)
|
||||||
{
|
{
|
||||||
PKT_user_id *uid = node->pkt->pkt.user_id;
|
err = insert_key_origin_uid (node->pkt->pkt.user_id, curtime,
|
||||||
|
origin, url);
|
||||||
if (origin == KEYORG_WKD || origin == KEYORG_DANE)
|
if (err)
|
||||||
{
|
return err;
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1724,24 +1754,24 @@ import_one (ctrl_t ctrl,
|
|||||||
if (opt.verbose > 1 )
|
if (opt.verbose > 1 )
|
||||||
log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) );
|
log_info (_("writing to '%s'\n"), keydb_get_resource_name (hd) );
|
||||||
|
|
||||||
|
if ((options & IMPORT_CLEAN))
|
||||||
|
clean_key (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL),
|
||||||
|
&n_uids_cleaned,&n_sigs_cleaned);
|
||||||
|
|
||||||
/* Unless we are in restore mode apply meta data to the
|
/* Unless we are in restore mode apply meta data to the
|
||||||
* keyblock. Note that this will never change the first packet
|
* keyblock. Note that this will never change the first packet
|
||||||
* and thus the address of KEYBLOCK won't change. */
|
* and thus the address of KEYBLOCK won't change. */
|
||||||
if ( !(options & IMPORT_RESTORE) )
|
if ( !(options & IMPORT_RESTORE) )
|
||||||
{
|
{
|
||||||
rc = apply_meta_data (keyblock, origin, url);
|
rc = insert_key_origin (keyblock, origin, url);
|
||||||
if (rc)
|
if (rc)
|
||||||
{
|
{
|
||||||
log_error ("apply_meta_data failed: %s\n", gpg_strerror (rc));
|
log_error ("insert_key_origin failed: %s\n", gpg_strerror (rc));
|
||||||
keydb_release (hd);
|
keydb_release (hd);
|
||||||
return GPG_ERR_GENERAL;
|
return GPG_ERR_GENERAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((options & IMPORT_CLEAN))
|
|
||||||
clean_key (ctrl, keyblock, opt.verbose, (options&IMPORT_MINIMAL),
|
|
||||||
&n_uids_cleaned,&n_sigs_cleaned);
|
|
||||||
|
|
||||||
rc = keydb_insert_keyblock (hd, keyblock );
|
rc = keydb_insert_keyblock (hd, keyblock );
|
||||||
if (rc)
|
if (rc)
|
||||||
log_error (_("error writing keyring '%s': %s\n"),
|
log_error (_("error writing keyring '%s': %s\n"),
|
||||||
@ -1778,7 +1808,7 @@ import_one (ctrl_t ctrl,
|
|||||||
stats->imported++;
|
stats->imported++;
|
||||||
new_key = 1;
|
new_key = 1;
|
||||||
}
|
}
|
||||||
else /* merge */
|
else /* Merge the key. */
|
||||||
{
|
{
|
||||||
KEYDB_HANDLE hd;
|
KEYDB_HANDLE hd;
|
||||||
int n_uids, n_sigs, n_subk, n_sigs_cleaned, n_uids_cleaned;
|
int n_uids, n_sigs, n_subk, n_sigs_cleaned, n_uids_cleaned;
|
||||||
@ -1827,8 +1857,9 @@ import_one (ctrl_t ctrl,
|
|||||||
clear_kbnode_flags( keyblock_orig );
|
clear_kbnode_flags( keyblock_orig );
|
||||||
clear_kbnode_flags( keyblock );
|
clear_kbnode_flags( keyblock );
|
||||||
n_uids = n_sigs = n_subk = n_uids_cleaned = 0;
|
n_uids = n_sigs = n_subk = n_uids_cleaned = 0;
|
||||||
rc = merge_blocks (ctrl, keyblock_orig, keyblock,
|
rc = merge_blocks (ctrl, options, keyblock_orig, keyblock, keyid,
|
||||||
keyid, &n_uids, &n_sigs, &n_subk );
|
origin, url,
|
||||||
|
&n_uids, &n_sigs, &n_subk );
|
||||||
if (rc )
|
if (rc )
|
||||||
{
|
{
|
||||||
keydb_release (hd);
|
keydb_release (hd);
|
||||||
@ -3193,11 +3224,14 @@ revocation_present (ctrl_t ctrl, kbnode_t keyblock)
|
|||||||
* Note: We indicate newly inserted packets with NODE_FLAG_A.
|
* Note: We indicate newly inserted packets with NODE_FLAG_A.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
merge_blocks (ctrl_t ctrl, kbnode_t keyblock_orig, kbnode_t keyblock,
|
merge_blocks (ctrl_t ctrl, unsigned int options,
|
||||||
u32 *keyid, int *n_uids, int *n_sigs, int *n_subk )
|
kbnode_t keyblock_orig, kbnode_t keyblock,
|
||||||
|
u32 *keyid, int origin, const char *url,
|
||||||
|
int *n_uids, int *n_sigs, int *n_subk )
|
||||||
{
|
{
|
||||||
kbnode_t onode, node;
|
kbnode_t onode, node;
|
||||||
int rc, found;
|
int rc, found;
|
||||||
|
u32 curtime = make_timestamp ();
|
||||||
|
|
||||||
/* 1st: handle revocation certificates */
|
/* 1st: handle revocation certificates */
|
||||||
for (node=keyblock->next; node; node=node->next )
|
for (node=keyblock->next; node; node=node->next )
|
||||||
@ -3308,7 +3342,8 @@ merge_blocks (ctrl_t ctrl, kbnode_t keyblock_orig, kbnode_t keyblock,
|
|||||||
break;
|
break;
|
||||||
if (!onode ) /* this is a new user id: append */
|
if (!onode ) /* this is a new user id: append */
|
||||||
{
|
{
|
||||||
rc = append_uid (keyblock_orig, node, n_sigs);
|
rc = append_new_uid (options, keyblock_orig, node,
|
||||||
|
curtime, origin, url, n_sigs);
|
||||||
if (rc )
|
if (rc )
|
||||||
return rc;
|
return rc;
|
||||||
++*n_uids;
|
++*n_uids;
|
||||||
@ -3384,17 +3419,23 @@ merge_blocks (ctrl_t ctrl, kbnode_t keyblock_orig, kbnode_t keyblock,
|
|||||||
|
|
||||||
|
|
||||||
/* Helper function for merge_blocks.
|
/* Helper function for merge_blocks.
|
||||||
* Append the userid starting with NODE and all signatures to KEYBLOCK.
|
*
|
||||||
|
* 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.
|
||||||
*/
|
*/
|
||||||
static int
|
static gpg_error_t
|
||||||
append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs)
|
append_new_uid (unsigned int options,
|
||||||
|
kbnode_t keyblock, kbnode_t node, u32 curtime,
|
||||||
|
int origin, const char *url, int *n_sigs)
|
||||||
{
|
{
|
||||||
|
gpg_error_t err;
|
||||||
kbnode_t n;
|
kbnode_t n;
|
||||||
kbnode_t n_where = NULL;
|
kbnode_t n_where = NULL;
|
||||||
|
|
||||||
log_assert (node->pkt->pkttype == PKT_USER_ID);
|
log_assert (node->pkt->pkttype == PKT_USER_ID);
|
||||||
|
|
||||||
/* find the position */
|
/* Find the right position for the new user id and its signatures. */
|
||||||
for (n = keyblock; n; n_where = n, n = n->next)
|
for (n = keyblock; n; n_where = n, n = n->next)
|
||||||
{
|
{
|
||||||
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
if (n->pkt->pkttype == PKT_PUBLIC_SUBKEY
|
||||||
@ -3408,8 +3449,17 @@ append_uid (kbnode_t keyblock, kbnode_t node, int *n_sigs)
|
|||||||
while (node)
|
while (node)
|
||||||
{
|
{
|
||||||
/* we add a clone to the original keyblock, because this
|
/* we add a clone to the original keyblock, because this
|
||||||
* one is released first */
|
* one is released first. */
|
||||||
n = clone_kbnode(node);
|
n = clone_kbnode(node);
|
||||||
|
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)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if (n_where)
|
if (n_where)
|
||||||
{
|
{
|
||||||
insert_kbnode( n_where, n, 0 );
|
insert_kbnode( n_where, n, 0 );
|
||||||
|
Loading…
x
Reference in New Issue
Block a user