diff --git a/SOURCES/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch b/SOURCES/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch
new file mode 100644
index 0000000..4ecdab7
--- /dev/null
+++ b/SOURCES/0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch
@@ -0,0 +1,32 @@
+From 5b21f2f2a12adfd9e1adffc2bf1ad7171ee5d03c Mon Sep 17 00:00:00 2001
+From: "Vladimir D. Seleznev" <vseleznv@altlinux.org>
+Date: Tue, 13 Mar 2018 00:04:45 +0300
+Subject: [PATCH 01/33] Add RPMTAG_AUTOINSTALLED reservation
+
+This tag is needed to track automatically installed packages with rpmdb.
+Zero value means that a package was installed manually, other values
+mean that the package was installed automatically as some else package
+dependency.
+
+This tag is reserved for ALT Linux Team and marked as unimplemented.
+
+Signed-off-by: Vladimir D. Seleznev <vseleznv@altlinux.org>
+---
+ lib/rpmtag.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/lib/rpmtag.h b/lib/rpmtag.h
+index 57b10a706..664561156 100644
+--- a/lib/rpmtag.h
++++ b/lib/rpmtag.h
+@@ -368,6 +368,7 @@ typedef enum rpmTag_e {
+     RPMTAG_FILESIGNATURELENGTH  = 5091, /* i */
+     RPMTAG_PAYLOADDIGEST	= 5092, /* s[] */
+     RPMTAG_PAYLOADDIGESTALGO	= 5093, /* i */
++    RPMTAG_AUTOINSTALLED	= 5094, /* i reservation (unimplemented) */
+     RPMTAG_MODULARITYLABEL	= 5096, /* s */
+ 
+     RPMTAG_FIRSTFREE_TAG	/*!< internal */
+-- 
+2.27.0
+
diff --git a/SOURCES/0002-Add-RPMTAG_IDENTITY-reservation.patch b/SOURCES/0002-Add-RPMTAG_IDENTITY-reservation.patch
new file mode 100644
index 0000000..9dca222
--- /dev/null
+++ b/SOURCES/0002-Add-RPMTAG_IDENTITY-reservation.patch
@@ -0,0 +1,34 @@
+From a74ea72cb47dcdc1006ffbdd23643964bd40f580 Mon Sep 17 00:00:00 2001
+From: "Vladimir D. Seleznev" <vseleznv@altlinux.org>
+Date: Tue, 13 Mar 2018 00:04:46 +0300
+Subject: [PATCH 02/33] Add RPMTAG_IDENTITY reservation
+
+This tag represents binary package build characteristic: if two binary
+packages have equal RPMTAG_IDENTITY values, it means that these packages
+have no significant differences.
+
+One of the applications of RPMTAG_IDENTITY is reproducible build
+verification.
+
+This tag is reserved for ALT Linux Team and marked as unimplemented.
+
+Signed-off-by: Vladimir D. Seleznev <vseleznv@altlinux.org>
+---
+ lib/rpmtag.h | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/lib/rpmtag.h b/lib/rpmtag.h
+index 664561156..002492d20 100644
+--- a/lib/rpmtag.h
++++ b/lib/rpmtag.h
+@@ -369,6 +369,7 @@ typedef enum rpmTag_e {
+     RPMTAG_PAYLOADDIGEST	= 5092, /* s[] */
+     RPMTAG_PAYLOADDIGESTALGO	= 5093, /* i */
+     RPMTAG_AUTOINSTALLED	= 5094, /* i reservation (unimplemented) */
++    RPMTAG_IDENTITY		= 5095, /* s reservation (unimplemented) */
+     RPMTAG_MODULARITYLABEL	= 5096, /* s */
+ 
+     RPMTAG_FIRSTFREE_TAG	/*!< internal */
+-- 
+2.27.0
+
diff --git a/SOURCES/0003-Use-lower-level-headerPut-for-file-signing.patch b/SOURCES/0003-Use-lower-level-headerPut-for-file-signing.patch
new file mode 100644
index 0000000..129f420
--- /dev/null
+++ b/SOURCES/0003-Use-lower-level-headerPut-for-file-signing.patch
@@ -0,0 +1,58 @@
+From 492823ca53f5666b82e94fcfdd422bdcd67005cb Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 10 Oct 2017 11:07:38 +0300
+Subject: [PATCH 03/33] Use lower-level headerPut() for file signing
+
+Not supposed to affect behavior at all, but we'll need this in the
+next step.
+---
+ sign/rpmsignfiles.c | 19 ++++++++++++++++---
+ 1 file changed, 16 insertions(+), 3 deletions(-)
+
+diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
+index 61b73bd40..1fc127cb1 100644
+--- a/sign/rpmsignfiles.c
++++ b/sign/rpmsignfiles.c
+@@ -82,7 +82,7 @@ char *keypass)
+ 
+ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
+ {
+-    struct rpmtd_s digests;
++    struct rpmtd_s digests, td;
+     int algo;
+     int diglen;
+     uint32_t siglen;
+@@ -110,7 +110,19 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
+     headerDel(h, RPMTAG_FILESIGNATURELENGTH);
+     headerDel(h, RPMTAG_FILESIGNATURES);
+     siglen = signatureLength(algoname, diglen, key, keypass);
+-    headerPutUint32(h, RPMTAG_FILESIGNATURELENGTH, &siglen, 1);
++
++    rpmtdReset(&td);
++    td.tag = RPMTAG_FILESIGNATURELENGTH;
++    td.type = RPM_INT32_TYPE;
++    td.data = &siglen;
++    td.count = 1;
++    headerPut(h, &td, HEADERPUT_DEFAULT);
++
++    rpmtdReset(&td);
++    td.tag = RPMTAG_FILESIGNATURES;
++    td.type = RPM_STRING_ARRAY_TYPE;
++    td.data = NULL; /* set in the loop below */
++    td.count = 1;
+ 
+     headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);
+     while ((digest = rpmtdNextString(&digests))) {
+@@ -120,7 +132,8 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
+ 	    rc = RPMRC_FAIL;
+ 	    goto exit;
+ 	}
+-	if (!headerPutString(h, RPMTAG_FILESIGNATURES, signature)) {
++	td.data = &signature;
++	if (!headerPut(h, &td, HEADERPUT_APPEND)) {
+ 	    free(signature);
+ 	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
+ 	    rc = RPMRC_FAIL;
+-- 
+2.27.0
+
diff --git a/SOURCES/0004-Place-file-signatures-into-the-signature-header-wher.patch b/SOURCES/0004-Place-file-signatures-into-the-signature-header-wher.patch
new file mode 100644
index 0000000..12f8d8b
--- /dev/null
+++ b/SOURCES/0004-Place-file-signatures-into-the-signature-header-wher.patch
@@ -0,0 +1,329 @@
+From f354c5a4265ddad758ad41abfb2f5fe174a54c69 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 10 Oct 2017 11:44:10 +0300
+Subject: [PATCH 04/33] Place file signatures into the signature header where
+ they belong
+
+The original file signing puts the file signatures into the main header
+immutable region, invalidating all previous signatures and digests so
+the package no longer appears to be what it was when it came out of the
+assembly line. Which is bad. Doing that also requires recalculating
+everything again which is just added complexity, and since it adds
+stuff to different place from the rest of the signing, it requires yet
+complexity to deal with that. Moving the file signatures into the
+signature header solves all that and allows removing a big pile of
+now unnecessary code.
+
+Because this means retrofitting tags bass-ackwards into the signature
+header, the tag definitions are backwards to everything else. Other
+options would certainly be possible, but this makes things look more
+normal on the signature header side. "Users" only ever see the
+unchanged file signature tags as they have always been.
+
+This also means the signature header can be MUCH bigger than ever before,
+so bump up the limit (to 64MB, arbitrary something for now), and
+permit string array types to be migrated from the signature header
+on package read.
+
+Caveats:
+This loses the check for identical existing signatures to keep the
+complexity down, it's hardly a critical thing and can be added back later.
+While file signing could now be done separately to other signing, that
+is not handled here.
+---
+ lib/rpmtag.h        |   4 ++
+ sign/rpmgensig.c    | 161 +++-----------------------------------------
+ sign/rpmsignfiles.c |  14 ++--
+ sign/rpmsignfiles.h |   5 +-
+ 4 files changed, 22 insertions(+), 162 deletions(-)
+
+diff --git a/lib/rpmtag.h b/lib/rpmtag.h
+index 002492d20..46719ec75 100644
+--- a/lib/rpmtag.h
++++ b/lib/rpmtag.h
+@@ -65,6 +65,8 @@ typedef enum rpmTag_e {
+     RPMTAG_LONGARCHIVESIZE	= RPMTAG_SIG_BASE+15,	/* l */
+     /* RPMTAG_SIG_BASE+16 reserved */
+     RPMTAG_SHA256HEADER		= RPMTAG_SIG_BASE+17,	/* s */
++    /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURELENGTH */
++    /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURES */
+ 
+     RPMTAG_NAME  		= 1000,	/* s */
+ #define	RPMTAG_N	RPMTAG_NAME	/* s */
+@@ -425,6 +427,8 @@ typedef enum rpmSigTag_e {
+     RPMSIGTAG_LONGSIZE	= RPMTAG_LONGSIGSIZE,	/*!< internal Header+Payload size (64bit) in bytes. */
+     RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */
+     RPMSIGTAG_SHA256	= RPMTAG_SHA256HEADER,
++    RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 18,
++    RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 19,
+ } rpmSigTag;
+ 
+ 
+diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
+index 8f77ad9c1..5fddb56ea 100644
+--- a/sign/rpmgensig.c
++++ b/sign/rpmgensig.c
+@@ -417,74 +417,12 @@ static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag)
+     }
+ }
+ 
+-#ifdef WITH_IMAEVM
+-static rpmRC replaceSigDigests(FD_t fd, const char *rpm, Header *sigp,
+-			       off_t sigStart, off_t sigTargetSize,
+-			       char *SHA256, char *SHA1, uint8_t *MD5)
+-{
+-    off_t archiveSize;
+-    rpmRC rc = RPMRC_OK;
+-
+-    if (Fseek(fd, sigStart, SEEK_SET) < 0) {
+-	rc = RPMRC_FAIL;
+-	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
+-		rpm, Fstrerror(fd));
+-	goto exit;
+-    }
+-
+-    /* Get payload size from signature tag */
+-    archiveSize = headerGetNumber(*sigp, RPMSIGTAG_PAYLOADSIZE);
+-    if (!archiveSize) {
+-	archiveSize = headerGetNumber(*sigp, RPMSIGTAG_LONGARCHIVESIZE);
+-    }
+-
+-    /* Set reserved space to 0 */
+-    rpmPushMacro(NULL, "__gpg_reserved_space", NULL, 0, RMIL_GLOBAL);
+-
+-    /* Replace old digests in sigh */
+-    rc = rpmGenerateSignature(SHA256, SHA1, MD5, sigTargetSize, archiveSize, fd);
+-    if (rc != RPMRC_OK) {
+-	rpmlog(RPMLOG_ERR, _("generateSignature failed\n"));
+-	goto exit;
+-    }
+-
+-    if (Fseek(fd, sigStart, SEEK_SET) < 0) {
+-	rc = RPMRC_FAIL;
+-	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
+-		rpm, Fstrerror(fd));
+-	goto exit;
+-    }
+-
+-    headerFree(*sigp);
+-    rc = rpmReadSignature(fd, sigp, NULL);
+-    if (rc != RPMRC_OK) {
+-	rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n"));
+-	goto exit;
+-    }
+-
+-exit:
+-    return rc;
+-}
+-#endif
+-
+-static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
+-				   Header *sigp, Header *hdrp,
+-				   off_t sigStart, off_t headerStart)
++static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
+ {
+ #ifdef WITH_IMAEVM
+-    FD_t ofd = NULL;
+-    char *trpm = NULL;
++    rpmRC rc;
+     char *key;
+     char *keypass;
+-    char *SHA1 = NULL;
+-    char *SHA256 = NULL;
+-    uint8_t *MD5 = NULL;
+-    off_t sigTargetSize;
+-    rpmRC rc = RPMRC_OK;
+-    struct rpmtd_s osigtd;
+-    char *o_sha1 = NULL;
+-
+-    unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE);
+ 
+     key = rpmExpand("%{?_file_signing_key}", NULL);
+ 
+@@ -494,94 +432,10 @@ static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
+ 	keypass = NULL;
+     }
+ 
+-    rc = rpmSignFiles(*hdrp, key, keypass);
+-    if (rc != RPMRC_OK) {
+-	goto exit;
+-    }
+-
+-    *hdrp = headerReload(*hdrp, RPMTAG_HEADERIMMUTABLE);
+-    if (*hdrp == NULL) {
+-	rc = RPMRC_FAIL;
+-	rpmlog(RPMLOG_ERR, _("headerReload failed\n"));
+-	goto exit;
+-    }
+-
+-    ofd = rpmMkTempFile(NULL, &trpm);
+-    if (ofd == NULL || Ferror(ofd)) {
+-	rc = RPMRC_FAIL;
+-	rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
+-	goto exit;
+-    }
+-
+-    /* Copy archive to temp file */
+-    if (copyFile(&fd, rpm, &ofd, trpm)) {
+-	rc = RPMRC_FAIL;
+-	rpmlog(RPMLOG_ERR, _("copyFile failed\n"));
+-	goto exit;
+-    }
+-
+-    if (Fseek(fd, headerStart, SEEK_SET) < 0) {
+-	rc = RPMRC_FAIL;
+-	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
+-		rpm, Fstrerror(fd));
+-	goto exit;
+-    }
++    rc = rpmSignFiles(*sigp, *hdrp, key, keypass);
+ 
+-    /* Start MD5 calculation */
+-    fdInitDigestID(fd, PGPHASHALGO_MD5, RPMSIGTAG_MD5, 0);
+-
+-    /* Write header to rpm and recalculate digests */
+-    fdInitDigestID(fd, PGPHASHALGO_SHA1, RPMSIGTAG_SHA1, 0);
+-    fdInitDigestID(fd, PGPHASHALGO_SHA256, RPMSIGTAG_SHA256, 0);
+-    rc = headerWrite(fd, *hdrp, HEADER_MAGIC_YES);
+-    if (rc != RPMRC_OK) {
+-	rpmlog(RPMLOG_ERR, _("headerWrite failed\n"));
+-	goto exit;
+-    }
+-    fdFiniDigest(fd, RPMSIGTAG_SHA1, (void **)&SHA1, NULL, 1);
+-    /* Only add SHA256 if it was there to begin with */
+-    if (headerIsEntry(*sigp, RPMSIGTAG_SHA256))
+-	fdFiniDigest(fd, RPMSIGTAG_SHA256, (void **)&SHA256, NULL, 1);
+-
+-    /* Copy archive from temp file */
+-    if (Fseek(ofd, 0, SEEK_SET) < 0) {
+-	rc = RPMRC_FAIL;
+-	rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
+-		rpm, Fstrerror(fd));
+-	goto exit;
+-    }
+-    if (copyFile(&ofd, trpm, &fd, rpm)) {
+-	rc = RPMRC_FAIL;
+-	rpmlog(RPMLOG_ERR, _("copyFile failed\n"));
+-	goto exit;
+-    }
+-    unlink(trpm);
+-
+-    sigTargetSize = Ftell(fd) - headerStart;
+-    fdFiniDigest(fd, RPMSIGTAG_MD5, (void **)&MD5, NULL, 0);
+-
+-    if (headerGet(*sigp, RPMSIGTAG_SHA1, &osigtd, HEADERGET_DEFAULT)) {
+-	o_sha1 = xstrdup(osigtd.data);
+-	rpmtdFreeData(&osigtd);
+-    }
+-
+-    if (strcmp(SHA1, o_sha1) == 0)
+-	rpmlog(RPMLOG_WARNING,
+-	       _("%s already contains identical file signatures\n"),
+-	       rpm);
+-    else
+-	replaceSigDigests(fd, rpm, sigp, sigStart, sigTargetSize, SHA256, SHA1, MD5);
+-
+-exit:
+-    free(trpm);
+-    free(MD5);
+-    free(SHA1);
+-    free(SHA256);
+-    free(o_sha1);
+     free(keypass);
+     free(key);
+-    if (ofd)
+-	(void) closeFile(&ofd);
+     return rc;
+ #else
+     rpmlog(RPMLOG_ERR, _("file signing support not built in\n"));
+@@ -674,13 +528,14 @@ static int rpmSign(const char *rpm, int deleting, int signfiles)
+ 	goto exit;
+     }
+ 
+-    if (signfiles) {
+-	includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart);
+-    }
+-
+     unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);
+     origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
+ 
++    if (signfiles) {
++	if (includeFileSignatures(&sigh, &h))
++	    goto exit;
++    }
++
+     if (deleting) {	/* Nuke all the signature tags. */
+ 	deleteSigs(sigh);
+     } else {
+diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
+index 1fc127cb1..2dcc50400 100644
+--- a/sign/rpmsignfiles.c
++++ b/sign/rpmsignfiles.c
+@@ -80,7 +80,7 @@ char *keypass)
+     return siglen + 1;
+ }
+ 
+-rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
++rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ {
+     struct rpmtd_s digests, td;
+     int algo;
+@@ -107,19 +107,19 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
+ 	return RPMRC_FAIL;
+     }
+ 
+-    headerDel(h, RPMTAG_FILESIGNATURELENGTH);
+-    headerDel(h, RPMTAG_FILESIGNATURES);
++    headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);
++    headerDel(sigh, RPMTAG_FILESIGNATURES);
+     siglen = signatureLength(algoname, diglen, key, keypass);
+ 
+     rpmtdReset(&td);
+-    td.tag = RPMTAG_FILESIGNATURELENGTH;
++    td.tag = RPMSIGTAG_FILESIGNATURELENGTH;
+     td.type = RPM_INT32_TYPE;
+     td.data = &siglen;
+     td.count = 1;
+-    headerPut(h, &td, HEADERPUT_DEFAULT);
++    headerPut(sigh, &td, HEADERPUT_DEFAULT);
+ 
+     rpmtdReset(&td);
+-    td.tag = RPMTAG_FILESIGNATURES;
++    td.tag = RPMSIGTAG_FILESIGNATURES;
+     td.type = RPM_STRING_ARRAY_TYPE;
+     td.data = NULL; /* set in the loop below */
+     td.count = 1;
+@@ -133,7 +133,7 @@ rpmRC rpmSignFiles(Header h, const char *key, char *keypass)
+ 	    goto exit;
+ 	}
+ 	td.data = &signature;
+-	if (!headerPut(h, &td, HEADERPUT_APPEND)) {
++	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {
+ 	    free(signature);
+ 	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
+ 	    rc = RPMRC_FAIL;
+diff --git a/sign/rpmsignfiles.h b/sign/rpmsignfiles.h
+index 4163fafde..2ff623cdf 100644
+--- a/sign/rpmsignfiles.h
++++ b/sign/rpmsignfiles.h
+@@ -9,14 +9,15 @@ extern "C" {
+ #endif
+ 
+ /**
+- * Sign file digests in header and store the signatures in header
++ * Sign file digests in header into signature header
++ * @param sigh		package signature header
+  * @param h		package header
+  * @param key		signing key
+  * @param keypass	signing key password
+  * @return		RPMRC_OK on success
+  */
+ RPM_GNUC_INTERNAL
+-rpmRC rpmSignFiles(Header h, const char *key, char *keypass);
++rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass);
+ 
+ #ifdef _cplusplus
+ }
+-- 
+2.27.0
+
diff --git a/SOURCES/0005-Unbreak-file-signing-from-previous-commit.patch b/SOURCES/0005-Unbreak-file-signing-from-previous-commit.patch
new file mode 100644
index 0000000..ce68ba5
--- /dev/null
+++ b/SOURCES/0005-Unbreak-file-signing-from-previous-commit.patch
@@ -0,0 +1,30 @@
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 10 Oct 2017 14:40:05 +0300
+Subject: [PATCH 05/33] Unbreak file signing from previous commit
+From cabecd35ff6842c029103732ca5e5ea7dcdce256 Mon Sep 17 00:00:00 2001
+
+Commit f558e886050c4e98f6cdde391df679a411b3f62c essentially broke
+file signing because signatures never get migrated into the package
+header. This is what happens when you play around with too many
+variants of the same thing and forget to test what ultimately got
+committed, which was subtly different from anything else so far... :(
+---
+ lib/package.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/lib/package.c b/lib/package.c
+index 211fd3902..b7d996a12 100644
+--- a/lib/package.c
++++ b/lib/package.c
+@@ -43,6 +43,8 @@ struct taglate_s {
+     { RPMSIGTAG_GPG, RPMTAG_SIGGPG, 0, 0 },
+     /* { RPMSIGTAG_PGP5, RPMTAG_SIGPGP5, 0, 0 }, */ /* long obsolete, dont use */
+     { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 },
++    { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },
++    { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },
+     { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },
+     { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },
+     { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },
+-- 
+2.27.0
+
diff --git a/SOURCES/0006-Assume-failure-in-rpmSignFiles.patch b/SOURCES/0006-Assume-failure-in-rpmSignFiles.patch
new file mode 100644
index 0000000..1b987f5
--- /dev/null
+++ b/SOURCES/0006-Assume-failure-in-rpmSignFiles.patch
@@ -0,0 +1,71 @@
+From bcdd8505e792fd67c1480d43d987b92a61710e53 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 10 Oct 2017 14:43:58 +0300
+Subject: [PATCH 06/33] Assume failure in rpmSignFiles()
+
+Doesn't make it any shorter yet, but makes more sense in the next steps.
+Just refactoring.
+---
+ sign/rpmsignfiles.c | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
+index 2dcc50400..c1d227a07 100644
+--- a/sign/rpmsignfiles.c
++++ b/sign/rpmsignfiles.c
+@@ -88,23 +88,24 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+     uint32_t siglen;
+     const char *algoname;
+     const char *digest;
+-    char *signature;
+-    rpmRC rc = RPMRC_OK;
++    char *signature = NULL;
++    rpmRC rc = RPMRC_FAIL;
+ 
++    rpmtdReset(&digests);
+     algo = headerGetNumber(h, RPMTAG_FILEDIGESTALGO);
+     if (!algo) {
+         /* use default algorithm */
+         algo = PGPHASHALGO_MD5;
+     } else if (algo < 0 || algo >= ARRAY_SIZE(hash_algo_name)) {
+ 	rpmlog(RPMLOG_ERR, _("File digest algorithm id is invalid"));
+-	return RPMRC_FAIL;
++	goto exit;
+     }
+ 
+     diglen = rpmDigestLength(algo);
+     algoname = hash_algo_name[algo];
+     if (!algoname) {
+ 	rpmlog(RPMLOG_ERR, _("hash_algo_name failed\n"));
+-	return RPMRC_FAIL;
++	goto exit;
+     }
+ 
+     headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);
+@@ -129,20 +130,19 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ 	signature = signFile(algoname, digest, diglen, key, keypass);
+ 	if (!signature) {
+ 	    rpmlog(RPMLOG_ERR, _("signFile failed\n"));
+-	    rc = RPMRC_FAIL;
+ 	    goto exit;
+ 	}
+ 	td.data = &signature;
+ 	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {
+-	    free(signature);
+ 	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
+-	    rc = RPMRC_FAIL;
+ 	    goto exit;
+ 	}
+-	free(signature);
++	signature = _free(signature);
+     }
++    rc = RPMRC_OK;
+ 
+ exit:
++    free(signature);
+     rpmtdFreeData(&digests);
+     return rc;
+ }
+-- 
+2.27.0
+
diff --git a/SOURCES/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch b/SOURCES/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch
new file mode 100644
index 0000000..b70d845
--- /dev/null
+++ b/SOURCES/0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch
@@ -0,0 +1,108 @@
+From 0a7318ab4467d3156723c7a265dbd3456b8d1e20 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 10 Oct 2017 14:44:18 +0300
+Subject: [PATCH 07/33] Use rpm file info sets instead of header for retrieving
+ file data
+
+Simplifies the code a little, but more imporantly it avoids duplicating
+code and special knowledge like the default digest algo and converting
+hex to binary. As a side-effect, this fixes RPMTAG_FILESIGNATURELENGTH
+inadvertly getting added into packages that have no files at all.
+---
+ sign/rpmsignfiles.c | 36 +++++++++++++++++-------------------
+ 1 file changed, 17 insertions(+), 19 deletions(-)
+
+diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
+index c1d227a07..de7a73cfd 100644
+--- a/sign/rpmsignfiles.c
++++ b/sign/rpmsignfiles.c
+@@ -8,7 +8,7 @@
+ #include "imaevm.h"
+ 
+ #include <rpm/rpmlog.h>		/* rpmlog */
+-#include <rpm/rpmstring.h>	/* rnibble */
++#include <rpm/rpmfi.h>
+ #include <rpm/rpmpgp.h>		/* rpmDigestLength */
+ #include "lib/header.h"		/* HEADERGET_MINMEM */
+ #include "lib/rpmtypes.h"	/* rpmRC */
+@@ -32,7 +32,7 @@ static const char *hash_algo_name[] = {
+ 
+ #define ARRAY_SIZE(a)  (sizeof(a) / sizeof(a[0]))
+ 
+-static char *signFile(const char *algo, const char *fdigest, int diglen,
++static char *signFile(const char *algo, const uint8_t *fdigest, int diglen,
+ const char *key, char *keypass)
+ {
+     char *fsignature;
+@@ -40,15 +40,11 @@ const char *key, char *keypass)
+     unsigned char signature[MAX_SIGNATURE_LENGTH];
+     int siglen;
+ 
+-    /* convert file digest hex to binary */
+-    memset(digest, 0, diglen);
+     /* some entries don't have a digest - we return an empty signature */
+-    if (strlen(fdigest) != diglen * 2)
++    memset(digest, 0, diglen);
++    if (memcmp(digest, fdigest, diglen) == 0)
+         return strdup("");
+ 
+-    for (int i = 0; i < diglen; ++i, fdigest += 2)
+-	digest[i] = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
+-
+     /* prepare file signature */
+     memset(signature, 0, MAX_SIGNATURE_LENGTH);
+     signature[0] = '\x03';
+@@ -82,21 +78,23 @@ char *keypass)
+ 
+ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ {
+-    struct rpmtd_s digests, td;
++    struct rpmtd_s td;
+     int algo;
+     int diglen;
+     uint32_t siglen;
+     const char *algoname;
+-    const char *digest;
++    const uint8_t *digest;
+     char *signature = NULL;
+     rpmRC rc = RPMRC_FAIL;
++    rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
++
++    if (rpmfiFC(fi) == 0) {
++	rc = RPMRC_OK;
++	goto exit;
++    }
+ 
+-    rpmtdReset(&digests);
+-    algo = headerGetNumber(h, RPMTAG_FILEDIGESTALGO);
+-    if (!algo) {
+-        /* use default algorithm */
+-        algo = PGPHASHALGO_MD5;
+-    } else if (algo < 0 || algo >= ARRAY_SIZE(hash_algo_name)) {
++    algo = rpmfiDigestAlgo(fi);
++    if (algo >= ARRAY_SIZE(hash_algo_name)) {
+ 	rpmlog(RPMLOG_ERR, _("File digest algorithm id is invalid"));
+ 	goto exit;
+     }
+@@ -125,8 +123,8 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+     td.data = NULL; /* set in the loop below */
+     td.count = 1;
+ 
+-    headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);
+-    while ((digest = rpmtdNextString(&digests))) {
++    while (rpmfiNext(fi) >= 0) {
++	digest = rpmfiFDigest(fi, NULL, NULL);
+ 	signature = signFile(algoname, digest, diglen, key, keypass);
+ 	if (!signature) {
+ 	    rpmlog(RPMLOG_ERR, _("signFile failed\n"));
+@@ -143,6 +141,6 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ 
+ exit:
+     free(signature);
+-    rpmtdFreeData(&digests);
++    rpmfiFree(fi);
+     return rc;
+ }
+-- 
+2.27.0
+
diff --git a/SOURCES/0008-Eliminate-redundant-signature-length-calculation-fun.patch b/SOURCES/0008-Eliminate-redundant-signature-length-calculation-fun.patch
new file mode 100644
index 0000000..1d7daa4
--- /dev/null
+++ b/SOURCES/0008-Eliminate-redundant-signature-length-calculation-fun.patch
@@ -0,0 +1,105 @@
+From ff2fb80469e9aa478ea4de3eae5d9c13ca411382 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 10 Oct 2017 15:04:38 +0300
+Subject: [PATCH 08/33] Eliminate redundant signature length calculation
+ function
+
+The actual signing function knows the length already, we just need to
+return it and then we can insert it if there was anything at all
+to sign.
+---
+ sign/rpmsignfiles.c | 40 ++++++++++++++--------------------------
+ 1 file changed, 14 insertions(+), 26 deletions(-)
+
+diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
+index de7a73cfd..9fe6e6d41 100644
+--- a/sign/rpmsignfiles.c
++++ b/sign/rpmsignfiles.c
+@@ -33,7 +33,7 @@ static const char *hash_algo_name[] = {
+ #define ARRAY_SIZE(a)  (sizeof(a) / sizeof(a[0]))
+ 
+ static char *signFile(const char *algo, const uint8_t *fdigest, int diglen,
+-const char *key, char *keypass)
++const char *key, char *keypass, uint32_t *siglenp)
+ {
+     char *fsignature;
+     unsigned char digest[diglen];
+@@ -56,32 +56,18 @@ const char *key, char *keypass)
+ 	return NULL;
+     }
+ 
++    *siglenp = siglen + 1;
+     /* convert file signature binary to hex */
+     fsignature = pgpHexStr(signature, siglen+1);
+     return fsignature;
+ }
+ 
+-static uint32_t signatureLength(const char *algo, int diglen, const char *key,
+-char *keypass)
+-{
+-    unsigned char digest[diglen];
+-    unsigned char signature[MAX_SIGNATURE_LENGTH];
+-
+-    memset(digest, 0, diglen);
+-    memset(signature, 0, MAX_SIGNATURE_LENGTH);
+-    signature[0] = '\x03';
+-
+-    uint32_t siglen = sign_hash(algo, digest, diglen, key, keypass,
+-				signature+1);
+-    return siglen + 1;
+-}
+-
+ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ {
+     struct rpmtd_s td;
+     int algo;
+     int diglen;
+-    uint32_t siglen;
++    uint32_t siglen = 0;
+     const char *algoname;
+     const uint8_t *digest;
+     char *signature = NULL;
+@@ -108,14 +94,6 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ 
+     headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);
+     headerDel(sigh, RPMTAG_FILESIGNATURES);
+-    siglen = signatureLength(algoname, diglen, key, keypass);
+-
+-    rpmtdReset(&td);
+-    td.tag = RPMSIGTAG_FILESIGNATURELENGTH;
+-    td.type = RPM_INT32_TYPE;
+-    td.data = &siglen;
+-    td.count = 1;
+-    headerPut(sigh, &td, HEADERPUT_DEFAULT);
+ 
+     rpmtdReset(&td);
+     td.tag = RPMSIGTAG_FILESIGNATURES;
+@@ -125,7 +103,7 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ 
+     while (rpmfiNext(fi) >= 0) {
+ 	digest = rpmfiFDigest(fi, NULL, NULL);
+-	signature = signFile(algoname, digest, diglen, key, keypass);
++	signature = signFile(algoname, digest, diglen, key, keypass, &siglen);
+ 	if (!signature) {
+ 	    rpmlog(RPMLOG_ERR, _("signFile failed\n"));
+ 	    goto exit;
+@@ -137,6 +115,16 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ 	}
+ 	signature = _free(signature);
+     }
++
++    if (siglen > 0) {
++	rpmtdReset(&td);
++	td.tag = RPMSIGTAG_FILESIGNATURELENGTH;
++	td.type = RPM_INT32_TYPE;
++	td.data = &siglen;
++	td.count = 1;
++	headerPut(sigh, &td, HEADERPUT_DEFAULT);
++    }
++
+     rc = RPMRC_OK;
+ 
+ exit:
+-- 
+2.27.0
+
diff --git a/SOURCES/0009-Drop-redundant-check-on-hash-algo-name.patch b/SOURCES/0009-Drop-redundant-check-on-hash-algo-name.patch
new file mode 100644
index 0000000..627511c
--- /dev/null
+++ b/SOURCES/0009-Drop-redundant-check-on-hash-algo-name.patch
@@ -0,0 +1,29 @@
+From efd41edd0c9ba848814a5434d986338c1691418e Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 10 Oct 2017 15:20:16 +0300
+Subject: [PATCH 09/33] Drop redundant check on hash algo name
+
+The array is already size-validated, me thinks we can safely
+assume the array to be populated with non-NULL values.
+---
+ sign/rpmsignfiles.c | 4 ----
+ 1 file changed, 4 deletions(-)
+
+diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
+index 9fe6e6d41..4876f66f2 100644
+--- a/sign/rpmsignfiles.c
++++ b/sign/rpmsignfiles.c
+@@ -87,10 +87,6 @@ rpmRC rpmSignFiles(Header sigh, Header h, const char *key, char *keypass)
+ 
+     diglen = rpmDigestLength(algo);
+     algoname = hash_algo_name[algo];
+-    if (!algoname) {
+-	rpmlog(RPMLOG_ERR, _("hash_algo_name failed\n"));
+-	goto exit;
+-    }
+ 
+     headerDel(sigh, RPMTAG_FILESIGNATURELENGTH);
+     headerDel(sigh, RPMTAG_FILESIGNATURES);
+-- 
+2.27.0
+
diff --git a/SOURCES/0010-Drop-redundant-check-on-hash-algo-name.patch b/SOURCES/0010-Drop-redundant-check-on-hash-algo-name.patch
new file mode 100644
index 0000000..e619007
--- /dev/null
+++ b/SOURCES/0010-Drop-redundant-check-on-hash-algo-name.patch
@@ -0,0 +1,40 @@
+From 3461bd52ef2d403de1c420962aac52834f6e4b34 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Tue, 10 Oct 2017 15:20:16 +0300
+Subject: [PATCH 10/33] Drop redundant check on hash algo name
+
+The array is already size-validated, me thinks we can safely
+assume the array to be populated with non-NULL values.
+---
+ lib/rpmtag.h | 8 ++++----
+ 1 file changed, 4 insertions(+), 4 deletions(-)
+
+diff --git a/lib/rpmtag.h b/lib/rpmtag.h
+index 46719ec75..40ff5fa5d 100644
+--- a/lib/rpmtag.h
++++ b/lib/rpmtag.h
+@@ -65,8 +65,8 @@ typedef enum rpmTag_e {
+     RPMTAG_LONGARCHIVESIZE	= RPMTAG_SIG_BASE+15,	/* l */
+     /* RPMTAG_SIG_BASE+16 reserved */
+     RPMTAG_SHA256HEADER		= RPMTAG_SIG_BASE+17,	/* s */
+-    /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURELENGTH */
+-    /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURES */
++    /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */
++    /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */
+ 
+     RPMTAG_NAME  		= 1000,	/* s */
+ #define	RPMTAG_N	RPMTAG_NAME	/* s */
+@@ -427,8 +427,8 @@ typedef enum rpmSigTag_e {
+     RPMSIGTAG_LONGSIZE	= RPMTAG_LONGSIGSIZE,	/*!< internal Header+Payload size (64bit) in bytes. */
+     RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */
+     RPMSIGTAG_SHA256	= RPMTAG_SHA256HEADER,
+-    RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 18,
+-    RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 19,
++    RPMSIGTAG_FILESIGNATURES           = RPMTAG_SIG_BASE + 18,
++    RPMSIGTAG_FILESIGNATURELENGTH      = RPMTAG_SIG_BASE + 19,
+ } rpmSigTag;
+ 
+ 
+-- 
+2.27.0
+
diff --git a/SOURCES/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch b/SOURCES/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch
new file mode 100644
index 0000000..d86b96b
--- /dev/null
+++ b/SOURCES/0011-Generalize-file-signing-to-use-a-generic-flags-field.patch
@@ -0,0 +1,129 @@
+From 9e1a49197a6ddd0e984c12c9dc15fe7af435b611 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Mon, 2 Mar 2020 13:56:33 +0200
+Subject: [PATCH 11/33] Generalize file signing to use a generic flags field in
+ signing arguments
+
+There will be any number of signing flags in the future, and we don't
+want to break the ABI for every single one of them by adding new
+fields to the sign argument struct. Replace the signfiles field
+with a bitfield in the common rpm style. No functional changes.
+
+This is an API change of course, but we'll have to bump the soname for
+the next release anyway so might as well do it now.
+---
+ rpmsign.c        | 11 ++++++-----
+ sign/rpmgensig.c |  8 ++++----
+ sign/rpmsign.h   |  8 +++++++-
+ 3 files changed, 17 insertions(+), 10 deletions(-)
+
+diff --git a/rpmsign.c b/rpmsign.c
+index 1a5cd59c2..57cb36919 100644
+--- a/rpmsign.c
++++ b/rpmsign.c
+@@ -19,7 +19,7 @@ enum modes {
+ static int mode = MODE_NONE;
+ 
+ #ifdef WITH_IMAEVM
+-static int signfiles = 0, fskpass = 0;
++static int fskpass = 0;
+ static char * fileSigningKey = NULL;
+ #endif
+ 
+@@ -33,7 +33,8 @@ static struct poptOption signOptsTable[] = {
+     { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,
+ 	N_("delete package signatures"), NULL },
+ #ifdef WITH_IMAEVM
+-    { "signfiles", '\0', POPT_ARG_NONE, &signfiles, 0,
++    { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
++	&sargs.signflags, RPMSIGN_FLAG_IMA,
+ 	N_("sign package(s) files"), NULL},
+     { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,
+ 	N_("use file signing key <key>"),
+@@ -107,7 +108,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
+ 	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
+     }
+ 
+-    if (signfiles) {
++    if (sargs->signflags & RPMSIGN_FLAG_IMA) {
+ 	char *fileSigningKeyPassword = NULL;
+ 	char *key = rpmExpand("%{?_file_signing_key}", NULL);
+ 	if (rstreq(key, "")) {
+@@ -126,7 +127,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
+ 	    free(fileSigningKeyPassword);
+ 	}
+ 
+-	sargs->signfiles = 1;
++	sargs->signflags |= RPMSIGN_FLAG_IMA;
+ 	free(key);
+     }
+ #endif
+@@ -163,7 +164,7 @@ int main(int argc, char *argv[])
+     }
+ 
+ #ifdef WITH_IMAEVM
+-    if (fileSigningKey && !signfiles) {
++    if (fileSigningKey && !(sargs.signflags & RPMSIGN_FLAG_IMA)) {
+ 	argerror(_("--fskpath may only be specified when signing files"));
+     }
+ #endif
+diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
+index 5fddb56ea..1981981f4 100644
+--- a/sign/rpmgensig.c
++++ b/sign/rpmgensig.c
+@@ -472,10 +472,10 @@ static int checkPkg(FD_t fd, char **msg)
+  * Create/modify elements in signature header.
+  * @param rpm		path to package
+  * @param deleting	adding or deleting signature?
+- * @param signfiles	sign files if non-zero
++ * @param flags
+  * @return		0 on success, -1 on error
+  */
+-static int rpmSign(const char *rpm, int deleting, int signfiles)
++static int rpmSign(const char *rpm, int deleting, int flags)
+ {
+     FD_t fd = NULL;
+     FD_t ofd = NULL;
+@@ -531,7 +531,7 @@ static int rpmSign(const char *rpm, int deleting, int signfiles)
+     unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);
+     origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
+ 
+-    if (signfiles) {
++    if (flags & RPMSIGN_FLAG_IMA) {
+ 	if (includeFileSignatures(&sigh, &h))
+ 	    goto exit;
+     }
+@@ -682,7 +682,7 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args)
+ 	}
+     }
+ 
+-    rc = rpmSign(path, 0, args ? args->signfiles : 0);
++    rc = rpmSign(path, 0, args ? args->signflags : 0);
+ 
+     if (args) {
+ 	if (args->hashalgo) {
+diff --git a/sign/rpmsign.h b/sign/rpmsign.h
+index bed8d6245..545e80d2d 100644
+--- a/sign/rpmsign.h
++++ b/sign/rpmsign.h
+@@ -13,10 +13,16 @@
+ extern "C" {
+ #endif
+ 
++enum rpmSignFlags_e {
++    RPMSIGN_FLAG_NONE		= 0,
++    RPMSIGN_FLAG_IMA		= (1 << 0),
++};
++typedef rpmFlags rpmSignFlags;
++
+ struct rpmSignArgs {
+     char *keyid;
+     pgpHashAlgo hashalgo;
+-    int signfiles;
++    rpmSignFlags signflags;
+     /* ... what else? */
+ };
+ 
+-- 
+2.27.0
+
diff --git a/SOURCES/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch b/SOURCES/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch
new file mode 100644
index 0000000..f287e92
--- /dev/null
+++ b/SOURCES/0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch
@@ -0,0 +1,201 @@
+From 031b8481a0dfe875e9cf0f5d440b9379a62651a6 Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Mon, 2 Mar 2020 14:47:26 +0200
+Subject: [PATCH 12/33] Stop adding rpm v3 header+payload signatures by default
+ where not needed
+
+On packages where a separate payload digest exists (ie those built with
+rpm >= 4.14), rpm v3 header+payload signatures are nothing but expensive
+legacy baggage, as the payload digest will be signed by a header-only
+signature already, without having to recalculate the entire file.
+
+Automatically detect the payload digest presence and only add V3
+signatures on packages that need it, but also add an override switch
+to force their addition if needed for compatibility or so. A particular
+use-case would be ability to signature-level verify the entire package
+on rpm older than 4.14.
+
+Fixes: #863
+---
+ doc/rpmsign.8      |  9 +++++++++
+ rpmsign.c          |  3 +++
+ sign/rpmgensig.c   | 24 +++++++++++++++++-------
+ sign/rpmsign.h     |  1 +
+ tests/rpmsigdig.at | 36 ++++++++++++++++++++++++++++++++++--
+ 5 files changed, 64 insertions(+), 9 deletions(-)
+
+diff --git a/doc/rpmsign.8 b/doc/rpmsign.8
+index d895a3b8c..f7ceae89b 100644
+--- a/doc/rpmsign.8
++++ b/doc/rpmsign.8
+@@ -11,6 +11,7 @@ rpmsign \- RPM Package Signing
+ 
+ .SS "rpmsign-options"
+ .PP
++[\fb--rpmv3\fR]
+ [\fb--fskpath \fIKEY\fb\fR] [\fB--signfiles\fR]
+ 
+ .SH DESCRIPTION
+@@ -32,6 +33,14 @@ Delete all signatures from each package \fIPACKAGE_FILE\fR given.
+ .SS "SIGN OPTIONS"
+ .PP
+ .TP
++\fB--rpmv3\fR
++Force RPM V3 header+payload signature addition.
++These are expensive and redundant baggage on packages where a separate
++payload digest exists (packages built with rpm >= 4.14).  Rpm will
++automatically detect the need for V3 signatures, but this option can be
++used to force their creation if the packages must be fully 
++signature verifiable with rpm < 4.14 or other interoperability reasons.
++.TP
+ \fB--fskpath \fIKEY\fB\fR
+ Used with \fB--signfiles\fR, use file signing key \fIKey\fR.
+ .TP
+diff --git a/rpmsign.c b/rpmsign.c
+index 57cb36919..a74948ba8 100644
+--- a/rpmsign.c
++++ b/rpmsign.c
+@@ -32,6 +32,9 @@ static struct poptOption signOptsTable[] = {
+ 	N_("sign package(s) (identical to --addsign)"), NULL },
+     { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,
+ 	N_("delete package signatures"), NULL },
++    { "rpmv3", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
++	&sargs.signflags, RPMSIGN_FLAG_RPMV3,
++	N_("create rpm v3 header+payload signatures") },
+ #ifdef WITH_IMAEVM
+     { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
+ 	&sargs.signflags, RPMSIGN_FLAG_IMA,
+diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
+index 1981981f4..4903a4de1 100644
+--- a/sign/rpmgensig.c
++++ b/sign/rpmgensig.c
+@@ -377,14 +377,17 @@ static int replaceSignature(Header sigh, sigTarget sigt_v3, sigTarget sigt_v4)
+ 
+     if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)
+ 	goto exit;
+-    rpmtdFree(sigtd);
+ 
+-    /* Assume the same signature test holds for v3 signature too */
+-    if ((sigtd = makeGPGSignature(sigh, 0, sigt_v3)) == NULL)
+-	goto exit;
++    if (sigt_v3) {
++	rpmtdFree(sigtd);
+ 
+-    if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)
+-	goto exit;
++	/* Assume the same signature test holds for v3 signature too */
++	if ((sigtd = makeGPGSignature(sigh, 0, sigt_v3)) == NULL)
++	    goto exit;
++
++	if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)
++	    goto exit;
++    }
+ 
+     rc = 0;
+ exit:
+@@ -528,6 +531,12 @@ static int rpmSign(const char *rpm, int deleting, int flags)
+ 	goto exit;
+     }
+ 
++    /* Always add V3 signatures if no payload digest present */
++    if (!(headerIsEntry(h, RPMTAG_PAYLOADDIGEST) ||
++	  headerIsEntry(h, RPMTAG_PAYLOADDIGESTALT))) {
++	flags |= RPMSIGN_FLAG_RPMV3;
++    }
++
+     unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);
+     origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
+ 
+@@ -540,6 +549,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)
+ 	deleteSigs(sigh);
+     } else {
+ 	/* Signature target containing header + payload */
++	int v3 = (flags & RPMSIGN_FLAG_RPMV3);
+ 	sigt_v3.fd = fd;
+ 	sigt_v3.start = headerStart;
+ 	sigt_v3.fileName = rpm;
+@@ -549,7 +559,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)
+ 	sigt_v4 = sigt_v3;
+ 	sigt_v4.size = headerSizeof(h, HEADER_MAGIC_YES);
+ 
+-	res = replaceSignature(sigh, &sigt_v3, &sigt_v4);
++	res = replaceSignature(sigh, v3 ? &sigt_v3 : NULL, &sigt_v4);
+ 	if (res != 0) {
+ 	    if (res == 1) {
+ 		rpmlog(RPMLOG_WARNING,
+diff --git a/sign/rpmsign.h b/sign/rpmsign.h
+index 545e80d2d..7a770d879 100644
+--- a/sign/rpmsign.h
++++ b/sign/rpmsign.h
+@@ -16,6 +16,7 @@ extern "C" {
+ enum rpmSignFlags_e {
+     RPMSIGN_FLAG_NONE		= 0,
+     RPMSIGN_FLAG_IMA		= (1 << 0),
++    RPMSIGN_FLAG_RPMV3		= (1 << 1),
+ };
+ typedef rpmFlags rpmSignFlags;
+ 
+diff --git a/tests/rpmsigdig.at b/tests/rpmsigdig.at
+index 880e5edd0..12e2221b3 100644
+--- a/tests/rpmsigdig.at
++++ b/tests/rpmsigdig.at
+@@ -391,7 +391,7 @@ AT_CLEANUP
+ 
+ # ------------------------------
+ # Test --addsign
+-AT_SETUP([rpmsign --addsign <unsigned>])
++AT_SETUP([rpmsign --addsign --rpmv3 <unsigned>])
+ AT_KEYWORDS([rpmsign signature])
+ AT_CHECK([
+ RPMDB_CLEAR
+@@ -399,7 +399,7 @@ RPMDB_INIT
+ rm -rf "${TOPDIR}"
+ 
+ cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64.rpm "${RPMTEST}"/tmp/
+-run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null
++run rpmsign --key-id 1964C5FC --rpmv3 --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null
+ echo PRE-IMPORT
+ runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm|grep -v digest
+ echo POST-IMPORT
+@@ -424,6 +424,38 @@ POST-DELSIGN
+ [])
+ AT_CLEANUP
+ 
++# Test --addsign
++AT_SETUP([rpmsign --addsign <unsigned>])
++AT_KEYWORDS([rpmsign signature])
++AT_CHECK([
++RPMDB_CLEAR
++RPMDB_INIT
++rm -rf "${TOPDIR}"
++
++cp "${RPMTEST}"/data/RPMS/hello-2.0-1.x86_64.rpm "${RPMTEST}"/tmp/
++run rpmsign --key-id 1964C5FC --addsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null
++echo PRE-IMPORT
++runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm|grep -v digest
++echo POST-IMPORT
++runroot rpmkeys --import /data/keys/rpm.org-rsa-2048-test.pub
++runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm|grep -v digest
++run rpmsign --delsign "${RPMTEST}"/tmp/hello-2.0-1.x86_64.rpm > /dev/null
++echo POST-DELSIGN
++runroot rpmkeys -Kv /tmp/hello-2.0-1.x86_64.rpm|grep -v digest
++],
++[0],
++[PRE-IMPORT
++/tmp/hello-2.0-1.x86_64.rpm:
++    Header V4 RSA/SHA256 Signature, key ID 1964c5fc: NOKEY
++POST-IMPORT
++/tmp/hello-2.0-1.x86_64.rpm:
++    Header V4 RSA/SHA256 Signature, key ID 1964c5fc: OK
++POST-DELSIGN
++/tmp/hello-2.0-1.x86_64.rpm:
++],
++[])
++AT_CLEANUP
++
+ # ------------------------------
+ # Test --delsign
+ AT_SETUP([rpmsign --delsign <package>])
+-- 
+2.27.0
+
diff --git a/SOURCES/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch b/SOURCES/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch
new file mode 100644
index 0000000..70975fa
--- /dev/null
+++ b/SOURCES/0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch
@@ -0,0 +1,27 @@
+From 5e11a52627882efe6a15622ec256835a821e3eff Mon Sep 17 00:00:00 2001
+From: Igor Kanyuka <ikanyuka@fb.com>
+Date: Thu, 29 Apr 2021 18:24:48 -0700
+Subject: [PATCH 13/33] RPMTAG_PAYLOADDIGESTALT is not backported here, don't
+ check if it's in the header
+
+---
+ sign/rpmgensig.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
+index 4903a4de1..a6e37e71b 100644
+--- a/sign/rpmgensig.c
++++ b/sign/rpmgensig.c
+@@ -532,8 +532,7 @@ static int rpmSign(const char *rpm, int deleting, int flags)
+     }
+ 
+     /* Always add V3 signatures if no payload digest present */
+-    if (!(headerIsEntry(h, RPMTAG_PAYLOADDIGEST) ||
+-	  headerIsEntry(h, RPMTAG_PAYLOADDIGESTALT))) {
++    if (!headerIsEntry(h, RPMTAG_PAYLOADDIGEST)) {
+ 	flags |= RPMSIGN_FLAG_RPMV3;
+     }
+ 
+-- 
+2.27.0
+
diff --git a/SOURCES/0014-Drop-support-for-dmalloc.patch b/SOURCES/0014-Drop-support-for-dmalloc.patch
new file mode 100644
index 0000000..55dd7d4
--- /dev/null
+++ b/SOURCES/0014-Drop-support-for-dmalloc.patch
@@ -0,0 +1,48 @@
+From 6398807623ca24eafac0607b3d09b244cc5dfd5d Mon Sep 17 00:00:00 2001
+From: Panu Matilainen <pmatilai@redhat.com>
+Date: Fri, 27 Mar 2020 15:09:25 +0200
+Subject: [PATCH 14/33] Drop support for dmalloc
+
+Last dmalloc release is from 2007, and these days there are plenty of
+other, maintained tools for debugging memory issues.
+---
+ configure.ac | 7 -------
+ debug.h      | 4 ----
+ 2 files changed, 11 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 57a4f4001..3c102d5eb 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1030,13 +1030,6 @@ AS_IF([test "$enable_plugins" != no],[
+ ])
+ AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes])
+ 
+-with_dmalloc=no
+-AC_ARG_WITH(dmalloc, [AS_HELP_STRING([--with-dmalloc],[build with dmalloc debugging support])])
+-if test "$with_dmalloc" = yes ; then
+-  AC_DEFINE(DMALLOC, 1, [Build with dmalloc support?])
+-  LIBS="$LIBS -ldmalloc"
+-fi
+-
+ user_with_uid0=$(awk -F: '$3==0 {print $1;exit}' /etc/passwd)
+ group_with_gid0=$(awk -F: '$3==0 {print $1;exit}' /etc/group)
+ AC_DEFINE_UNQUOTED([UID_0_USER],["$user_with_uid0"],[Get the user name having userid 0])
+diff --git a/debug.h b/debug.h
+index 3d34ea010..db7ea1df9 100644
+--- a/debug.h
++++ b/debug.h
+@@ -6,10 +6,6 @@
+ 
+ #include <assert.h>
+ 
+-#ifdef	DMALLOC
+-#include <dmalloc.h>
+-#endif
+-
+ #define RPMDBG_TOSTR(a)		RPMDBG_TOSTR_ARG(a)
+ #define RPMDBG_TOSTR_ARG(a)	#a
+ 
+-- 
+2.27.0
+
diff --git a/SOURCES/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch b/SOURCES/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch
new file mode 100644
index 0000000..e6dae81
--- /dev/null
+++ b/SOURCES/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch
@@ -0,0 +1,28 @@
+From 7784da14fe57df919df9dfdad30e436ffe6d3e28 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Mon, 20 Apr 2020 11:22:15 -0400
+Subject: [PATCH 15/33] rpmsign: RPMSIGN_FLAG_IMA is already set
+
+There is no need to set RPMSIGN_FLAG_IMA since it was already set to
+get here.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ rpmsign.c | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/rpmsign.c b/rpmsign.c
+index a74948ba8..e1d207da5 100644
+--- a/rpmsign.c
++++ b/rpmsign.c
+@@ -130,7 +130,6 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
+ 	    free(fileSigningKeyPassword);
+ 	}
+ 
+-	sargs->signflags |= RPMSIGN_FLAG_IMA;
+ 	free(key);
+     }
+ #endif
+-- 
+2.27.0
+
diff --git a/SOURCES/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch b/SOURCES/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch
new file mode 100644
index 0000000..89845cb
--- /dev/null
+++ b/SOURCES/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch
@@ -0,0 +1,136 @@
+From f525681b4f66026578bc728b864bfea3d814c29e Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Fri, 27 Mar 2020 18:31:36 -0400
+Subject: [PATCH 16/33] Add basic autoconf and framework for fsverity support
+
+Use the same signing key argument as is used for IMA file signing.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ configure.ac     | 19 +++++++++++++++++++
+ rpmsign.c        | 20 ++++++++++++++------
+ sign/Makefile.am |  5 +++++
+ sign/rpmsign.h   |  1 +
+ 4 files changed, 39 insertions(+), 6 deletions(-)
+
+diff --git a/configure.ac b/configure.ac
+index 3c102d5eb..cc7144440 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -919,6 +919,25 @@ fi
+ AM_CONDITIONAL(WITH_IMAEVM,[test "$with_imaevm" = yes])
+ AC_SUBST(WITH_IMAEVM_LIB)
+ 
++# fsverity
++AC_ARG_WITH([fsverity], [AS_HELP_STRING([--with-fsverity],[build with fsverity support])],[],[with_fsverity=no])
++if test "$with_fsverity" = yes ; then
++  AC_MSG_CHECKING([libfsverity])
++  AC_COMPILE_IFELSE(
++    [AC_LANG_PROGRAM(
++      [[#include <libfsverity.h>]],
++      [[return libfsverity_sign_digest(NULL, NULL, NULL, NULL);]]
++    )],
++    [AC_MSG_RESULT(yes)
++      AC_DEFINE(WITH_FSVERITY, 1, [Build with fsverity support?])
++      WITH_FSVERITY_LIB="-lfsverity"
++    ],
++    [AC_MSG_ERROR([--with-fsverity given, libfsverity or libfsverity.h missing])]
++  )
++fi
++AM_CONDITIONAL(WITH_FSVERITY,[test "$with_fsverity" = yes])
++AC_SUBST(WITH_FSVERITY_LIB)
++
+ # libcap
+ WITH_CAP_LIB=
+ AC_ARG_WITH(cap, [AS_HELP_STRING([--with-cap],[build with capability support])],
+diff --git a/rpmsign.c b/rpmsign.c
+index e1d207da5..8861c2c59 100644
+--- a/rpmsign.c
++++ b/rpmsign.c
+@@ -18,7 +18,7 @@ enum modes {
+ 
+ static int mode = MODE_NONE;
+ 
+-#ifdef WITH_IMAEVM
++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
+ static int fskpass = 0;
+ static char * fileSigningKey = NULL;
+ #endif
+@@ -39,6 +39,13 @@ static struct poptOption signOptsTable[] = {
+     { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
+ 	&sargs.signflags, RPMSIGN_FLAG_IMA,
+ 	N_("sign package(s) files"), NULL},
++#endif
++#ifdef WITH_FSVERITY
++    { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
++	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,
++	N_("generate fsverity signatures for package(s) files"), NULL},
++#endif
++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
+     { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,
+ 	N_("use file signing key <key>"),
+ 	N_("<key>") },
+@@ -59,7 +66,7 @@ static struct poptOption optionsTable[] = {
+     POPT_TABLEEND
+ };
+ 
+-#ifdef WITH_IMAEVM
++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
+ static char *get_fskpass(void)
+ {
+     struct termios flags, tmp_flags;
+@@ -106,12 +113,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
+ 	goto exit;
+     }
+ 
+-#ifdef WITH_IMAEVM
++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
+     if (fileSigningKey) {
+ 	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
+     }
+ 
+-    if (sargs->signflags & RPMSIGN_FLAG_IMA) {
++    if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) {
+ 	char *fileSigningKeyPassword = NULL;
+ 	char *key = rpmExpand("%{?_file_signing_key}", NULL);
+ 	if (rstreq(key, "")) {
+@@ -165,8 +172,9 @@ int main(int argc, char *argv[])
+ 	argerror(_("no arguments given"));
+     }
+ 
+-#ifdef WITH_IMAEVM
+-    if (fileSigningKey && !(sargs.signflags & RPMSIGN_FLAG_IMA)) {
++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
++    if (fileSigningKey &&
++	!(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) {
+ 	argerror(_("--fskpath may only be specified when signing files"));
+     }
+ #endif
+diff --git a/sign/Makefile.am b/sign/Makefile.am
+index db774de0e..8d372915a 100644
+--- a/sign/Makefile.am
++++ b/sign/Makefile.am
+@@ -24,3 +24,8 @@ if WITH_IMAEVM
+ librpmsign_la_SOURCES += rpmsignfiles.c rpmsignfiles.h
+ librpmsign_la_LIBADD += @WITH_IMAEVM_LIB@
+ endif
++
++if WITH_FSVERITY
++librpmsign_la_SOURCES += rpmsignverity.c rpmsignverity.h
++librpmsign_la_LIBADD += @WITH_FSVERITY_LIB@
++endif
+diff --git a/sign/rpmsign.h b/sign/rpmsign.h
+index 7a770d879..2b8a10a1a 100644
+--- a/sign/rpmsign.h
++++ b/sign/rpmsign.h
+@@ -17,6 +17,7 @@ enum rpmSignFlags_e {
+     RPMSIGN_FLAG_NONE		= 0,
+     RPMSIGN_FLAG_IMA		= (1 << 0),
+     RPMSIGN_FLAG_RPMV3		= (1 << 1),
++    RPMSIGN_FLAG_FSVERITY	= (1 << 2),
+ };
+ typedef rpmFlags rpmSignFlags;
+ 
+-- 
+2.27.0
+
diff --git a/SOURCES/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch b/SOURCES/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch
new file mode 100644
index 0000000..ae64146
--- /dev/null
+++ b/SOURCES/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch
@@ -0,0 +1,51 @@
+From dbb4f464d177e2c3bfa13b1b2bb511fa6fde40d9 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Wed, 27 May 2020 16:49:03 -0400
+Subject: [PATCH 17/33] rpmsign: Add helper to indicate file signing enabled
+
+Helper function returning true if either IMA or VERITY signatures are
+to be applied. This simplifies the code and makes it easier to read.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ rpmsign.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/rpmsign.c b/rpmsign.c
+index 8861c2c59..94cbf1d1a 100644
+--- a/rpmsign.c
++++ b/rpmsign.c
+@@ -67,6 +67,11 @@ static struct poptOption optionsTable[] = {
+ };
+ 
+ #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
++static int flags_sign_files(int flags)
++{
++	return (flags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY) ? 1 : 0);
++}
++
+ static char *get_fskpass(void)
+ {
+     struct termios flags, tmp_flags;
+@@ -118,7 +123,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
+ 	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
+     }
+ 
+-    if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) {
++    if (flags_sign_files(sargs->signflags)) {
+ 	char *fileSigningKeyPassword = NULL;
+ 	char *key = rpmExpand("%{?_file_signing_key}", NULL);
+ 	if (rstreq(key, "")) {
+@@ -173,8 +178,7 @@ int main(int argc, char *argv[])
+     }
+ 
+ #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
+-    if (fileSigningKey &&
+-	!(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) {
++    if (fileSigningKey && !(flags_sign_files(sargs.signflags))) {
+ 	argerror(_("--fskpath may only be specified when signing files"));
+     }
+ #endif
+-- 
+2.27.0
+
diff --git a/SOURCES/0018-rpmsign-Handle-certpath-for-signing-certificate.patch b/SOURCES/0018-rpmsign-Handle-certpath-for-signing-certificate.patch
new file mode 100644
index 0000000..77a8b31
--- /dev/null
+++ b/SOURCES/0018-rpmsign-Handle-certpath-for-signing-certificate.patch
@@ -0,0 +1,52 @@
+From 5e74846046e06f5a3401c4d2eb4ccfadacd4ab53 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Fri, 3 Apr 2020 16:26:06 -0400
+Subject: [PATCH 18/33] rpmsign: Handle --certpath for signing certificate
+
+fsverirty needs a certificate for signing, in addition to the signing key.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ rpmsign.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+diff --git a/rpmsign.c b/rpmsign.c
+index 94cbf1d1a..074dd8b13 100644
+--- a/rpmsign.c
++++ b/rpmsign.c
+@@ -22,6 +22,9 @@ static int mode = MODE_NONE;
+ static int fskpass = 0;
+ static char * fileSigningKey = NULL;
+ #endif
++#ifdef WITH_FSVERITY
++static char * fileSigningCert = NULL;
++#endif
+ 
+ static struct rpmSignArgs sargs = {NULL, 0, 0};
+ 
+@@ -44,6 +47,9 @@ static struct poptOption signOptsTable[] = {
+     { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
+ 	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,
+ 	N_("generate fsverity signatures for package(s) files"), NULL},
++    { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0,
++	N_("use file signing cert <cert>"),
++	N_("<cert>") },
+ #endif
+ #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
+     { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,
+@@ -123,6 +129,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
+ 	rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
+     }
+ 
++#ifdef WITH_FSVERITY
++    if (fileSigningCert) {
++	rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL);
++    }
++#endif
++
+     if (flags_sign_files(sargs->signflags)) {
+ 	char *fileSigningKeyPassword = NULL;
+ 	char *key = rpmExpand("%{?_file_signing_key}", NULL);
+-- 
+2.27.0
+
diff --git a/SOURCES/0019-Implement-rpmSignVerity.patch b/SOURCES/0019-Implement-rpmSignVerity.patch
new file mode 100644
index 0000000..70e873a
--- /dev/null
+++ b/SOURCES/0019-Implement-rpmSignVerity.patch
@@ -0,0 +1,243 @@
+From d447376aa2bf66a5d5b6a928fb0c6e65189910ba Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Fri, 3 Apr 2020 16:38:08 -0400
+Subject: [PATCH 19/33] Implement rpmSignVerity()
+
+This generates the root Merkle tree hash and signs it using the
+specified key and certificate.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ sign/rpmgensig.c     |  36 +++++++++++++
+ sign/rpmsignverity.c | 121 +++++++++++++++++++++++++++++++++++++++++++
+ sign/rpmsignverity.h |  29 +++++++++++
+ 3 files changed, 186 insertions(+)
+ create mode 100644 sign/rpmsignverity.c
+ create mode 100644 sign/rpmsignverity.h
+
+diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
+index a6e37e71b..8d5c5858f 100644
+--- a/sign/rpmgensig.c
++++ b/sign/rpmgensig.c
+@@ -22,6 +22,7 @@
+ #include "lib/signature.h"
+ #include "lib/rpmvs.h"
+ #include "sign/rpmsignfiles.h"
++#include "sign/rpmsignverity.h"
+ 
+ #include "debug.h"
+ 
+@@ -446,6 +447,36 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
+ #endif
+ }
+ 
++static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)
++{
++#ifdef WITH_FSVERITY
++    rpmRC rc;
++    char *key = rpmExpand("%{?_file_signing_key}", NULL);
++    char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
++    char *cert = rpmExpand("%{?_file_signing_cert}", NULL);
++
++    if (rstreq(keypass, "")) {
++	free(keypass);
++	keypass = NULL;
++    }
++
++    if (key && cert) {
++	rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert);
++    } else {
++	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));
++	rc = RPMRC_FAIL;
++    }
++
++    free(keypass);
++    free(key);
++    free(cert);
++    return rc;
++#else
++    rpmlog(RPMLOG_ERR, _("fsverity signing support not built in\n"));
++    return RPMRC_FAIL;
++#endif
++}
++
+ static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata)
+ {
+     char **msg = cbdata;
+@@ -544,6 +575,11 @@ static int rpmSign(const char *rpm, int deleting, int flags)
+ 	    goto exit;
+     }
+ 
++    if (flags & RPMSIGN_FLAG_FSVERITY) {
++	if (includeVeritySignatures(fd, &sigh, &h))
++	    goto exit;
++    }
++
+     if (deleting) {	/* Nuke all the signature tags. */
+ 	deleteSigs(sigh);
+     } else {
+diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
+new file mode 100644
+index 000000000..5346c3bc8
+--- /dev/null
++++ b/sign/rpmsignverity.c
+@@ -0,0 +1,121 @@
++/**
++ * Copyright (C) 2020 Facebook
++ *
++ * Author: Jes Sorensen <jsorensen@fb.com>
++ */
++
++#include "system.h"
++
++#include <rpm/rpmlib.h>		/* RPMSIGTAG & related */
++#include <rpm/rpmlog.h>		/* rpmlog */
++#include <rpm/rpmfi.h>
++#include <rpm/rpmpgp.h>		/* rpmDigestLength */
++#include "lib/header.h"		/* HEADERGET_MINMEM */
++#include "lib/header_internal.h"
++#include "lib/rpmtypes.h"	/* rpmRC */
++#include <libfsverity.h>
++#include "rpmio/rpmio_internal.h"
++#include "lib/rpmvs.h"
++
++#include "sign/rpmsignverity.h"
++
++#define MAX_SIGNATURE_LENGTH 1024
++
++static int rpmVerityRead(void *opaque, void *buf, size_t size)
++{
++	int retval;
++	rpmfi fi = (rpmfi)opaque;
++
++	retval = rpmfiArchiveRead(fi, buf, size);
++
++	if (retval > 0)
++		retval = 0;
++	return retval;
++}
++
++rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
++		    char *keypass, char *cert)
++{
++    int rc, status;
++    FD_t gzdi;
++    rpmfiles files = NULL;
++    rpmfi fi = NULL;
++    rpmts ts = rpmtsCreate();
++    struct libfsverity_digest *digest = NULL;
++    struct libfsverity_merkle_tree_params params;
++    struct libfsverity_signature_params sig_params;
++    rpm_loff_t file_size;
++    off_t offset = Ftell(fd);
++    const char *compr;
++    char *rpmio_flags = NULL;
++    char *digest_hex;
++    uint8_t *sig;
++    size_t sig_size;
++
++    Fseek(fd, 0, SEEK_SET);
++    rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
++		    RPMVSF_NOHDRCHK);
++    rc = rpmReadPackageFile(ts, fd, "fsverity", &h);
++    if (rc != RPMRC_OK) {
++	rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),
++	       __func__, rc);
++	goto out;
++    }
++
++    rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key);
++    rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert);
++
++    compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
++    rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
++
++    gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);
++    free(rpmio_flags);
++
++    files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
++    fi = rpmfiNewArchiveReader(gzdi, files,
++			       RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS);
++
++    while (rpmfiNext(fi) >= 0) {
++	if (!S_ISREG(rpmfiFMode(fi)))
++	    continue;
++	file_size = rpmfiFSize(fi);
++	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"),
++	       rpmfiFN(fi), file_size);
++
++	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
++	params.version = 1;
++	params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
++	params.block_size = sysconf(_SC_PAGESIZE);
++	params.salt_size = 0 /* salt_size */;
++	params.salt = NULL /* salt */;
++	params.file_size = file_size;
++	status = libfsverity_compute_digest(fi, rpmVerityRead,
++					    &params, &digest);
++	if (!status) {
++	    digest_hex = pgpHexStr(digest->digest, digest->digest_size);
++	    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
++		   digest->digest_size, digest_hex);
++	    free(digest_hex);
++	}
++	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
++	sig_params.keyfile = key;
++	sig_params.certfile = cert;
++	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {
++	    rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));
++	    rc = RPMRC_FAIL;
++	    goto out;
++	}
++	rpmlog(RPMLOG_DEBUG, _("digest signing success\n"));
++
++	free(digest);
++	free(sig);
++    }
++
++out:
++    Fseek(fd, offset, SEEK_SET);
++
++    rpmfilesFree(files);
++    rpmfiFree(fi);
++    rpmtsFree(ts);
++    return rc;
++}
+diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
+new file mode 100644
+index 000000000..f3ad3bb18
+--- /dev/null
++++ b/sign/rpmsignverity.h
+@@ -0,0 +1,29 @@
++#ifndef H_RPMSIGNVERITY
++#define H_RPMSIGNVERITY
++
++#include <rpm/rpmtypes.h>
++#include <rpm/rpmutil.h>
++
++#ifdef __cplusplus
++extern "C" {
++#endif
++
++/**
++ * Sign file digests in header into signature header
++ * @param fd		file descriptor of RPM
++ * @param sigh		package signature header
++ * @param h		package header
++ * @param key		signing key
++ * @param keypass	signing key password
++ * @param cert		signing cert
++ * @return		RPMRC_OK on success
++ */
++RPM_GNUC_INTERNAL
++rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
++		    char *keypass, char *cert);
++
++#ifdef _cplusplus
++}
++#endif
++
++#endif /* H_RPMSIGNVERITY */
+-- 
+2.27.0
+
diff --git a/SOURCES/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch b/SOURCES/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch
new file mode 100644
index 0000000..b099eaf
--- /dev/null
+++ b/SOURCES/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch
@@ -0,0 +1,95 @@
+From a7e81a1b18c9e9d124a4ea917c8015af62584abb Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Thu, 28 May 2020 17:48:23 -0400
+Subject: [PATCH 20/33] Introduce base2bin() - a helper to convert tag array of
+ base64 strings
+
+This will convert a tag of base64 strings to a binary array, similar
+to how hex2bin() works. It supports variable sized strings, and will
+determine the maximum string length and build the output array based
+on that.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ lib/rpmfi.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 58 insertions(+)
+
+diff --git a/lib/rpmfi.c b/lib/rpmfi.c
+index 689ead2c5..8c69d3e40 100644
+--- a/lib/rpmfi.c
++++ b/lib/rpmfi.c
+@@ -19,6 +19,7 @@
+ #include "lib/fsm.h"	/* rpmpsm stuff for now */
+ #include "lib/rpmug.h"
+ #include "rpmio/rpmio_internal.h"       /* fdInit/FiniDigest */
++#include "rpmio/rpmbase64.h"
+ 
+ #include "debug.h"
+ 
+@@ -1520,6 +1521,63 @@ static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len)
+     return bin;
+ }
+ 
++/*
++ * Convert a tag of base64 strings to binary presentation.
++ * This handles variable length strings by finding the longest string
++ * before building the output array. Dummy strings in the tag should be
++ * added as '\0'
++ */
++static uint8_t *base2bin(Header h, rpmTagVal tag, rpm_count_t num, int *len)
++{
++    struct rpmtd_s td;
++    uint8_t *bin = NULL, *t = NULL;
++    size_t maxlen = 0;
++    int status, i= 0;
++    void **arr = xmalloc(num * sizeof(void *));
++    size_t *lengths = xcalloc(num, sizeof(size_t));
++    const char *s;
++
++    if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) != num)
++	goto out;
++
++    while ((s = rpmtdNextString(&td))) {
++	/* Insert a dummy entry for empty strings */
++	if (*s == '\0') {
++	    arr[i++] = NULL;
++	    continue;
++	}
++	status = rpmBase64Decode(s, &arr[i], &lengths[i]);
++	if (lengths[i] > maxlen)
++	    maxlen = lengths[i];
++	if (status) {
++	    rpmlog(RPMLOG_DEBUG, _("%s: base64 decode failed, len %li\n"),
++		   __func__, lengths[i]);
++	    goto out;
++	}
++	i++;
++    }
++
++    if (maxlen) {
++	rpmlog(RPMLOG_DEBUG, _("%s: base64 decode success, len %li\n"),
++	       __func__, maxlen);
++
++	t = bin = xcalloc(num, maxlen);
++
++	for (i = 0; i < num; i++) {
++	    memcpy(t, arr[i], lengths[i]);
++	    free(arr[i]);
++	    t += maxlen;
++	}
++	*len = maxlen;
++    }
++ out:
++    free(arr);
++    free(lengths);
++    rpmtdFreeData(&td);
++
++    return bin;
++}
++
+ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
+ {
+     headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ? 
+-- 
+2.27.0
+
diff --git a/SOURCES/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch b/SOURCES/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch
new file mode 100644
index 0000000..6caee37
--- /dev/null
+++ b/SOURCES/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch
@@ -0,0 +1,210 @@
+From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Thu, 9 Apr 2020 12:58:17 -0400
+Subject: [PATCH 21/33] rpmsignverity: Add verity signature headers to the
+ package
+
+This adds the array of verity signatures, and a signature length
+header. We use 4K block for the Merkle tree, and rely on the kernel
+doing the right thing.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ lib/rpmtag.h         |   6 ++-
+ sign/rpmsignverity.c | 112 +++++++++++++++++++++++++++++--------------
+ sign/rpmsignverity.h |   7 +++
+ 3 files changed, 87 insertions(+), 38 deletions(-)
+
+diff --git a/lib/rpmtag.h b/lib/rpmtag.h
+index 40ff5fa5d..478457ecb 100644
+--- a/lib/rpmtag.h
++++ b/lib/rpmtag.h
+@@ -67,6 +67,7 @@ typedef enum rpmTag_e {
+     RPMTAG_SHA256HEADER		= RPMTAG_SIG_BASE+17,	/* s */
+     /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */
+     /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */
++    RPMTAG_VERITYSIGNATURES	= RPMTAG_SIG_BASE+20,	/* s[] */
+ 
+     RPMTAG_NAME  		= 1000,	/* s */
+ #define	RPMTAG_N	RPMTAG_NAME	/* s */
+@@ -427,8 +428,9 @@ typedef enum rpmSigTag_e {
+     RPMSIGTAG_LONGSIZE	= RPMTAG_LONGSIGSIZE,	/*!< internal Header+Payload size (64bit) in bytes. */
+     RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */
+     RPMSIGTAG_SHA256	= RPMTAG_SHA256HEADER,
+-    RPMSIGTAG_FILESIGNATURES           = RPMTAG_SIG_BASE + 18,
+-    RPMSIGTAG_FILESIGNATURELENGTH      = RPMTAG_SIG_BASE + 19,
++    RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 18,
++    RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 19,
++    RPMSIGTAG_VERITYSIGNATURES		= RPMTAG_VERITYSIGNATURES,
+ } rpmSigTag;
+ 
+ 
+diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
+index 5346c3bc8..a9818bd08 100644
+--- a/sign/rpmsignverity.c
++++ b/sign/rpmsignverity.c
+@@ -33,23 +33,66 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size)
+ 	return retval;
+ }
+ 
++static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
++			       char *keypass, char *cert)
++{
++    struct libfsverity_merkle_tree_params params;
++    struct libfsverity_signature_params sig_params;
++    struct libfsverity_digest *digest = NULL;
++    rpm_loff_t file_size;
++    char *digest_hex, *sig_hex = NULL;
++    uint8_t *sig;
++    int status;
++
++    file_size = rpmfiFSize(fi);
++
++    memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
++    params.version = 1;
++    params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
++    params.block_size = RPM_FSVERITY_BLKSZ;
++    params.salt_size = 0 /* salt_size */;
++    params.salt = NULL /* salt */;
++    params.file_size = file_size;
++    status = libfsverity_compute_digest(fi, rpmVerityRead, &params, &digest);
++    if (status) {
++	rpmlog(RPMLOG_DEBUG, _("failed to compute digest\n"));
++	goto out;
++    }
++
++    digest_hex = pgpHexStr(digest->digest, digest->digest_size);
++    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
++	   digest->digest_size, digest_hex);
++    free(digest_hex);
++
++    memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
++    sig_params.keyfile = key;
++    sig_params.certfile = cert;
++    if (libfsverity_sign_digest(digest, &sig_params, &sig, sig_size)) {
++	rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));
++	goto out;
++    }
++
++    sig_hex = pgpHexStr(sig, *sig_size + 1);
++ out:
++    free(digest);
++    free(sig);
++    return sig_hex;
++}
++
+ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+ 		    char *keypass, char *cert)
+ {
+-    int rc, status;
++    int rc;
+     FD_t gzdi;
+     rpmfiles files = NULL;
+     rpmfi fi = NULL;
+     rpmts ts = rpmtsCreate();
+-    struct libfsverity_digest *digest = NULL;
+-    struct libfsverity_merkle_tree_params params;
+-    struct libfsverity_signature_params sig_params;
++    struct rpmtd_s td;
+     rpm_loff_t file_size;
+     off_t offset = Ftell(fd);
+     const char *compr;
+     char *rpmio_flags = NULL;
+-    char *digest_hex;
+-    uint8_t *sig;
++    char *sig_hex;
+     size_t sig_size;
+ 
+     Fseek(fd, 0, SEEK_SET);
+@@ -75,43 +118,40 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+     fi = rpmfiNewArchiveReader(gzdi, files,
+ 			       RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS);
+ 
++    /*
++     * Should this be sigh from the cloned fd or the sigh we received?
++     */
++    headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
++
++    rpmtdReset(&td);
++    td.tag = RPMSIGTAG_VERITYSIGNATURES;
++    td.type = RPM_STRING_ARRAY_TYPE;
++    td.count = 1;
++
+     while (rpmfiNext(fi) >= 0) {
+-	if (!S_ISREG(rpmfiFMode(fi)))
+-	    continue;
+ 	file_size = rpmfiFSize(fi);
+-	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"),
+-	       rpmfiFN(fi), file_size);
+-
+-	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
+-	params.version = 1;
+-	params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
+-	params.block_size = sysconf(_SC_PAGESIZE);
+-	params.salt_size = 0 /* salt_size */;
+-	params.salt = NULL /* salt */;
+-	params.file_size = file_size;
+-	status = libfsverity_compute_digest(fi, rpmVerityRead,
+-					    &params, &digest);
+-	if (!status) {
+-	    digest_hex = pgpHexStr(digest->digest, digest->digest_size);
+-	    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
+-		   digest->digest_size, digest_hex);
+-	    free(digest_hex);
+-	}
+-	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
+-	sig_params.keyfile = key;
+-	sig_params.certfile = cert;
+-	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {
+-	    rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));
++
++	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),
++	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));
++
++	sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
++	td.data = &sig_hex;
++	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);
++#if 0
++	rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex);
++#endif
++	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {
++	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
+ 	    rc = RPMRC_FAIL;
+ 	    goto out;
+ 	}
+-	rpmlog(RPMLOG_DEBUG, _("digest signing success\n"));
+-
+-	free(digest);
+-	free(sig);
++	free(sig_hex);
+     }
+ 
+-out:
++    rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));
++
++    rc = RPMRC_OK;
++ out:
+     Fseek(fd, offset, SEEK_SET);
+ 
+     rpmfilesFree(files);
+diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
+index f3ad3bb18..69bbaf7f7 100644
+--- a/sign/rpmsignverity.h
++++ b/sign/rpmsignverity.h
+@@ -8,6 +8,13 @@
+ extern "C" {
+ #endif
+ 
++/*
++ * Block size used to generate the Merkle tree for fsverity. For now
++ * we only support 4K blocks, if we ever decide to support different
++ * block sizes, we will need a tag to indicate this.
++ */
++#define RPM_FSVERITY_BLKSZ	4096
++
+ /**
+  * Sign file digests in header into signature header
+  * @param fd		file descriptor of RPM
+-- 
+2.27.0
+
diff --git a/SOURCES/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch b/SOURCES/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch
new file mode 100644
index 0000000..dba0ca6
--- /dev/null
+++ b/SOURCES/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch
@@ -0,0 +1,162 @@
+From 22420d9ee652a25357727b00585dc3cfe78b2a80 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Mon, 13 Apr 2020 18:14:15 -0400
+Subject: [PATCH 22/33] rpmSignVerity: Generate signatures for files not
+ present in archive
+
+This generates signatures for all files in the archive, then picks up
+ghost files from the header metadata and generates signatures for them
+as well. It finally submits them to RPMTAG_VERITYSIGNATURES in header
+file order as we cannot rely on archive order and header order being
+the same.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ lib/package.c        |  1 +
+ sign/rpmsignverity.c | 55 ++++++++++++++++++++++++++++++++++----------
+ 2 files changed, 44 insertions(+), 12 deletions(-)
+
+diff --git a/lib/package.c b/lib/package.c
+index b7d996a12..c6108f686 100644
+--- a/lib/package.c
++++ b/lib/package.c
+@@ -45,6 +45,7 @@ struct taglate_s {
+     { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 },
+     { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },
+     { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },
++    { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 },
+     { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },
+     { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },
+     { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },
+diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
+index a9818bd08..3bb23a18d 100644
+--- a/sign/rpmsignverity.c
++++ b/sign/rpmsignverity.c
+@@ -41,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+     struct libfsverity_digest *digest = NULL;
+     rpm_loff_t file_size;
+     char *digest_hex, *sig_hex = NULL;
+-    uint8_t *sig;
++    uint8_t *sig = NULL;
+     int status;
+ 
+     file_size = rpmfiFSize(fi);
+@@ -72,7 +72,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+ 	goto out;
+     }
+ 
+-    sig_hex = pgpHexStr(sig, *sig_size + 1);
++    sig_hex = pgpHexStr(sig, *sig_size);
+  out:
+     free(digest);
+     free(sig);
+@@ -86,6 +86,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+     FD_t gzdi;
+     rpmfiles files = NULL;
+     rpmfi fi = NULL;
++    rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
+     rpmts ts = rpmtsCreate();
+     struct rpmtd_s td;
+     rpm_loff_t file_size;
+@@ -93,11 +94,14 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+     const char *compr;
+     char *rpmio_flags = NULL;
+     char *sig_hex;
++    char **signatures = NULL;
+     size_t sig_size;
++    int nr_files, idx;
+ 
+     Fseek(fd, 0, SEEK_SET);
+     rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
+ 		    RPMVSF_NOHDRCHK);
++
+     rc = rpmReadPackageFile(ts, fd, "fsverity", &h);
+     if (rc != RPMRC_OK) {
+ 	rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),
+@@ -113,6 +117,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+ 
+     gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);
+     free(rpmio_flags);
++    if (!gzdi)
++	rpmlog(RPMLOG_DEBUG, _("Fdopen() failed\n"));
+ 
+     files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
+     fi = rpmfiNewArchiveReader(gzdi, files,
+@@ -123,39 +129,64 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+      */
+     headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
+ 
+-    rpmtdReset(&td);
+-    td.tag = RPMSIGTAG_VERITYSIGNATURES;
+-    td.type = RPM_STRING_ARRAY_TYPE;
+-    td.count = 1;
++    /*
++     * The payload doesn't include special files, like ghost files, and
++     * we cannot rely on the file order in the payload to match that of
++     * the header. Instead we allocate an array of pointers and populate
++     * it as we go along. Then walk the header fi and account for the
++     * special files. Last we walk the array and populate the header.
++     */
++    nr_files = rpmfiFC(hfi);
++    signatures = xcalloc(nr_files, sizeof(char *));
++
++    rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),
++	   nr_files, rpmfiFC(fi));
+ 
+     while (rpmfiNext(fi) >= 0) {
+ 	file_size = rpmfiFSize(fi);
++	idx = rpmfiFX(fi);
+ 
+ 	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),
+ 	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));
+ 
+-	sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
++	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
++    }
++
++    while (rpmfiNext(hfi) >= 0) {
++	idx = rpmfiFX(hfi);
++	if (signatures[idx])
++	    continue;
++	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert);
++    }
++
++    rpmtdReset(&td);
++    td.tag = RPMSIGTAG_VERITYSIGNATURES;
++    td.type = RPM_STRING_ARRAY_TYPE;
++    td.count = 1;
++    for (idx = 0; idx < nr_files; idx++) {
++	sig_hex = signatures[idx];
+ 	td.data = &sig_hex;
+-	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);
+-#if 0
+-	rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex);
+-#endif
+ 	if (!headerPut(sigh, &td, HEADERPUT_APPEND)) {
+ 	    rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
+ 	    rc = RPMRC_FAIL;
+ 	    goto out;
+ 	}
+-	free(sig_hex);
++	rpmlog(RPMLOG_DEBUG, _("signature: %s\n"), signatures[idx]);
++	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);
++	free(signatures[idx]);
++	signatures[idx] = NULL;
+     }
+ 
+     rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));
+ 
+     rc = RPMRC_OK;
+  out:
++    signatures = _free(signatures);
+     Fseek(fd, offset, SEEK_SET);
+ 
+     rpmfilesFree(files);
+     rpmfiFree(fi);
++    rpmfiFree(hfi);
+     rpmtsFree(ts);
+     return rc;
+ }
+-- 
+2.27.0
+
diff --git a/SOURCES/0023-Process-verity-tag-on-package-read.patch b/SOURCES/0023-Process-verity-tag-on-package-read.patch
new file mode 100644
index 0000000..4f682c7
--- /dev/null
+++ b/SOURCES/0023-Process-verity-tag-on-package-read.patch
@@ -0,0 +1,189 @@
+From 34e751ccee43f799dd32f6b9c64020106dba9fac Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Mon, 13 Apr 2020 18:21:36 -0400
+Subject: [PATCH 23/33] Process verity tag on package read
+
+This processes verity signature tags on package read, and provides
+accessor functions to access them.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ lib/rpmfi.c          | 27 +++++++++++++++++++++++++++
+ lib/rpmfi.h          |  8 ++++++++
+ lib/rpmfiles.h       | 10 ++++++++++
+ sign/rpmsignverity.c | 20 ++++++++++++++++----
+ 4 files changed, 61 insertions(+), 4 deletions(-)
+
+diff --git a/lib/rpmfi.c b/lib/rpmfi.c
+index 8c69d3e40..5fdbe02a2 100644
+--- a/lib/rpmfi.c
++++ b/lib/rpmfi.c
+@@ -116,8 +116,10 @@ struct rpmfiles_s {
+ 
+     int digestalgo;		/*!< File digest algorithm */
+     int signaturelength;	/*!< File signature length */
++    int veritysiglength;	/*!< Verity signature length */
+     unsigned char * digests;	/*!< File digests in binary. */
+     unsigned char * signatures; /*!< File signatures in binary. */
++    unsigned char * veritysigs; /*!< Verity signatures in binary. */
+ 
+     struct nlinkHash_s * nlinks;/*!< Files connected by hardlinks */
+     rpm_off_t * replacedSizes;	/*!< (TR_ADDED) */
+@@ -582,6 +584,19 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
+     return signature;
+ }
+ 
++const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)
++{
++    const unsigned char *vsignature = NULL;
++
++    if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) {
++	if (fi->veritysigs != NULL)
++	    vsignature = fi->veritysigs + (fi->veritysiglength * ix);
++	if (len)
++	    *len = fi->veritysiglength;
++    }
++    return vsignature;
++}
++
+ const char * rpmfilesFLink(rpmfiles fi, int ix)
+ {
+     const char * flink = NULL;
+@@ -1268,6 +1283,7 @@ rpmfiles rpmfilesFree(rpmfiles fi)
+ 	fi->flangs = _free(fi->flangs);
+ 	fi->digests = _free(fi->digests);
+ 	fi->signatures = _free(fi->signatures);
++	fi->veritysigs = _free(fi->veritysigs);
+ 	fi->fcaps = _free(fi->fcaps);
+ 
+ 	fi->cdict = _free(fi->cdict);
+@@ -1649,6 +1665,12 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
+ 				 totalfc, fi->signaturelength);
+     }
+ 
++    fi->veritysigs = NULL;
++    if (!(flags & RPMFI_NOVERITYSIGNATURES)) {
++	fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES,
++				  totalfc, &fi->veritysiglength);
++    }
++
+     /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */
+     if (!(flags & RPMFI_NOFILEMTIMES))
+ 	_hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes);
+@@ -1939,6 +1961,11 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)
+     return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);
+ }
+ 
++const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len)
++{
++    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len);
++}
++
+ uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
+ {
+     return rpmfilesFDepends(fi->files,  fi ? fi->i : -1, fddictp);
+diff --git a/lib/rpmfi.h b/lib/rpmfi.h
+index 6ef70cd28..fcb9d3acd 100644
+--- a/lib/rpmfi.h
++++ b/lib/rpmfi.h
+@@ -190,6 +190,14 @@ char * rpmfiFDigestHex(rpmfi fi, int *algo);
+  */
+ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen);
+ 
++/** \ingroup rpmfi
++ * Return current verity (binary) signature of file info set iterator.
++ * @param fi		file info set iterator
++ * @retval siglen	signature length (pass NULL to ignore)
++ * @return		current verity signature, NULL on invalid
++ */
++const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen);
++
+ /** \ingroup rpmfi
+  * Return current file linkto (i.e. symlink(2) target) from file info set iterator.
+  * @param fi		file info set iterator
+diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
+index daf572cf4..81b3d01a1 100644
+--- a/lib/rpmfiles.h
++++ b/lib/rpmfiles.h
+@@ -119,6 +119,7 @@ enum rpmfiFlags_e {
+     RPMFI_NOFILEVERIFYFLAGS	= (1 << 16),
+     RPMFI_NOFILEFLAGS		= (1 << 17),
+     RPMFI_NOFILESIGNATURES	= (1 << 18),
++    RPMFI_NOVERITYSIGNATURES	= (1 << 19),
+ };
+ 
+ typedef rpmFlags rpmfiFlags;
+@@ -442,6 +443,15 @@ const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *le
+  */
+ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len);
+ 
++/** \ingroup rpmfiles
++ * Return file verity signature (binary)
++ * @param fi            file info set
++ * @param ix            file index
++ * @retval len       signature length (pass NULL to ignore)
++ * @return              verity signature, NULL on invalid
++ */
++const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len);
++
+ /** \ingroup rpmfiles
+  * Return file rdev from file info set.
+  * @param fi		file info set
+diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
+index 3bb23a18d..177561957 100644
+--- a/sign/rpmsignverity.c
++++ b/sign/rpmsignverity.c
+@@ -15,6 +15,7 @@
+ #include "lib/rpmtypes.h"	/* rpmRC */
+ #include <libfsverity.h>
+ #include "rpmio/rpmio_internal.h"
++#include "rpmio/rpmbase64.h"
+ #include "lib/rpmvs.h"
+ 
+ #include "sign/rpmsignverity.h"
+@@ -40,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+     struct libfsverity_signature_params sig_params;
+     struct libfsverity_digest *digest = NULL;
+     rpm_loff_t file_size;
+-    char *digest_hex, *sig_hex = NULL;
++    char *digest_hex, *digest_base64, *sig_base64 = NULL, *sig_hex = NULL;
+     uint8_t *sig = NULL;
+     int status;
+ 
+@@ -60,8 +61,14 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+     }
+ 
+     digest_hex = pgpHexStr(digest->digest, digest->digest_size);
+-    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
+-	   digest->digest_size, digest_hex);
++    digest_base64 = rpmBase64Encode(digest->digest, digest->digest_size, -1);
++    rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest(%i): %s, idx %i\n"),
++	   file_size, rpmfiFN(fi), digest->digest_size, digest_hex,
++	   rpmfiFX(fi));
++    rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest sz (%i): base64 sz (%li), %s, idx %i\n"),
++	   file_size, rpmfiFN(fi), digest->digest_size, strlen(digest_base64),
++	   digest_base64, rpmfiFX(fi));
++
+     free(digest_hex);
+ 
+     memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
+@@ -73,10 +80,15 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+     }
+ 
+     sig_hex = pgpHexStr(sig, *sig_size);
++    sig_base64 = rpmBase64Encode(sig, *sig_size, -1);
++    rpmlog(RPMLOG_DEBUG, _("%s: sig_size(%li), base64_size(%li), idx %i: signature:\n%s\n"),
++	   rpmfiFN(fi), *sig_size, strlen(sig_base64), rpmfiFX(fi), sig_hex);
+  out:
++    free(sig_hex);
++
+     free(digest);
+     free(sig);
+-    return sig_hex;
++    return sig_base64;
+ }
+ 
+ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+-- 
+2.27.0
+
diff --git a/SOURCES/0024-Generate-a-zero-length-signature-for-symlinks.patch b/SOURCES/0024-Generate-a-zero-length-signature-for-symlinks.patch
new file mode 100644
index 0000000..2fc3f5a
--- /dev/null
+++ b/SOURCES/0024-Generate-a-zero-length-signature-for-symlinks.patch
@@ -0,0 +1,33 @@
+From 202359dc598f2162175e3a8552c9b338d27b8989 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Tue, 14 Apr 2020 10:33:32 -0400
+Subject: [PATCH 24/33] Generate a zero-length signature for symlinks
+
+The fsverity utility follows the symlink when generating a signature.
+Since we don't want to sign the same file twice, we need to skip these
+links, and instead just generate a dummy zero-length signature here.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ sign/rpmsignverity.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
+index 177561957..2c7d21620 100644
+--- a/sign/rpmsignverity.c
++++ b/sign/rpmsignverity.c
+@@ -45,7 +45,10 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+     uint8_t *sig = NULL;
+     int status;
+ 
+-    file_size = rpmfiFSize(fi);
++    if (S_ISLNK(rpmfiFMode(fi)))
++	file_size = 0;
++    else
++	file_size = rpmfiFSize(fi);
+ 
+     memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
+     params.version = 1;
+-- 
+2.27.0
+
diff --git a/SOURCES/0025-rpmsignverity.c-Clean-up-debug-logging.patch b/SOURCES/0025-rpmsignverity.c-Clean-up-debug-logging.patch
new file mode 100644
index 0000000..bb6e4f3
--- /dev/null
+++ b/SOURCES/0025-rpmsignverity.c-Clean-up-debug-logging.patch
@@ -0,0 +1,40 @@
+From 7e50b3f4b2ebb963d1080a0a1469517ef81f780c Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Tue, 14 Apr 2020 12:08:09 -0400
+Subject: [PATCH 25/33] rpmsignverity.c: Clean up debug logging
+
+Put most logging in one place and avoid printing the same info twice.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ sign/rpmsignverity.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
+index 2c7d21620..445e1197c 100644
+--- a/sign/rpmsignverity.c
++++ b/sign/rpmsignverity.c
+@@ -104,7 +104,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+     rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
+     rpmts ts = rpmtsCreate();
+     struct rpmtd_s td;
+-    rpm_loff_t file_size;
+     off_t offset = Ftell(fd);
+     const char *compr;
+     char *rpmio_flags = NULL;
+@@ -158,12 +157,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+ 	   nr_files, rpmfiFC(fi));
+ 
+     while (rpmfiNext(fi) >= 0) {
+-	file_size = rpmfiFSize(fi);
+ 	idx = rpmfiFX(fi);
+ 
+-	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"),
+-	       rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi));
+-
+ 	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
+     }
+ 
+-- 
+2.27.0
+
diff --git a/SOURCES/0026-fsverity-add-tag-for-fsverity-algorithm.patch b/SOURCES/0026-fsverity-add-tag-for-fsverity-algorithm.patch
new file mode 100644
index 0000000..d1c12c9
--- /dev/null
+++ b/SOURCES/0026-fsverity-add-tag-for-fsverity-algorithm.patch
@@ -0,0 +1,161 @@
+From e339fdbbd0b81dc1fcdc2032e861b8a5fa6e062d Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Mon, 20 Apr 2020 13:40:26 -0400
+Subject: [PATCH 26/33] fsverity - add tag for fsverity algorithm
+
+The default algorith is SHA256, but fsverity allows for other
+algorithms, so add a tag to handle this.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ lib/package.c        |  1 +
+ lib/rpmfi.c          |  2 ++
+ lib/rpmtag.h         |  2 ++
+ sign/rpmsignverity.c | 32 ++++++++++++++++++++++++++++----
+ 4 files changed, 33 insertions(+), 4 deletions(-)
+
+diff --git a/lib/package.c b/lib/package.c
+index c6108f686..3c761d365 100644
+--- a/lib/package.c
++++ b/lib/package.c
+@@ -46,6 +46,7 @@ struct taglate_s {
+     { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },
+     { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },
+     { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 },
++    { RPMSIGTAG_VERITYSIGNATUREALGO, RPMTAG_VERITYSIGNATUREALGO, 1, 0 },
+     { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },
+     { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },
+     { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },
+diff --git a/lib/rpmfi.c b/lib/rpmfi.c
+index 5fdbe02a2..70f05f509 100644
+--- a/lib/rpmfi.c
++++ b/lib/rpmfi.c
+@@ -117,6 +117,7 @@ struct rpmfiles_s {
+     int digestalgo;		/*!< File digest algorithm */
+     int signaturelength;	/*!< File signature length */
+     int veritysiglength;	/*!< Verity signature length */
++    uint16_t verityalgo;	/*!< Verity algorithm */
+     unsigned char * digests;	/*!< File digests in binary. */
+     unsigned char * signatures; /*!< File signatures in binary. */
+     unsigned char * veritysigs; /*!< Verity signatures in binary. */
+@@ -1667,6 +1668,7 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags)
+ 
+     fi->veritysigs = NULL;
+     if (!(flags & RPMFI_NOVERITYSIGNATURES)) {
++	fi->verityalgo = headerGetNumber(h, RPMTAG_VERITYSIGNATUREALGO);
+ 	fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES,
+ 				  totalfc, &fi->veritysiglength);
+     }
+diff --git a/lib/rpmtag.h b/lib/rpmtag.h
+index 478457ecb..8d1efcc79 100644
+--- a/lib/rpmtag.h
++++ b/lib/rpmtag.h
+@@ -68,6 +68,7 @@ typedef enum rpmTag_e {
+     /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */
+     /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */
+     RPMTAG_VERITYSIGNATURES	= RPMTAG_SIG_BASE+20,	/* s[] */
++    RPMTAG_VERITYSIGNATUREALGO	= RPMTAG_SIG_BASE+21,	/* i */
+ 
+     RPMTAG_NAME  		= 1000,	/* s */
+ #define	RPMTAG_N	RPMTAG_NAME	/* s */
+@@ -431,6 +432,7 @@ typedef enum rpmSigTag_e {
+     RPMSIGTAG_FILESIGNATURES		= RPMTAG_SIG_BASE + 18,
+     RPMSIGTAG_FILESIGNATURELENGTH	= RPMTAG_SIG_BASE + 19,
+     RPMSIGTAG_VERITYSIGNATURES		= RPMTAG_VERITYSIGNATURES,
++    RPMSIGTAG_VERITYSIGNATUREALGO	= RPMTAG_VERITYSIGNATUREALGO,
+ } rpmSigTag;
+ 
+ 
+diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
+index 445e1197c..55096e732 100644
+--- a/sign/rpmsignverity.c
++++ b/sign/rpmsignverity.c
+@@ -35,7 +35,7 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size)
+ }
+ 
+ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+-			       char *keypass, char *cert)
++			       char *keypass, char *cert, uint16_t algo)
+ {
+     struct libfsverity_merkle_tree_params params;
+     struct libfsverity_signature_params sig_params;
+@@ -52,7 +52,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+ 
+     memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
+     params.version = 1;
+-    params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
++    params.hash_algorithm = algo;
+     params.block_size = RPM_FSVERITY_BLKSZ;
+     params.salt_size = 0 /* salt_size */;
+     params.salt = NULL /* salt */;
+@@ -111,6 +111,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+     char **signatures = NULL;
+     size_t sig_size;
+     int nr_files, idx;
++    uint16_t algo;
++    uint32_t algo32;
+ 
+     Fseek(fd, 0, SEEK_SET);
+     rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
+@@ -142,6 +144,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+      * Should this be sigh from the cloned fd or the sigh we received?
+      */
+     headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
++    headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO);
+ 
+     /*
+      * The payload doesn't include special files, like ghost files, and
+@@ -153,20 +156,24 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+     nr_files = rpmfiFC(hfi);
+     signatures = xcalloc(nr_files, sizeof(char *));
+ 
++    algo = FS_VERITY_HASH_ALG_SHA256;
++
+     rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),
+ 	   nr_files, rpmfiFC(fi));
+ 
+     while (rpmfiNext(fi) >= 0) {
+ 	idx = rpmfiFX(fi);
+ 
+-	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
++	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert,
++					    algo);
+     }
+ 
+     while (rpmfiNext(hfi) >= 0) {
+ 	idx = rpmfiFX(hfi);
+ 	if (signatures[idx])
+ 	    continue;
+-	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert);
++	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert,
++					    algo);
+     }
+ 
+     rpmtdReset(&td);
+@@ -187,6 +194,23 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+ 	signatures[idx] = NULL;
+     }
+ 
++    if (sig_size == 0) {
++	rpmlog(RPMLOG_ERR, _("Zero length fsverity signature\n"));
++	rc = RPMRC_FAIL;
++	goto out;
++    }
++
++    rpmtdReset(&td);
++
++    /* RPM doesn't like new 16 bit types, so use a 32 bit tag */
++    algo32 = algo;
++    rpmtdReset(&td);
++    td.tag = RPMSIGTAG_VERITYSIGNATUREALGO;
++    td.type = RPM_INT32_TYPE;
++    td.data = &algo32;
++    td.count = 1;
++    headerPut(sigh, &td, HEADERPUT_DEFAULT);
++
+     rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));
+ 
+     rc = RPMRC_OK;
+-- 
+2.27.0
+
diff --git a/SOURCES/0027-plugins-fsverity-Install-fsverity-signatures.patch b/SOURCES/0027-plugins-fsverity-Install-fsverity-signatures.patch
new file mode 100644
index 0000000..aa78311
--- /dev/null
+++ b/SOURCES/0027-plugins-fsverity-Install-fsverity-signatures.patch
@@ -0,0 +1,281 @@
+From f1a92e02faa2715777286acd07b8d0f465c5df37 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Mon, 20 Apr 2020 11:11:25 -0400
+Subject: [PATCH 27/33] plugins/fsverity: Install fsverity signatures
+
+This plugin installs fsverity signatures for regular files, when a signature
+is found in the RPM. It tries to enable them unconditionally, but fails
+gracefully if fsverity isn't supported or enabled.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ configure.ac        |  29 ++++++++
+ macros.in           |   4 +
+ plugins/Makefile.am |   7 ++
+ plugins/fsverity.c  | 177 ++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 217 insertions(+)
+ create mode 100644 plugins/fsverity.c
+
+diff --git a/configure.ac b/configure.ac
+index cc7144440..7d3c31831 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1049,6 +1049,35 @@ AS_IF([test "$enable_plugins" != no],[
+ ])
+ AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes])
+ 
++AS_IF([test "$enable_plugins" != no],[
++AC_CHECK_HEADERS([linux/fsverity.h],[FSVERITY_IOCTL="yes"])
++])
++AM_CONDITIONAL(FSVERITY_IOCTL,[test "x$FSVERITY_IOCTL" = xyes])
++
++#=================
++# Check for audit library.
++AC_ARG_WITH(audit,
++AS_HELP_STRING([--with-audit],[Linux audit plugin]),
++with_audit=$withval,
++with_audit=auto)
++
++WITH_AUDIT_LIB=
++AS_IF([test "$enable_plugins" != no],[
++  AS_IF([test "x$with_audit" != xno],[
++    AC_SEARCH_LIBS([audit_open],[audit],[
++      WITH_AUDIT_LIB="$ac_res"
++      AC_DEFINE(WITH_AUDIT, 1, [libaudit support])
++      with_audit=yes
++    ],[
++      if test "x$with_audit" != xauto; then
++        AC_MSG_ERROR([missing audit library])
++      fi
++    ])
++  ])
++])
++AC_SUBST(WITH_AUDIT_LIB)
++AM_CONDITIONAL(AUDIT,[test "$with_audit" = yes])
++
+ user_with_uid0=$(awk -F: '$3==0 {print $1;exit}' /etc/passwd)
+ group_with_gid0=$(awk -F: '$3==0 {print $1;exit}' /etc/group)
+ AC_DEFINE_UNQUOTED([UID_0_USER],["$user_with_uid0"],[Get the user name having userid 0])
+diff --git a/macros.in b/macros.in
+index fe8862903..3c722146b 100644
+--- a/macros.in
++++ b/macros.in
+@@ -767,6 +767,9 @@ package or when debugging this package.\
+ # performance for rotational disks)
+ #%_flush_io	0
+ 
++# Set to 1 to have fsverity signatures written for %config files.
++#%_fsverity_sign_config_files	0
++
+ #
+ # Default output format string for rpm -qa
+ #
+@@ -1185,6 +1188,7 @@ package or when debugging this package.\
+ %__transaction_syslog		%{__plugindir}/syslog.so
+ %__transaction_ima		%{__plugindir}/ima.so
+ %__transaction_fapolicyd	%{__plugindir}/fapolicyd.so
++%__transaction_fsverity		%{__plugindir}/fsverity.so
+ %__transaction_prioreset	%{__plugindir}/prioreset.so
+ 
+ #------------------------------------------------------------------------------
+diff --git a/plugins/Makefile.am b/plugins/Makefile.am
+index cbfb81e19..e51b71f62 100644
+--- a/plugins/Makefile.am
++++ b/plugins/Makefile.am
+@@ -48,3 +48,10 @@ fapolicyd_la_sources = fapolicyd.c
+ fapolicyd_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
+ plugins_LTLIBRARIES += fapolicyd.la
+ endif
++
++if FSVERITY_IOCTL
++fsverity_la_sources = fsverity.c
++fsverity_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
++plugins_LTLIBRARIES += fsverity.la
++endif
++
+diff --git a/plugins/fsverity.c b/plugins/fsverity.c
+new file mode 100644
+index 000000000..15ddcf33e
+--- /dev/null
++++ b/plugins/fsverity.c
+@@ -0,0 +1,177 @@
++/**
++ * Copyright (C) 2020 Facebook
++ *
++ * Author: Jes Sorensen <jsorensen@fb.com>
++ */
++
++#include "system.h"
++
++#include <errno.h>
++#include <fcntl.h>
++#include <sys/ioctl.h>
++#include <linux/fsverity.h>
++
++#include <rpm/rpmfi.h>
++#include <rpm/rpmte.h>
++#include <rpm/rpmfiles.h>
++#include <rpm/rpmtypes.h>
++#include <rpm/rpmlog.h>
++#include <rpmio/rpmstring.h>
++#include <rpmio/rpmmacro.h>
++
++#include "lib/rpmfs.h"
++#include "lib/rpmplugin.h"
++#include "lib/rpmte_internal.h"
++
++#include "sign/rpmsignverity.h"
++
++static int sign_config_files = 0;
++
++/*
++ * This unconditionally tries to apply the fsverity signature to a file,
++ * but fails gracefully if the file system doesn't support it or the
++ * verity feature flag isn't enabled in the file system (ext4).
++ */
++static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
++				       const char *path, const char *dest,
++				       mode_t file_mode, rpmFsmOp op)
++{
++    struct fsverity_enable_arg arg;
++    const unsigned char * signature = NULL;
++    size_t len;
++    int rc = RPMRC_OK;
++    int fd;
++    rpmFileAction action = XFO_ACTION(op);
++    char *buffer;
++
++    /* Ignore skipped files and unowned directories */
++    if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) {
++	rpmlog(RPMLOG_DEBUG, "fsverity skipping early: path %s dest %s\n",
++	       path, dest);
++	goto exit;
++    }
++
++    /*
++     * Do not install signatures for config files unless the
++     * user explicitly asks for it.
++     */
++    if (rpmfiFFlags(fi) & RPMFILE_CONFIG) {
++	if (!(rpmfiFMode(fi) & (S_IXUSR|S_IXGRP|S_IXOTH)) &&
++	    !sign_config_files) {
++	    rpmlog(RPMLOG_DEBUG, "fsverity skipping: path %s dest %s\n",
++		   path, dest);
++
++	    goto exit;
++	}
++    }
++
++    /*
++     * Right now fsverity doesn't deal with symlinks or directories, so do
++     * not try to install signatures for non regular files.
++     */
++    if (!S_ISREG(rpmfiFMode(fi))) {
++	rpmlog(RPMLOG_DEBUG, "fsverity skipping non regular: path %s dest %s\n",
++	       path, dest);
++	goto exit;
++    }
++
++    signature = rpmfiVSignature(fi, &len);
++    if (!signature || !len) {
++	rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n",
++	       path, dest);
++	goto exit;
++    }
++
++    memset(&arg, 0, sizeof(arg));
++    arg.version = 1;
++    arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
++    arg.block_size = RPM_FSVERITY_BLKSZ;
++    arg.sig_ptr = (uintptr_t)signature;
++    arg.sig_size = len;
++
++    buffer = pgpHexStr(signature, arg.sig_size);
++    rpmlog(RPMLOG_DEBUG, "applying signature: %s\n", buffer);
++    free(buffer);
++
++    fd = open(path, O_RDONLY);
++    if (fd < 0) {
++	rpmlog(RPMLOG_ERR, "failed to open path %s\n", path);
++	goto exit;
++    }
++
++    /*
++     * Enable fsverity on the file.
++     * fsverity not supported by file system (ENOTTY) and fsverity not
++     * enabled on file system are expected and not considered
++     * errors. Every other non-zero error code will result in the
++     * installation failing.
++     */
++    if (ioctl(fd, FS_IOC_ENABLE_VERITY, &arg) != 0) {
++	switch(errno) {
++	case EBADMSG:
++	    rpmlog(RPMLOG_DEBUG, "invalid or malformed fsverity signature for %s\n", path);
++	    rc = RPMRC_FAIL;
++	    break;
++	case EEXIST:
++	    rpmlog(RPMLOG_DEBUG, "fsverity signature already enabled %s\n",
++		   path);
++	    rc = RPMRC_FAIL;
++	    break;
++	case EINVAL:
++	    rpmlog(RPMLOG_DEBUG, "invalid arguments for ioctl %s\n", path);
++	    rc = RPMRC_FAIL;
++	    break;
++	case EKEYREJECTED:
++	    rpmlog(RPMLOG_DEBUG, "signature doesn't match file %s\n", path);
++	    rc = RPMRC_FAIL;
++	    break;
++	case EMSGSIZE:
++	    rpmlog(RPMLOG_DEBUG, "invalid signature size for %s\n", path);
++	    rc = RPMRC_FAIL;
++	    break;
++	case ENOPKG:
++	    rpmlog(RPMLOG_DEBUG, "unsupported signature algoritm (%i) for %s\n",
++		   arg.hash_algorithm, path);
++	    rc = RPMRC_FAIL;
++	    break;
++	case ETXTBSY:
++	    rpmlog(RPMLOG_DEBUG, "file is open by other process %s\n",
++		   path);
++	    rc = RPMRC_FAIL;
++	    break;
++	case ENOTTY:
++	    rpmlog(RPMLOG_DEBUG, "fsverity not supported by file system for %s\n",
++		   path);
++	    break;
++	case EOPNOTSUPP:
++	    rpmlog(RPMLOG_DEBUG, "fsverity not enabled on file system for %s\n",
++		   path);
++	    break;
++	default:
++	    rpmlog(RPMLOG_DEBUG, "failed to enable verity (errno %i) for %s\n",
++		   errno, path);
++	    rc = RPMRC_FAIL;
++	    break;
++	}
++    }
++
++    rpmlog(RPMLOG_DEBUG, "fsverity enabled signature for: path %s dest %s\n",
++	   path, dest);
++    close(fd);
++exit:
++    return rc;
++}
++
++static rpmRC fsverity_init(rpmPlugin plugin, rpmts ts)
++{
++    sign_config_files = rpmExpandNumeric("%{?_fsverity_sign_config_files}");
++
++    rpmlog(RPMLOG_DEBUG, "fsverity_init\n");
++
++    return RPMRC_OK;
++}
++
++struct rpmPluginHooks_s fsverity_hooks = {
++    .init = fsverity_init,
++    .fsm_file_prepare = fsverity_fsm_file_prepare,
++};
+-- 
+2.27.0
+
diff --git a/SOURCES/0028-fsverity-plugin-Use-tag-for-algorithm.patch b/SOURCES/0028-fsverity-plugin-Use-tag-for-algorithm.patch
new file mode 100644
index 0000000..0b9bb41
--- /dev/null
+++ b/SOURCES/0028-fsverity-plugin-Use-tag-for-algorithm.patch
@@ -0,0 +1,116 @@
+From 5a5286ac37cd58779cc0e5b69088d9acc8f40c4e Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Mon, 20 Apr 2020 14:13:51 -0400
+Subject: [PATCH 28/33] fsverity plugin: Use tag for algorithm
+
+This uses the algorithm from the tag, if available. Fallback is SHA256.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ lib/rpmfi.c        | 9 ++++++---
+ lib/rpmfi.h        | 3 ++-
+ lib/rpmfiles.h     | 3 ++-
+ plugins/fsverity.c | 8 ++++++--
+ 4 files changed, 16 insertions(+), 7 deletions(-)
+
+diff --git a/lib/rpmfi.c b/lib/rpmfi.c
+index 70f05f509..3e2b4e676 100644
+--- a/lib/rpmfi.c
++++ b/lib/rpmfi.c
+@@ -585,7 +585,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len)
+     return signature;
+ }
+ 
+-const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)
++const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len,
++					 uint16_t *algo)
+ {
+     const unsigned char *vsignature = NULL;
+ 
+@@ -594,6 +595,8 @@ const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len)
+ 	    vsignature = fi->veritysigs + (fi->veritysiglength * ix);
+ 	if (len)
+ 	    *len = fi->veritysiglength;
++	if (algo)
++	    *algo = fi->verityalgo;
+     }
+     return vsignature;
+ }
+@@ -1963,9 +1966,9 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len)
+     return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len);
+ }
+ 
+-const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len)
++const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len, uint16_t *algo)
+ {
+-    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len);
++    return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len, algo);
+ }
+ 
+ uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp)
+diff --git a/lib/rpmfi.h b/lib/rpmfi.h
+index fcb9d3acd..6fd2747d6 100644
+--- a/lib/rpmfi.h
++++ b/lib/rpmfi.h
+@@ -194,9 +194,10 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen);
+  * Return current verity (binary) signature of file info set iterator.
+  * @param fi		file info set iterator
+  * @retval siglen	signature length (pass NULL to ignore)
++ * @retval algo		fsverity algorithm
+  * @return		current verity signature, NULL on invalid
+  */
+-const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen);
++const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen, uint16_t *algo);
+ 
+ /** \ingroup rpmfi
+  * Return current file linkto (i.e. symlink(2) target) from file info set iterator.
+diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
+index 81b3d01a1..64b33281a 100644
+--- a/lib/rpmfiles.h
++++ b/lib/rpmfiles.h
+@@ -450,7 +450,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len);
+  * @retval len       signature length (pass NULL to ignore)
+  * @return              verity signature, NULL on invalid
+  */
+-const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len);
++const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len,
++					 uint16_t *algo);
+ 
+ /** \ingroup rpmfiles
+  * Return file rdev from file info set.
+diff --git a/plugins/fsverity.c b/plugins/fsverity.c
+index 15ddcf33e..1e7f38b38 100644
+--- a/plugins/fsverity.c
++++ b/plugins/fsverity.c
+@@ -39,6 +39,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
+     struct fsverity_enable_arg arg;
+     const unsigned char * signature = NULL;
+     size_t len;
++    uint16_t algo = 0;
+     int rc = RPMRC_OK;
+     int fd;
+     rpmFileAction action = XFO_ACTION(op);
+@@ -75,7 +76,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
+ 	goto exit;
+     }
+ 
+-    signature = rpmfiVSignature(fi, &len);
++    signature = rpmfiVSignature(fi, &len, &algo);
+     if (!signature || !len) {
+ 	rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n",
+ 	       path, dest);
+@@ -84,7 +85,10 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi,
+ 
+     memset(&arg, 0, sizeof(arg));
+     arg.version = 1;
+-    arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
++    if (algo)
++	arg.hash_algorithm = algo;
++    else
++	arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
+     arg.block_size = RPM_FSVERITY_BLKSZ;
+     arg.sig_ptr = (uintptr_t)signature;
+     arg.sig_size = len;
+-- 
+2.27.0
+
diff --git a/SOURCES/0029-Add-fsverity-tags-to-rpmgeneral.at.patch b/SOURCES/0029-Add-fsverity-tags-to-rpmgeneral.at.patch
new file mode 100644
index 0000000..6575b99
--- /dev/null
+++ b/SOURCES/0029-Add-fsverity-tags-to-rpmgeneral.at.patch
@@ -0,0 +1,28 @@
+From 3132053a066b3dc8aa38b358ecd316ee60fd0f7c Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Mon, 20 Apr 2020 18:52:08 -0400
+Subject: [PATCH 29/33] Add fsverity tags to rpmgeneral.at
+
+Make sure we pass the checks with the new tags in place.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ tests/rpmgeneral.at | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at
+index 45d38698b..8a7dc827f 100644
+--- a/tests/rpmgeneral.at
++++ b/tests/rpmgeneral.at
+@@ -291,6 +291,8 @@ VERBOSE
+ VERIFYSCRIPT
+ VERIFYSCRIPTFLAGS
+ VERIFYSCRIPTPROG
++VERITYSIGNATUREALGO
++VERITYSIGNATURES
+ VERSION
+ XPM
+ ])
+-- 
+2.27.0
+
diff --git a/SOURCES/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch b/SOURCES/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch
new file mode 100644
index 0000000..d872d5e
--- /dev/null
+++ b/SOURCES/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch
@@ -0,0 +1,117 @@
+From 46db4f6827840e828f42424454410b930895d9a7 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Mon, 13 Apr 2020 18:24:31 -0400
+Subject: [PATCH 30/33] Add --delfilesign flag to delete IMA and fsverity file
+ signatures
+
+This allows a user to remove both types of file signatures from the
+package. Previously there was no way to delete IMA signatures, only
+replace them by first removing the package signature and then
+resigning the package and the files.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ rpmsign.c        | 12 ++++++++++++
+ sign/rpmgensig.c | 17 ++++++++++++++++-
+ sign/rpmsign.h   |  9 +++++++++
+ 3 files changed, 37 insertions(+), 1 deletion(-)
+
+diff --git a/rpmsign.c b/rpmsign.c
+index 074dd8b13..e43811e9f 100644
+--- a/rpmsign.c
++++ b/rpmsign.c
+@@ -14,6 +14,7 @@ enum modes {
+     MODE_ADDSIGN = (1 << 0),
+     MODE_RESIGN  = (1 << 1),
+     MODE_DELSIGN = (1 << 2),
++    MODE_DELFILESIGN = (1 << 3),
+ };
+ 
+ static int mode = MODE_NONE;
+@@ -35,6 +36,10 @@ static struct poptOption signOptsTable[] = {
+ 	N_("sign package(s) (identical to --addsign)"), NULL },
+     { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,
+ 	N_("delete package signatures"), NULL },
++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY)
++    { "delfilesign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode,
++      MODE_DELFILESIGN,	N_("delete IMA and fsverity file signatures"), NULL },
++#endif
+     { "rpmv3", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
+ 	&sargs.signflags, RPMSIGN_FLAG_RPMV3,
+ 	N_("create rpm v3 header+payload signatures") },
+@@ -207,6 +212,13 @@ int main(int argc, char *argv[])
+ 		ec++;
+ 	}
+ 	break;
++    case MODE_DELFILESIGN:
++	ec = 0;
++	while ((arg = poptGetArg(optCon)) != NULL) {
++	    if (rpmPkgDelFileSign(arg, &sargs) < 0)
++		ec++;
++	}
++	break;
+     case MODE_NONE:
+ 	printUsage(optCon, stderr, 0);
+ 	break;
+diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
+index 8d5c5858f..02cf0bc62 100644
+--- a/sign/rpmgensig.c
++++ b/sign/rpmgensig.c
+@@ -336,6 +336,14 @@ static void deleteSigs(Header sigh)
+     headerDel(sigh, RPMSIGTAG_PGP5);
+ }
+ 
++static void deleteFileSigs(Header sigh)
++{
++    headerDel(sigh, RPMSIGTAG_FILESIGNATURELENGTH);
++    headerDel(sigh, RPMSIGTAG_FILESIGNATURES);
++    headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
++    headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO);
++}
++
+ static int haveSignature(rpmtd sigtd, Header h)
+ {
+     pgpDigParams sig1 = NULL;
+@@ -580,7 +588,9 @@ static int rpmSign(const char *rpm, int deleting, int flags)
+ 	    goto exit;
+     }
+ 
+-    if (deleting) {	/* Nuke all the signature tags. */
++    if (deleting == 2) {	/* Nuke IMA + fsverity file signature tags. */
++	deleteFileSigs(sigh);
++    } else if (deleting) {	/* Nuke all the signature tags. */
+ 	deleteSigs(sigh);
+     } else {
+ 	/* Signature target containing header + payload */
+@@ -745,3 +755,8 @@ int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args)
+ {
+     return rpmSign(path, 1, 0);
+ }
++
++int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args)
++{
++    return rpmSign(path, 2, 0);
++}
+diff --git a/sign/rpmsign.h b/sign/rpmsign.h
+index 2b8a10a1a..5169741dd 100644
+--- a/sign/rpmsign.h
++++ b/sign/rpmsign.h
+@@ -44,6 +44,15 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args);
+  */
+ int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args);
+ 
++
++/** \ingroup rpmsign
++ * Delete file signature(s) from a package
++ * @param path		path to package
++ * @param args		signing parameters (or NULL for defaults)
++ * @return		0 on success
++ */
++int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args);
++
+ #ifdef __cplusplus
+ }
+ #endif
+-- 
+2.27.0
+
diff --git a/SOURCES/0031-Update-man-page-for-rpmsign.patch b/SOURCES/0031-Update-man-page-for-rpmsign.patch
new file mode 100644
index 0000000..938e0f1
--- /dev/null
+++ b/SOURCES/0031-Update-man-page-for-rpmsign.patch
@@ -0,0 +1,72 @@
+From 4d243b7e692e3803a764343dfed23feb1c656f0b Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Tue, 12 May 2020 13:42:34 -0400
+Subject: [PATCH 31/33] Update man page for rpmsign
+
+This documents the new arguments --signverity and --certpath required
+to sign a package with fsverity signatures.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ doc/rpmsign.8 | 20 ++++++++++++++++++++
+ 1 file changed, 20 insertions(+)
+
+diff --git a/doc/rpmsign.8 b/doc/rpmsign.8
+index f7ceae89b..a212746fe 100644
+--- a/doc/rpmsign.8
++++ b/doc/rpmsign.8
+@@ -9,6 +9,8 @@ rpmsign \- RPM Package Signing
+ 
+ \fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
+ 
++\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
++
+ .SS "rpmsign-options"
+ .PP
+ [\fb--rpmv3\fR]
+@@ -30,6 +32,12 @@ packages with a MD5/SHA1 checksums cannot be signed in FIPS mode.
+ .PP
+ Delete all signatures from each package \fIPACKAGE_FILE\fR given.
+ 
++\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
++
++.PP
++Delete all IMA and fsverity file signatures from each package
++\fIPACKAGE_FILE\fR given.
++
+ .SS "SIGN OPTIONS"
+ .PP
+ .TP
+@@ -44,12 +52,23 @@ signature verifiable with rpm < 4.14 or other interoperability reasons.
+ \fB--fskpath \fIKEY\fB\fR
+ Used with \fB--signfiles\fR, use file signing key \fIKey\fR.
+ .TP
++\fB--certpath \fICERT\fB\fR
++Used with \fB--signverity\fR, use file signing certificate \fICert\fR.
++.TP
+ \fB--signfiles\fR
+ Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must
+ be set to a supported algorithm before building the package. The
+ supported algorithms are SHA1, SHA256, SHA384, and SHA512, which are
+ represented as 2, 8, 9, and 10 respectively.  The file signing key (RSA
+ private key) must be set before signing the package, it can be configured on the command line with \fB--fskpath\fR or the macro %_file_signing_key.
++.TP
++\fB--signverity\fR
++Sign package files with fsverity signatures. The file signing key (RSA
++private key) and the signing certificate must be set before signing
++the package. The key can be configured on the command line with
++\fB--fskpath\fR or the macro %_file_signing_key, and the cert can be
++configured on the command line with \fB--certpath\fR or the macro
++%_file_signing_cert.
+ 
+ .SS "USING GPG TO SIGN PACKAGES"
+ .PP
+@@ -110,4 +129,5 @@ Jeff Johnson <jbj@redhat.com>
+ Erik Troan <ewt@redhat.com>
+ Panu Matilainen <pmatilai@redhat.com>
+ Fionnuala Gunter <fin@linux.vnet.ibm.com>
++Jes Sorensen <jsorensen@fb.com>
+ .fi
+-- 
+2.27.0
+
diff --git a/SOURCES/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch b/SOURCES/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch
new file mode 100644
index 0000000..c3f56e8
--- /dev/null
+++ b/SOURCES/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch
@@ -0,0 +1,168 @@
+From 3669fecaba2858aeca44d1bfc265760611ea8834 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Wed, 10 Jun 2020 12:30:54 -0400
+Subject: [PATCH 32/33] rpmsign: Add argument to specify algorithm for fsverity
+ signatures
+
+The argument --verity-algo can be used to specify the algorithm for
+the fsverity signatures. If nothing is specified, this will default to
+sha256. The available algorithms depend on libfsverity, currently
+sha256 and sha512 are supported.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ doc/rpmsign.8        |  3 +++
+ rpmsign.c            |  7 +++++++
+ sign/rpmgensig.c     | 22 ++++++++++++++++++++--
+ sign/rpmsignverity.c |  6 +++---
+ sign/rpmsignverity.h |  2 +-
+ 5 files changed, 34 insertions(+), 6 deletions(-)
+
+diff --git a/doc/rpmsign.8 b/doc/rpmsign.8
+index a212746fe..5165e39f9 100644
+--- a/doc/rpmsign.8
++++ b/doc/rpmsign.8
+@@ -55,6 +55,9 @@ Used with \fB--signfiles\fR, use file signing key \fIKey\fR.
+ \fB--certpath \fICERT\fB\fR
+ Used with \fB--signverity\fR, use file signing certificate \fICert\fR.
+ .TP
++\fB--verityalgo \fIALG\fB\fR
++Used with \fB--signverity\fR, to specify the signing algorithm. sha256 and sha512 are supported, with sha256 being the default if this argument is not specified. This can also be specified with the macro %_verity_algorithm
++.TP
+ \fB--signfiles\fR
+ Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must
+ be set to a supported algorithm before building the package. The
+diff --git a/rpmsign.c b/rpmsign.c
+index e43811e9f..12299379c 100644
+--- a/rpmsign.c
++++ b/rpmsign.c
+@@ -25,6 +25,7 @@ static char * fileSigningKey = NULL;
+ #endif
+ #ifdef WITH_FSVERITY
+ static char * fileSigningCert = NULL;
++static char * verityAlgorithm = NULL;
+ #endif
+ 
+ static struct rpmSignArgs sargs = {NULL, 0, 0};
+@@ -52,6 +53,9 @@ static struct poptOption signOptsTable[] = {
+     { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR),
+ 	&sargs.signflags, RPMSIGN_FLAG_FSVERITY,
+ 	N_("generate fsverity signatures for package(s) files"), NULL},
++    { "verityalgo", '\0', POPT_ARG_STRING, &verityAlgorithm, 0,
++	N_("algorithm to use for verity signatures, default sha256"),
++	N_("<algorithm>") },
+     { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0,
+ 	N_("use file signing cert <cert>"),
+ 	N_("<cert>") },
+@@ -138,6 +142,9 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs)
+     if (fileSigningCert) {
+ 	rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL);
+     }
++    if (verityAlgorithm) {
++	rpmPushMacro(NULL, "_verity_algorithm", NULL, verityAlgorithm, RMIL_GLOBAL);
++    }
+ #endif
+ 
+     if (flags_sign_files(sargs->signflags)) {
+diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
+index 02cf0bc62..b3b02828a 100644
+--- a/sign/rpmgensig.c
++++ b/sign/rpmgensig.c
+@@ -8,6 +8,10 @@
+ #include <errno.h>
+ #include <sys/wait.h>
+ #include <popt.h>
++#include <fcntl.h>
++#ifdef WITH_FSVERITY
++#include <libfsverity.h>
++#endif
+ 
+ #include <rpm/rpmlib.h>			/* RPMSIGTAG & related */
+ #include <rpm/rpmmacro.h>
+@@ -458,23 +462,37 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
+ static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)
+ {
+ #ifdef WITH_FSVERITY
+-    rpmRC rc;
++    rpmRC rc = RPMRC_OK;
+     char *key = rpmExpand("%{?_file_signing_key}", NULL);
+     char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
+     char *cert = rpmExpand("%{?_file_signing_cert}", NULL);
++    char *algorithm = rpmExpand("%{?_verity_algorithm}", NULL);
++    uint16_t algo = 0;
+ 
+     if (rstreq(keypass, "")) {
+ 	free(keypass);
+ 	keypass = NULL;
+     }
+ 
++    if (algorithm && strlen(algorithm) > 0) {
++	    algo = libfsverity_find_hash_alg_by_name(algorithm);
++	    rpmlog(RPMLOG_DEBUG, _("Searching for algorithm %s got %i\n"),
++		   algorithm, algo);
++	    if (!algo) {
++		    rpmlog(RPMLOG_ERR, _("Unsupported fsverity algorithm %s\n"),
++			   algorithm);
++		    rc = RPMRC_FAIL;
++		    goto out;
++	    }
++    }
+     if (key && cert) {
+-	rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert);
++	    rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert, algo);
+     } else {
+ 	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));
+ 	rc = RPMRC_FAIL;
+     }
+ 
++ out:
+     free(keypass);
+     free(key);
+     free(cert);
+diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
+index 55096e732..e6c830cdc 100644
+--- a/sign/rpmsignverity.c
++++ b/sign/rpmsignverity.c
+@@ -95,7 +95,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
+ }
+ 
+ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+-		    char *keypass, char *cert)
++		    char *keypass, char *cert, uint16_t algo)
+ {
+     int rc;
+     FD_t gzdi;
+@@ -111,7 +111,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+     char **signatures = NULL;
+     size_t sig_size;
+     int nr_files, idx;
+-    uint16_t algo;
+     uint32_t algo32;
+ 
+     Fseek(fd, 0, SEEK_SET);
+@@ -156,7 +155,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+     nr_files = rpmfiFC(hfi);
+     signatures = xcalloc(nr_files, sizeof(char *));
+ 
+-    algo = FS_VERITY_HASH_ALG_SHA256;
++    if (!algo)
++	    algo = FS_VERITY_HASH_ALG_SHA256;
+ 
+     rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),
+ 	   nr_files, rpmfiFC(fi));
+diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
+index 69bbaf7f7..d869e8d8e 100644
+--- a/sign/rpmsignverity.h
++++ b/sign/rpmsignverity.h
+@@ -27,7 +27,7 @@ extern "C" {
+  */
+ RPM_GNUC_INTERNAL
+ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
+-		    char *keypass, char *cert);
++		    char *keypass, char *cert, uint16_t algo);
+ 
+ #ifdef _cplusplus
+ }
+-- 
+2.27.0
+
diff --git a/SOURCES/0033-Enable-fsverity-in-CI.patch b/SOURCES/0033-Enable-fsverity-in-CI.patch
new file mode 100644
index 0000000..55a209f
--- /dev/null
+++ b/SOURCES/0033-Enable-fsverity-in-CI.patch
@@ -0,0 +1,27 @@
+From 84ee9dc61b14056fec489bb099f1f212b3b169a9 Mon Sep 17 00:00:00 2001
+From: Jes Sorensen <jsorensen@fb.com>
+Date: Fri, 28 Aug 2020 11:10:41 -0400
+Subject: [PATCH 33/33] Enable fsverity in CI
+
+Add fsverity-utils and fsverity-utils-devel as dependencies.
+
+Signed-off-by: Jes Sorensen <jsorensen@fb.com>
+---
+ Makefile.am | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/Makefile.am b/Makefile.am
+index 8e92f0cde..3c1451049 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -17,6 +17,7 @@ DISTCHECK_CONFIGURE_FLAGS = \
+ 	--with-imaevm \
+ 	--with-crypto=openssl \
+ 	--with-fapolicyd \
++	--with-fsverity \
+ 	--disable-dependency-tracking
+ 
+ include $(top_srcdir)/rpm.am
+-- 
+2.27.0
+
diff --git a/SPECS/rpm.spec b/SPECS/rpm.spec
index 353127d..96e3236 100644
--- a/SPECS/rpm.spec
+++ b/SPECS/rpm.spec
@@ -12,6 +12,8 @@
 %bcond_without libarchive
 # build with libimaevm.so
 %bcond_with libimaevm
+# build with libfsverity.so
+%bcond_without libfsverity
 # build with new db format
 %bcond_without ndb
 # build with zstd support?
@@ -30,7 +32,7 @@
 
 %global rpmver 4.14.3
 #global snapver rc2
-%global rel 15.1
+%global rel 15.2
 
 %global srcver %{version}%{?snapver:-%{snapver}}
 %global srcdir %{?snapver:testing}%{!?snapver:%{name}-%(echo %{version} | cut -d'.' -f1-2).x}
@@ -140,6 +142,43 @@ Patch1001: compile-with-Platform-Python-binary-where-relevant.patch
 # make unversioned %%__python an error unless explicitly overridden
 Patch1002: rpm-4.14.2-unversioned-python.patch
 
+# fsverity support
+%if %{with libfsverity}
+Patch1950: 0001-Add-RPMTAG_AUTOINSTALLED-reservation.patch
+Patch1951: 0002-Add-RPMTAG_IDENTITY-reservation.patch
+Patch1952: 0003-Use-lower-level-headerPut-for-file-signing.patch
+Patch1953: 0004-Place-file-signatures-into-the-signature-header-wher.patch
+Patch1954: 0005-Unbreak-file-signing-from-previous-commit.patch
+Patch1955: 0006-Assume-failure-in-rpmSignFiles.patch
+Patch1956: 0007-Use-rpm-file-info-sets-instead-of-header-for-retriev.patch
+Patch1957: 0008-Eliminate-redundant-signature-length-calculation-fun.patch
+Patch1958: 0009-Drop-redundant-check-on-hash-algo-name.patch
+Patch1959: 0010-Drop-redundant-check-on-hash-algo-name.patch
+Patch1960: 0011-Generalize-file-signing-to-use-a-generic-flags-field.patch
+Patch1961: 0012-Stop-adding-rpm-v3-header-payload-signatures-by-defa.patch
+Patch1962: 0013-RPMTAG_PAYLOADDIGESTALT-is-not-backported-here-don-t.patch
+Patch1963: 0014-Drop-support-for-dmalloc.patch
+Patch1964: 0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch
+Patch1965: 0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch
+Patch1966: 0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch
+Patch1967: 0018-rpmsign-Handle-certpath-for-signing-certificate.patch
+Patch1968: 0019-Implement-rpmSignVerity.patch
+Patch1969: 0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch
+Patch1970: 0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch
+Patch1971: 0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch
+Patch1972: 0023-Process-verity-tag-on-package-read.patch
+Patch1973: 0024-Generate-a-zero-length-signature-for-symlinks.patch
+Patch1974: 0025-rpmsignverity.c-Clean-up-debug-logging.patch
+Patch1975: 0026-fsverity-add-tag-for-fsverity-algorithm.patch
+Patch1976: 0027-plugins-fsverity-Install-fsverity-signatures.patch
+Patch1977: 0028-fsverity-plugin-Use-tag-for-algorithm.patch
+Patch1978: 0029-Add-fsverity-tags-to-rpmgeneral.at.patch
+Patch1979: 0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch
+Patch1980: 0031-Update-man-page-for-rpmsign.patch
+Patch1981: 0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch
+Patch1982: 0033-Enable-fsverity-in-CI.patch
+%endif
+
 Patch9998: https://github.com/rpm-software-management/rpm/pull/1381.patch
 Provides: rpm(pr1381)
 Patch9999: https://github.com/rpm-software-management/rpm/pull/1470.patch
@@ -223,6 +262,10 @@ BuildRequires: libubsan
 BuildRequires: %{imadevname} >= 1.0
 %endif
 
+%if %{with libfsverity}
+BuildRequires: fsverity-utils-devel >= 1.1
+%endif
+
 %description
 The RPM Package Manager (RPM) is a powerful command line driven
 package management system capable of installing, uninstalling,
@@ -398,6 +441,17 @@ Requires: rpm-libs%{_isa} = %{version}-%{release}
 %description plugin-ima
 %{summary}
 
+%if %{with libfsverity}
+%package plugin-fsverity
+Summary: Rpm plugin fsverity file signatures
+Group: System Environment/Base
+Requires: rpm-libs%{_isa} = %{version}-%{release}
+
+%description plugin-fsverity
+%{summary}
+
+%endif
+
 %package plugin-prioreset
 Summary: Rpm plugin for resetting scriptlet priorities for SysV init
 Group: System Environment/Base
@@ -471,6 +525,7 @@ done;
     %{?with_ndb: --enable-ndb} \
     %{!?with_libarchive: --without-archive} \
     %{?with_libimaevm: --with-imaevm} \
+    %{?with_libfsverity: --with-fsverity} \
     %{?with_zstd: --enable-zstd} \
     %{?with_lmdb: --enable-lmdb} \
     --with-fapolicyd \
@@ -616,6 +671,11 @@ make check || cat tests/rpmtests.log
 %if %{with plugins}
 %dir %{_libdir}/rpm-plugins
 
+%if %{with libfsverity}
+%files plugin-fsverity
+%{_libdir}/rpm-plugins/fsverity.so
+%endif
+
 %files plugin-syslog
 %{_libdir}/rpm-plugins/syslog.so
 
@@ -700,6 +760,9 @@ make check || cat tests/rpmtests.log
 %doc doc/librpm/html/*
 
 %changelog
+* Tue Aug 03 2021 Matthew Almond <malmond@fb.com> - 4.14.3-15.2
+- Added fsverity backport
+
 * Sat Jul 24 2021 Neal Gompa <ngompa@centosproject.org> - 4.14.3-15.1
 - Rebuild for Hyperscale