From 598a771d8b4f4f480d4990ccf59b978d537201dd Mon Sep 17 00:00:00 2001
From: Demi Marie Obenour <demi@invisiblethingslab.com>
Date: Sun, 27 Mar 2022 12:07:34 -0400
Subject: [PATCH] Parse key usage flags

RPM needs to know if a subkey can be used for signing.  Signatures made
by a subkey that cannot be used for signing are invalid.  Add a
key_flags member to pgpDigParams_s to store this information, and a
PGPDIG_SIG_HAS_KEY_FLAGS flag to indicate that it is valid.  The key
usage flags are reset for every signature.  Key usage flags in the
unhashed section are ignored.  If there is more than one key usage flags
subpacket in the hashed section, the signature is rejected.
---
 rpmio/digest.h |  2 ++
 rpmio/rpmpgp.c | 13 ++++++++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/rpmio/digest.h b/rpmio/digest.h
index ec7f339..6a326d2 100644
--- a/rpmio/digest.h
+++ b/rpmio/digest.h
@@ -28,6 +28,7 @@ struct pgpDigParams_s {
     const uint8_t * data;
     uint8_t tag;
 
+    uint8_t key_flags;		/*!< key usage flags */
     uint8_t version;		/*!< version number. */
     uint32_t time;		/*!< key/signature creation time. */
     uint8_t pubkey_algo;		/*!< public key algorithm. */
@@ -41,6 +42,7 @@ struct pgpDigParams_s {
 #define	PGPDIG_SAVED_TIME	(1 << 0)
 #define	PGPDIG_SAVED_ID		(1 << 1)
 #define	PGPDIG_SIG_HAS_CREATION_TIME	(1 << 2)
+#define	PGPDIG_SIG_HAS_KEY_FLAGS	(1 << 3)
 
     pgpDigAlg alg;
 };
diff --git a/rpmio/rpmpgp.c b/rpmio/rpmpgp.c
index 9b8503e..66837b1 100644
--- a/rpmio/rpmpgp.c
+++ b/rpmio/rpmpgp.c
@@ -500,6 +500,17 @@ static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype,
 		_digp->saved |= PGPDIG_SAVED_ID;
 		memcpy(_digp->signid, p+1, sizeof(_digp->signid));
 	    }
+	case PGPSUBTYPE_KEY_FLAGS: /* Key usage flags */
+	    /* Subpackets in the unhashed section cannot be trusted */
+	    if (!hashed)
+		break;
+	    /* Reject duplicate key usage flags */
+	    if (_digp->saved & PGPDIG_SIG_HAS_KEY_FLAGS)
+		return 1;
+	    impl = *p;
+	    _digp->saved |= PGPDIG_SIG_HAS_KEY_FLAGS;
+	    _digp->key_flags = plen >= 2 ? p[1] : 0;
+	    break;
 	case PGPSUBTYPE_EXPORTABLE_CERT:
 	case PGPSUBTYPE_TRUST_SIG:
 	case PGPSUBTYPE_REGEX:
@@ -510,7 +521,6 @@ static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype,
 	case PGPSUBTYPE_PREFER_KEYSERVER:
 	case PGPSUBTYPE_PRIMARY_USERID:
 	case PGPSUBTYPE_POLICY_URL:
-	case PGPSUBTYPE_KEY_FLAGS:
 	case PGPSUBTYPE_SIGNER_USERID:
 	case PGPSUBTYPE_REVOKE_REASON:
 	case PGPSUBTYPE_FEATURES:
@@ -602,6 +612,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
 
     /* Reset the saved flags */
     _digp->saved &= PGPDIG_SAVED_TIME | PGPDIG_SAVED_ID;
+    _digp->key_flags = 0;
 
     if (pgpVersion(h, hlen, &version))
 	return rc;
-- 
1.8.3.1

