diff --git a/g10/keyedit.c b/g10/keyedit.c --- a/g10/keyedit.c +++ b/g10/keyedit.c @@ -2447,6 +2447,74 @@ } +/* Helper to find the UID node for namehash. On success, returns the UID node. + Otherwise, return NULL. */ +kbnode_t +find_userid_by_namehash (kbnode_t keyblock, const char *namehash) +{ + byte hash[NAMEHASH_LEN]; + kbnode_t node = NULL; + int i; + + if (!namehash) + goto leave; + + if (strlen (namehash) != NAMEHASH_LEN * 2) + goto leave; + + for (i = 0; i < NAMEHASH_LEN; i++) + { + int b = hextobyte (&namehash[i * 2]); + if (b == -1) + goto leave; + hash[i] = b; + } + + for (node = keyblock; node; node = node->next) + { + if (node->pkt->pkttype == PKT_USER_ID) + { + namehash_from_uid (node->pkt->pkt.user_id); + if (!memcmp (node->pkt->pkt.user_id->namehash, hash, NAMEHASH_LEN)) + break; + } + } + + leave: + return node; +} + + +/* Helper to find the UID node for uid. On success, returns the UID node. + Otherwise, return NULL. */ +kbnode_t +find_userid (kbnode_t keyblock, const char *uid) +{ + kbnode_t node = NULL; + size_t uidlen; + + if (!keyblock || !uid) + goto leave; + + /* First try to find UID by namehash. */ + node = find_userid_by_namehash (keyblock, uid); + if (node) + goto leave; + + uidlen = strlen (uid); + for (node = keyblock; node; node = node->next) + { + if (node->pkt->pkttype == PKT_USER_ID + && uidlen == node->pkt->pkt.user_id->len + && !memcmp (node->pkt->pkt.user_id->name, uid, uidlen)) + break; + } + + leave: + return node; +} + + /* Unattended revocation of a keyid. USERNAME specifies the key. UIDTOREV is the user id revoke from the key. */ void @@ -2457,7 +2525,6 @@ kbnode_t keyblock = NULL; kbnode_t node; int modified = 0; - size_t revlen; size_t valid_uids; #ifdef HAVE_W32_SYSTEM @@ -2470,7 +2537,7 @@ if (err) goto leave; - /* Too make sure that we do not revoke the last valid UID, we first + /* To make sure that we do not revoke the last valid UID, we first count how many valid UIDs there are. */ valid_uids = 0; for (node = keyblock; node; node = node->next) @@ -2479,40 +2546,35 @@ && !node->pkt->pkt.user_id->flags.expired); /* Find the right UID. */ - revlen = strlen (uidtorev); - for (node = keyblock; node; node = node->next) + node = find_userid (keyblock, uidtorev); + if (node) { - if (node->pkt->pkttype == PKT_USER_ID - && revlen == node->pkt->pkt.user_id->len - && !memcmp (node->pkt->pkt.user_id->name, uidtorev, revlen)) - { - struct revocation_reason_info *reason; - - /* Make sure that we do not revoke the last valid UID. */ - if (valid_uids == 1 - && ! node->pkt->pkt.user_id->flags.revoked - && ! node->pkt->pkt.user_id->flags.expired) - { - log_error (_("cannot revoke the last valid user ID.\n")); - err = gpg_error (GPG_ERR_INV_USER_ID); - goto leave; - } + struct revocation_reason_info *reason; - reason = get_default_uid_revocation_reason (); - err = core_revuid (ctrl, keyblock, node, reason, &modified); - release_revocation_reason_info (reason); - if (err) - goto leave; - err = keydb_update_keyblock (ctrl, kdbhd, keyblock); - if (err) - { - log_error (_("update failed: %s\n"), gpg_strerror (err)); - goto leave; - } + /* Make sure that we do not revoke the last valid UID. */ + if (valid_uids == 1 + && ! node->pkt->pkt.user_id->flags.revoked + && ! node->pkt->pkt.user_id->flags.expired) + { + log_error (_("cannot revoke the last valid user ID.\n")); + err = gpg_error (GPG_ERR_INV_USER_ID); + goto leave; + } - revalidation_mark (ctrl); + reason = get_default_uid_revocation_reason (); + err = core_revuid (ctrl, keyblock, node, reason, &modified); + release_revocation_reason_info (reason); + if (err) + goto leave; + err = keydb_update_keyblock (ctrl, kdbhd, keyblock); + if (err) + { + log_error (_("update failed: %s\n"), gpg_strerror (err)); goto leave; } + + revalidation_mark (ctrl); + goto leave; } err = gpg_error (GPG_ERR_NO_USER_ID);