diff --git a/g10/import.c b/g10/import.c index b2d5c1d27..cd3363fc7 100644 --- a/g10/import.c +++ b/g10/import.c @@ -126,7 +126,8 @@ static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, 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, - u32 *keyid, unsigned int options); + u32 *keyid, unsigned int options, + kbnode_t *r_otherrevsigs); static int any_uid_left (kbnode_t keyblock); static void remove_all_non_self_sigs (kbnode_t *keyblock, u32 *keyid); static int merge_blocks (ctrl_t ctrl, unsigned int options, @@ -420,7 +421,7 @@ read_key_from_file_or_buffer (ctrl_t ctrl, const char *fname, goto leave; } - if (!delete_inv_parts (ctrl, keyblock, keyid, 0) ) + if (!delete_inv_parts (ctrl, keyblock, keyid, 0, NULL) ) { err = gpg_error (GPG_ERR_NO_USER_ID); goto leave; @@ -1830,8 +1831,9 @@ update_key_origin (kbnode_t keyblock, u32 curtime, int origin, const char *url) * even most error messages are suppressed. ORIGIN is the origin of * the key (0 for unknown) and URL the corresponding URL. FROM_SK * indicates that the key has been made from a secret key. If R_SAVED - * is not NULL a boolean will be stored indicating whether the keyblock - * has valid parts. + * 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. */ static gpg_error_t import_one_real (ctrl_t ctrl, @@ -1839,7 +1841,8 @@ import_one_real (ctrl_t ctrl, 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) + int origin, const char *url, int *r_valid, + kbnode_t *otherrevsigs) { gpg_error_t err = 0; PKT_public_key *pk; @@ -1974,7 +1977,8 @@ import_one_real (ctrl_t ctrl, } } - if (!delete_inv_parts (ctrl, keyblock, keyid, options ) ) + /* Delete invalid parts and bail out if there are no user ids left. */ + if (!delete_inv_parts (ctrl, keyblock, keyid, options, otherrevsigs)) { if (!silent) { @@ -2366,10 +2370,12 @@ import_one (ctrl_t ctrl, int origin, const char *url, int *r_valid) { gpg_error_t err; + kbnode_t otherrevsigs = NULL; + kbnode_t node; err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options, from_sk, silent, screener, screener_arg, - origin, url, r_valid); + origin, url, r_valid, &otherrevsigs); if (gpg_err_code (err) == GPG_ERR_TOO_LARGE && gpg_err_source (err) == GPG_ERR_SOURCE_KEYBOX && ((options & (IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN)) @@ -2385,8 +2391,17 @@ import_one (ctrl_t ctrl, options |= IMPORT_SELF_SIGS_ONLY | IMPORT_CLEAN; err = import_one_real (ctrl, keyblock, stats, fpr, fpr_len, options, from_sk, silent, screener, screener_arg, - origin, url, r_valid); + origin, url, r_valid, &otherrevsigs); } + + /* 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); return err; } @@ -3358,9 +3373,8 @@ list_standalone_revocation (ctrl_t ctrl, PKT_signature *sig, int sigrc) } -/**************** - * Import a revocation certificate; this is a single signature packet. - */ +/* Import a revocation certificate; only the first packet in the + * NODE-list is considered. */ static int import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, struct import_stats_s *stats) @@ -3377,10 +3391,12 @@ import_revoke_cert (ctrl_t ctrl, kbnode_t node, unsigned int options, /* No error output for --show-keys. */ silent = (options & (IMPORT_SHOW | IMPORT_DRY_RUN)); - log_assert (!node->next ); log_assert (node->pkt->pkttype == PKT_SIGNATURE ); log_assert (IS_KEY_REV (node->pkt->pkt.signature)); + /* FIXME: We can do better here by using the issuer fingerprint if + * available. We should also make use of get_keyblock_byfprint_fast. */ + keyid[0] = node->pkt->pkt.signature->keyid[0]; keyid[1] = node->pkt->pkt.signature->keyid[1]; @@ -3726,12 +3742,15 @@ chk_self_sigs (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, int *non_self) /* Delete all parts which are invalid and those signatures whose * public key algorithm is not available in this implementation; but * consider RSA as valid, because parse/build_packets knows about it. + * 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. * * Returns: True if at least one valid user-id is left over. */ static int delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, - unsigned int options) + unsigned int options, kbnode_t *r_otherrevsigs) { kbnode_t node; int nvalid=0, uid_seen=0, subkey_seen=0; @@ -3820,6 +3839,16 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, if(opt.verbose) log_info( _("key %s: revocation certificate" " at wrong place - skipped\n"),keystr(keyid)); + 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); + } delete_kbnode( node ); } else @@ -3842,6 +3871,16 @@ delete_inv_parts (ctrl_t ctrl, kbnode_t keyblock, u32 *keyid, delete_kbnode( node ); } } + 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); + } } } else if (node->pkt->pkttype == PKT_SIGNATURE diff --git a/g10/kbnode.c b/g10/kbnode.c index 9ed6cafbf..aa1e17c94 100644 --- a/g10/kbnode.c +++ b/g10/kbnode.c @@ -98,6 +98,19 @@ new_kbnode( PACKET *pkt ) } +/* Same as new_kbnode but insert the new node in front of LIST. Returns + * the new list. */ +kbnode_t +new_kbnode2 (kbnode_t list, PACKET *pkt) +{ + kbnode_t n; + + n = new_kbnode (pkt); + n->next = list; + return n; +} + + KBNODE clone_kbnode( KBNODE node ) { diff --git a/g10/keydb.h b/g10/keydb.h index 0f8d711a9..63a9f1087 100644 --- a/g10/keydb.h +++ b/g10/keydb.h @@ -552,6 +552,7 @@ gpg_error_t hexkeygrip_from_pk (PKT_public_key *pk, char **r_grip); /*-- kbnode.c --*/ KBNODE new_kbnode( PACKET *pkt ); +kbnode_t new_kbnode2 (kbnode_t list, PACKET *pkt); KBNODE clone_kbnode( KBNODE node ); void release_kbnode( KBNODE n ); void delete_kbnode( KBNODE node );