From 0d2a5aeeb4120999afc79d06619d90e26e2fec5c Mon Sep 17 00:00:00 2001
From: Jonathan McDowell <noodles@earth.li>
Date: Sun, 4 Mar 2007 15:37:43 +0000
Subject: [PATCH 1/1] Fix assumption that a signature on a public key is a
 revocation We've been assuming that a signature directly on a public key
 means the key is revoked. This isn't the case; it's used for key preferences
 for example. Change the structure element names to reflect this
 (revocations->sigs) and check for revoked status by looking for a signature
 type of 0x20.

---
 keydb.c         |  4 ++--
 keydb_dynamic.c |  4 ++--
 keyindex.c      |  8 +++-----
 keystructs.h    |  8 +++++---
 mem.c           |  6 +++---
 merge.c         | 30 +++++++++++++++++++-----------
 parsekey.c      | 26 +++++++++++++++++++++-----
 7 files changed, 55 insertions(+), 31 deletions(-)

diff --git a/keydb.c b/keydb.c
index 300e9b9..7d33108 100644
--- a/keydb.c
+++ b/keydb.c
@@ -82,7 +82,7 @@ struct ll *getkeysigs(uint64_t keyid, bool *revoked)
 			sigs = keysigs(sigs, uids->sigs);
 		}
 		if (revoked != NULL) {
-			*revoked = (publickey->revocations != NULL);
+			*revoked = publickey->revoked;
 		}
 		free_publickey(publickey);
 	}
@@ -188,7 +188,7 @@ int update_keys(struct openpgp_publickey **keys, bool sendsync)
 		 */
 		if (oldkey != NULL) {
 			merge_keys(oldkey, curkey);
-			if (curkey->revocations == NULL &&
+			if (curkey->sigs == NULL &&
 					curkey->uids == NULL &&
 					curkey->subkeys == NULL) {
 				if (prev == NULL) {
diff --git a/keydb_dynamic.c b/keydb_dynamic.c
index 6907144..49d77b8 100644
--- a/keydb_dynamic.c
+++ b/keydb_dynamic.c
@@ -203,7 +203,7 @@ struct ll *getkeysigs(uint64_t keyid, bool *revoked)
 			sigs = keysigs(sigs, uids->sigs);
 		}
 		if (revoked != NULL) {
-			*revoked = (publickey->revocations != NULL);
+			*revoked = publickey->revoked;
 		}
 		free_publickey(publickey);
 	}
@@ -342,7 +342,7 @@ int update_keys(struct openpgp_publickey **keys, bool sendsync)
 		 */
 		if (oldkey != NULL) {
 			merge_keys(oldkey, curkey);
-			if (curkey->revocations == NULL &&
+			if (curkey->sigs == NULL &&
 					curkey->uids == NULL &&
 					curkey->subkeys == NULL) {
 				if (prev == NULL) {
diff --git a/keyindex.c b/keyindex.c
index 0732a11..64c99a3 100644
--- a/keyindex.c
+++ b/keyindex.c
@@ -268,8 +268,7 @@ int key_index(struct openpgp_publickey *keys, bool verbose, bool fingerprint,
 			printf("%s%s%s\n", 
 				(html) ? txt2html(buf) : buf,
 				(html) ? "</a>" : "",
-				(keys->revocations == NULL) ? "" :
-					" *** REVOKED ***");
+				(keys->revoked) ? " *** REVOKED ***" : "");
 			if (fingerprint) {
 				display_fingerprint(keys);
 			}
@@ -279,8 +278,7 @@ int key_index(struct openpgp_publickey *keys, bool verbose, bool fingerprint,
 			curuid = curuid->next;
 		} else {
 			printf("%s\n", 
-				(keys->revocations == NULL) ? "" :
-					"*** REVOKED ***");
+				(keys->revoked) ? "*** REVOKED ***": "");
 			if (fingerprint) {
 				display_fingerprint(keys);
 			}
@@ -354,7 +352,7 @@ int mrkey_index(struct openpgp_publickey *keys)
 			type,
 			length,
 			created_time,
-			(keys->revocations == NULL) ? "" : "r");
+			(keys->revoked) ? "r" : "");
 	
 		for (curuid = keys->uids; curuid != NULL;
 			 curuid = curuid->next) {
diff --git a/keystructs.h b/keystructs.h
index 6c36bbe..33c6226 100644
--- a/keystructs.h
+++ b/keystructs.h
@@ -65,15 +65,17 @@ struct openpgp_signedpacket_list {
 /**
  *	struct openpgp_publickey - An OpenPGP public key complete with sigs.
  *	@publickey: The OpenPGP packet for the public key.
- *	@revocation: The OpenPGP packet for the revocation [optional]
+ *	@revoked: True if the key is revoked.
+ *	@sigs: Any signatures directly on the publickey packet.
  *	@uids: The list of UIDs with signatures for this key.
  *	@subkeys: The list of subkeys with signatures for this key.
  *	@next: The next public key.
  */
 struct openpgp_publickey {
 	struct openpgp_packet			*publickey;
-	struct openpgp_packet_list		*revocations;
-	struct openpgp_packet_list		*last_revocation;
+	bool					 revoked;
+	struct openpgp_packet_list		*sigs;
+	struct openpgp_packet_list		*last_sig;
 	struct openpgp_signedpacket_list	*uids;
 	struct openpgp_signedpacket_list	*last_uid;
 	struct openpgp_signedpacket_list	*subkeys;
diff --git a/mem.c b/mem.c
index 00507ab..47f2967 100644
--- a/mem.c
+++ b/mem.c
@@ -150,9 +150,9 @@ void free_publickey(struct openpgp_publickey *key) {
 			free_packet(key->publickey);
 			key->publickey = NULL;
 		}
-		if (key->revocations != NULL) {
-			free_packet_list(key->revocations);
-			key->revocations = NULL;
+		if (key->sigs != NULL) {
+			free_packet_list(key->sigs);
+			key->sigs = NULL;
 		}
 		if (key->uids != NULL) {
 			free_signedpacket_list(key->uids);
diff --git a/merge.c b/merge.c
index 4379596..87f45fc 100644
--- a/merge.c
+++ b/merge.c
@@ -314,12 +314,12 @@ int merge_keys(struct openpgp_publickey *a, struct openpgp_publickey *b)
 		/*
 		 * Key IDs are the same, so I guess we have to merge them.
 		 */
-		curpacket = b->revocations;
+		curpacket = b->sigs;
 		while (curpacket != NULL) {
 			nextpacket = curpacket->next;
-			if (find_packet(a->revocations, curpacket->packet)) {
+			if (find_packet(a->sigs, curpacket->packet)) {
 				/*
-				 * We already have this revocation, remove it
+				 * We already have this signature, remove it
 				 * from the difference list and free the memory
 				 * allocated for it.
 				 */
@@ -327,8 +327,8 @@ int merge_keys(struct openpgp_publickey *a, struct openpgp_publickey *b)
 				if (lastpacket != NULL) {
 					lastpacket->next = curpacket->next;
 				} else {
-					log_assert(curpacket == b->revocations);
-					b->revocations = curpacket->next;
+					log_assert(curpacket == b->sigs);
+					b->sigs = curpacket->next;
 				}
 				curpacket->next = NULL;
 				free_packet_list(curpacket);
@@ -338,15 +338,15 @@ int merge_keys(struct openpgp_publickey *a, struct openpgp_publickey *b)
 			}
 			curpacket = nextpacket;
 		}
-		b->last_revocation = lastpacket;
+		b->last_sig = lastpacket;
 
 		/*
-		 * Anything left on b->revocations doesn't exist on
-		 * a->revocations, so add them to the list.
+		 * Anything left on b->sigs doesn't exist on
+		 * a->sigs, so add them to the list.
 		 */
-		packet_list_add(&a->revocations,
-				&a->last_revocation,
-				b->revocations);
+		packet_list_add(&a->sigs,
+				&a->last_sig,
+				b->sigs);
 
 		/*
 		 * Merge uids (signed list).
@@ -359,5 +359,13 @@ int merge_keys(struct openpgp_publickey *a, struct openpgp_publickey *b)
 
 	}
 
+	/*
+	 * If either key was revoked, make sure both the new ones are marked as
+	 * being so.
+	 */
+	if (a->revoked || b->revoked) {
+		a->revoked = b->revoked = true;
+	}
+
 	return rc;
 }
diff --git a/parsekey.c b/parsekey.c
index 687fd9b..6e080af 100644
--- a/parsekey.c
+++ b/parsekey.c
@@ -48,8 +48,7 @@ int parse_keys(struct openpgp_packet_list *packets,
 		case 2:
 			/*
 			 * It's a signature packet. Add it to either the public
-			 * key (it should be a revocation), to the current UID
-			 * or the current subkey.
+			 * key, to the current UID or the current subkey.
 			 */
 			log_assert(curkey != NULL);
 			if (curkey->subkeys != NULL) {
@@ -62,8 +61,25 @@ int parse_keys(struct openpgp_packet_list *packets,
 					packet_dup(packets->packet));
 			} else {
 				ADD_PACKET_TO_LIST_END(curkey,
-					revocation,
+					sig,
 					packet_dup(packets->packet));
+				/*
+				 * This is a signature on the public key; check
+				 * if it's a revocation.
+				 */
+				if (packets->packet->data[0] == 3 &&
+					packets->packet->data[2] == 0x20) {
+					/*
+					 * Type 3 key, 0x20 == revocation
+					 */
+					curkey->revoked = true;
+				} else if (packets->packet->data[0] == 4 &&
+					packets->packet->data[1] == 0x20) {
+					/*
+					 * Type 4 key, 0x20 == revocation
+					 */
+					curkey->revoked = true;
+				}
 			}
 			break;
 		case 6:
@@ -416,9 +432,9 @@ int flatten_publickey(struct openpgp_publickey *key,
 		}
 
 		/*
-		 * Now do any revocation signatures on the main key.
+		 * Now do any signatures on the main key.
 		 */
-		for (tmplist = key->revocations; tmplist != NULL;
+		for (tmplist = key->sigs; tmplist != NULL;
 				tmplist = tmplist->next) {
 			ADD_PACKET_TO_LIST((*list_end),
 					packet_dup(tmplist->packet));
-- 
2.39.5