File verifybindingsig.diff of Package rpm-ndb

--- rpmio/digest.h.orig	2024-04-29 09:11:59.251170068 +0000
+++ rpmio/digest.h	2024-04-29 10:54:13.168416920 +0000
@@ -33,12 +33,13 @@ struct pgpDigParams_s {
 
     uint8_t hash_algo;
     uint8_t sigtype;
-    uint8_t hashlen;
+    uint32_t hashlen;
     uint8_t signhash16[2];
     pgpKeyID_t signid;
     uint8_t saved;
 #define	PGPDIG_SAVED_TIME	(1 << 0)
 #define	PGPDIG_SAVED_ID		(1 << 1)
+    uint8_t key_flags;
 
     pgpDigAlg alg;
 };
--- rpmio/rpmpgp.c.orig	2024-04-29 09:11:10.259240666 +0000
+++ rpmio/rpmpgp.c	2024-04-29 09:36:15.612510965 +0000
@@ -16,6 +16,8 @@
 
 #include "debug.h"
 
+static rpmRC pgpVerifySignatureRaw(pgpDigParams key, pgpDigParams sig, DIGEST_CTX hashctx);
+
 static int _print = 0;
 
 /** \ingroup rpmio
@@ -412,7 +414,7 @@ static int pgpVersion(const uint8_t *h,
 }
 
 static int pgpPrtSubType(const uint8_t *h, size_t hlen, pgpSigType sigtype, 
-			 pgpDigParams _digp)
+			 pgpDigParams _digp, int hashed)
 {
     const uint8_t *p = h;
     size_t plen = 0, i;
@@ -449,6 +451,8 @@ static int pgpPrtSubType(const uint8_t *
 		pgpPrtVal(" ", pgpKeyServerPrefsTbl, p[i]);
 	    break;
 	case PGPSUBTYPE_SIG_CREATE_TIME:
+	    if (!hashed)
+		break;
 	    impl = *p;
 	    if (!(_digp->saved & PGPDIG_SAVED_TIME) &&
 		(sigtype == PGPSIGTYPE_POSITIVE_CERT || sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT || sigtype == PGPSIGTYPE_STANDALONE))
@@ -478,8 +482,15 @@ static int pgpPrtSubType(const uint8_t *
 	    pgpPrtHex("", p+1, plen-1);
 	    break;
 
-	case PGPSUBTYPE_PRIMARY_USERID:
 	case PGPSUBTYPE_KEY_FLAGS:
+	    if (!hashed)
+		break;
+	    impl = *p;		/* accept critical packet */
+	    _digp->key_flags = plen >= 2 ? p[1] : 0;
+	    pgpPrtHex("", p+1, plen-1);
+	    break;
+
+	case PGPSUBTYPE_PRIMARY_USERID:
 	case PGPSUBTYPE_EMBEDDED_SIG:
 	    impl = *p;		/* accept critical packet */
 	    pgpPrtHex("", p+1, plen-1);
@@ -550,7 +561,7 @@ static int pgpPrtSigParams(pgpTag tag, u
 	int mpil = pgpMpiLen(p);
 	if (pend - p < mpil)
 	    break;
-	if (sigtype == PGPSIGTYPE_BINARY || sigtype == PGPSIGTYPE_TEXT) {
+	if (sigp->tag == PGPTAG_SIGNATURE) {
 	    if (sigalg->setmpi(sigalg, i, p))
 		break;
 	}
@@ -657,7 +668,7 @@ static int pgpPrtSig(pgpTag tag, const u
 	    _digp->hashlen = sizeof(*v) + plen;
 	    _digp->hash = memcpy(xmalloc(_digp->hashlen), v, _digp->hashlen);
 	}
-	if (pgpPrtSubType(p, plen, v->sigtype, _digp))
+	if (pgpPrtSubType(p, plen, v->sigtype, _digp, 1))
 	    return 1;
 	p += plen;
 
@@ -668,7 +679,7 @@ static int pgpPrtSig(pgpTag tag, const u
 	if ((p + plen) > hend)
 	    return 1;
 
-	if (pgpPrtSubType(p, plen, v->sigtype, _digp))
+	if (pgpPrtSubType(p, plen, v->sigtype, _digp, 0))
 	    return 1;
 	p += plen;
 
@@ -1068,13 +1079,52 @@ unsigned int pgpDigParamsAlgo(pgpDigPara
     return algo;
 }
 
+static void hashKey(DIGEST_CTX hash, const struct pgpPkt *pkt)
+{
+    uint8_t head[] = {
+	0x99,
+	(pkt->blen >> 8),
+	(pkt->blen     )
+    };
+    rpmDigestUpdate(hash, head, 3);
+    rpmDigestUpdate(hash, pkt->body, pkt->blen);
+}
+
+static int verifySubkeyBindingSignature(pgpDigParams digp, struct pgpPkt *mainpkt, struct pgpPkt *subkeypkt, struct pgpPkt *sigpkt)
+{
+    int rc = -1; /* assume failure */
+    pgpDigParams sigdigp = NULL;
+    DIGEST_CTX hash = NULL;
+
+    if (mainpkt->tag != PGPTAG_PUBLIC_KEY || subkeypkt->tag != PGPTAG_PUBLIC_SUBKEY || sigpkt->tag != PGPTAG_SIGNATURE)
+	goto exit;
+    sigdigp = xcalloc(1, sizeof(*sigdigp));
+    sigdigp->tag = PGPTAG_SIGNATURE;
+    if (pgpPrtPkt(sigpkt, sigdigp))
+	goto exit;
+    if (sigdigp->sigtype != PGPSIGTYPE_SUBKEY_BINDING)
+	goto exit;
+    hash = rpmDigestInit(sigdigp->hash_algo, 0); 
+    if (!hash)
+	goto exit;
+    hashKey(hash, mainpkt);
+    hashKey(hash, subkeypkt);
+    if (pgpVerifySignatureRaw(digp, sigdigp, hash) == RPMRC_OK)
+	rc = 0;
+exit:
+    if (hash)
+	rpmDigestFinal(hash, NULL, NULL, 0);
+    pgpDigParamsFree(sigdigp);
+    return rc;
+}
+
 int pgpPrtParams(const uint8_t * pkts, size_t pktlen, unsigned int pkttype,
 		 pgpDigParams * ret)
 {
     const uint8_t *p = pkts;
     const uint8_t *pend = pkts + pktlen;
     pgpDigParams digp = NULL;
-    struct pgpPkt pkt;
+    struct pgpPkt mainpkt, pkt;
     int rc = -1; /* assume failure */
 
     while (p < pend) {
@@ -1087,6 +1137,7 @@ int pgpPrtParams(const uint8_t * pkts, s
 	    } else {
 		digp = xcalloc(1, sizeof(*digp));
 		digp->tag = pkt.tag;
+		mainpkt = pkt;
 	    }
 	}
 
@@ -1096,6 +1147,17 @@ int pgpPrtParams(const uint8_t * pkts, s
 	p += (pkt.body - pkt.head) + pkt.blen;
 	if (pkttype == PGPTAG_SIGNATURE)
 	    break;
+	if (pkt.tag == PGPTAG_PUBLIC_SUBKEY) {
+	    /* make sure that a binding signature follows and verify it */
+	    struct pgpPkt sigpkt;
+	    if (p == pend || decodePkt(p, (pend - p), &sigpkt)) {
+		digp = pgpDigParamsFree(digp);
+		break;
+	    }
+	    if (verifySubkeyBindingSignature(digp, &mainpkt, &pkt, &sigpkt))
+		break;
+	    p += (sigpkt.body - sigpkt.head) + sigpkt.blen;
+	}
     }
 
     rc = (digp && (p == pend)) ? 0 : -1;
@@ -1137,7 +1199,7 @@ int pgpPrtParamsSubkeys(const uint8_t *p
 	    digps[count] = xcalloc(1, sizeof(**digps));
 	    digps[count]->tag = PGPTAG_PUBLIC_SUBKEY;
 	    /* Copy UID from main key to subkey */
-	    digps[count]->userid = xstrdup(mainkey->userid);
+	    digps[count]->userid = mainkey->userid ? xstrdup(mainkey->userid) : NULL;
 
 	    if (getKeyID(pkt.body, pkt.blen, digps[count]->signid)) {
 		pgpDigParamsFree(digps[count]);
@@ -1148,6 +1210,17 @@ int pgpPrtParamsSubkeys(const uint8_t *p
 		pgpDigParamsFree(digps[count]);
 		continue;
 	    }
+	    /* check key flags from following binding signature */
+	    if (p == pend || decodePkt(p, (pend - p), &pkt) || pkt.tag != PGPTAG_SIGNATURE || pgpPrtPkt(&pkt, digps[count])) {
+		pgpDigParamsFree(digps[count]);
+		continue;
+	    }
+	    if (!(digps[count]->key_flags & 0x02)) {
+		/* not a signing subkey */
+		pgpDigParamsFree(digps[count]);
+		continue;
+	    }
+	    
 	    count++;
 	}
     }
@@ -1208,7 +1281,7 @@ char *pgpIdentItem(pgpDigParams digp)
     return id;
 }
 
-rpmRC pgpVerifySignature(pgpDigParams key, pgpDigParams sig, DIGEST_CTX hashctx)
+static rpmRC pgpVerifySignatureRaw(pgpDigParams key, pgpDigParams sig, DIGEST_CTX hashctx)
 {
     DIGEST_CTX ctx = rpmDigestDup(hashctx);
     uint8_t *hash = NULL;
@@ -1260,6 +1333,13 @@ exit:
 
 }
 
+rpmRC pgpVerifySignature(pgpDigParams key, pgpDigParams sig, DIGEST_CTX hashctx)
+{
+    if (!sig || sig->tag != PGPTAG_SIGNATURE || (sig->sigtype != PGPSIGTYPE_BINARY && sig->sigtype != PGPSIGTYPE_TEXT && sig->sigtype != PGPSIGTYPE_STANDALONE))
+	return RPMRC_FAIL;
+    return pgpVerifySignatureRaw(key, sig, hashctx);
+}
+
 rpmRC pgpVerifySig(pgpDig dig, DIGEST_CTX hashctx)
 {
     if (dig == NULL || hashctx == NULL)
openSUSE Build Service is sponsored by