summaryrefslogtreecommitdiff
path: root/Add-IMA-digest-list-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'Add-IMA-digest-list-support.patch')
-rw-r--r--Add-IMA-digest-list-support.patch622
1 files changed, 622 insertions, 0 deletions
diff --git a/Add-IMA-digest-list-support.patch b/Add-IMA-digest-list-support.patch
new file mode 100644
index 0000000..223c645
--- /dev/null
+++ b/Add-IMA-digest-list-support.patch
@@ -0,0 +1,622 @@
+From 92ed69a1e2051f202a2532c28cb0b17facda1924 Mon Sep 17 00:00:00 2001
+From: zhoushuiqing <zhoushuiqing2@huawei.com>
+Date: Fri, 16 Jun 2023 11:35:21 +0800
+Subject: [PATCH] Add IMA digest list support
+
+---
+ build/files.c | 305 ++++++++++++++++++++++++++++++++++++++--
+ build/parsePreamble.c | 3 +-
+ macros.in | 1 +
+ plugins/Makefile.am | 4 +
+ plugins/selinux.c | 3 +-
+ rpmio/rpmpgp_internal.c | 32 +----
+ rpmio/rpmpgp_internal.h | 29 ++++
+ 7 files changed, 336 insertions(+), 41 deletions(-)
+
+diff --git a/build/files.c b/build/files.c
+index eb008ab..3fc3551 100644
+--- a/build/files.c
++++ b/build/files.c
+@@ -50,6 +50,8 @@
+ #define DEBUG_LIB_PREFIX "/usr/lib/debug/"
+ #define DEBUG_ID_DIR "/usr/lib/debug/.build-id"
+ #define DEBUG_DWZ_DIR "/usr/lib/debug/.dwz"
++#define DIGEST_LIST_DIR "/.digest_lists"
++#define DEST_DIGEST_LIST_DIR "/etc/ima/digest_lists"
+
+ #undef HASHTYPE
+ #undef HTKEYTYPE
+@@ -129,6 +131,8 @@ typedef struct AttrRec_s {
+
+ /* list of files */
+ static StringBuf check_fileList = NULL;
++/* list of files per binary package */
++static StringBuf check_fileList_bin_pkg = NULL;
+
+ typedef struct FileEntry_s {
+ rpmfileAttrs attrFlags;
+@@ -193,6 +197,10 @@ typedef struct FileList_s {
+ struct FileEntry_s cur;
+ } * FileList;
+
++static char *digest_list_dir;
++
++static int genDigestList(Header header, FileList fl, StringBuf fileList);
++
+ static void nullAttrRec(AttrRec ar)
+ {
+ memset(ar, 0, sizeof(*ar));
+@@ -992,6 +1000,139 @@ static int seenHardLink(FileRecords files, FileListRec flp, rpm_ino_t *fileid)
+ * @param pkg (sub) package
+ * @param isSrc pass 1 for source packages 0 otherwise
+ */
++static void genDigestListInput(FileList fl, Package pkg, int isSrc)
++{
++ FileListRec flp;
++ char buf[BUFSIZ];
++ char file_info[BUFSIZ];
++ char file_digest[128 * 2 + 1];
++ int i, gen_digest_lists = 1;
++ uint32_t defaultalgo = PGPHASHALGO_MD5, digestalgo;
++ Header h = pkg->header; /* just a shortcut */
++
++ /*
++ * See if non-md5 file digest algorithm is requested. If not
++ * specified, quietly assume md5. Otherwise check if supported type.
++ */
++ digestalgo = rpmExpandNumeric(isSrc ? "%{_source_filedigest_algorithm}" :
++ "%{_binary_filedigest_algorithm}");
++ if (digestalgo == 0) {
++ digestalgo = defaultalgo;
++ }
++
++ if (rpmDigestLength(digestalgo) == 0) {
++ rpmlog(RPMLOG_WARNING,
++ _("Unknown file digest algorithm %u, falling back to MD5\n"),
++ digestalgo);
++ digestalgo = defaultalgo;
++ }
++
++ /* Sort the big list */
++ if (fl->files.recs) {
++ qsort(fl->files.recs, fl->files.used,
++ sizeof(*(fl->files.recs)), compareFileListRecs);
++ }
++
++ /* Generate the header. */
++ for (i = 0, flp = fl->files.recs; i < fl->files.used; i++, flp++) {
++ /* Merge duplicate entries. */
++ while (i < (fl->files.used - 1) &&
++ rstreq(flp->cpioPath, flp[1].cpioPath)) {
++
++ /* Two entries for the same file found, merge the entries. */
++ /* Note that an %exclude is a duplication of a file reference */
++
++ /* file flags */
++ flp[1].flags |= flp->flags;
++
++ if (!(flp[1].flags & RPMFILE_EXCLUDE))
++ rpmlog(RPMLOG_WARNING, _("File listed twice: %s\n"),
++ flp->cpioPath);
++
++ /* file mode */
++ if (S_ISDIR(flp->fl_mode)) {
++ if ((flp[1].specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)) <
++ (flp->specdFlags & (SPECD_DIRMODE | SPECD_DEFDIRMODE)))
++ flp[1].fl_mode = flp->fl_mode;
++ } else {
++ if ((flp[1].specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)) <
++ (flp->specdFlags & (SPECD_FILEMODE | SPECD_DEFFILEMODE)))
++ flp[1].fl_mode = flp->fl_mode;
++ }
++
++ /* uid */
++ if ((flp[1].specdFlags & (SPECD_UID | SPECD_DEFUID)) <
++ (flp->specdFlags & (SPECD_UID | SPECD_DEFUID)))
++ {
++ flp[1].fl_uid = flp->fl_uid;
++ flp[1].uname = flp->uname;
++ }
++
++ /* gid */
++ if ((flp[1].specdFlags & (SPECD_GID | SPECD_DEFGID)) <
++ (flp->specdFlags & (SPECD_GID | SPECD_DEFGID)))
++ {
++ flp[1].fl_gid = flp->fl_gid;
++ flp[1].gname = flp->gname;
++ }
++
++ /* verify flags */
++ if ((flp[1].specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)) <
++ (flp->specdFlags & (SPECD_VERIFY | SPECD_DEFVERIFY)))
++ flp[1].verifyFlags = flp->verifyFlags;
++
++ /* XXX to-do: language */
++
++ flp++; i++;
++ }
++
++ /* Skip files that were marked with %exclude. */
++ if (flp->flags & RPMFILE_EXCLUDE)
++ {
++ argvAdd(&pkg->fileExcludeList, flp->cpioPath);
++ continue;
++ }
++
++ buf[0] = '\0';
++ if (S_ISREG(flp->fl_mode) && !(flp->flags & RPMFILE_GHOST))
++ (void) rpmDoDigest(digestalgo, flp->diskPath, 1,
++ (unsigned char *)buf);
++ headerPutString(h, RPMTAG_FILEDIGESTS, buf);
++ snprintf(file_digest, sizeof(file_digest), "%s", buf);
++
++ if (check_fileList_bin_pkg && S_ISREG(flp->fl_mode) &&
++ !(flp->flags & RPMFILE_GHOST)) {
++ appendStringBuf(check_fileList_bin_pkg, "path=");
++ appendStringBuf(check_fileList_bin_pkg, flp->diskPath);
++ snprintf(file_info, sizeof(file_info),
++ "|digestalgopgp=%d|digest=%s|mode=%d"
++ "|uname=%s|gname=%s|caps=%s\n",
++ digestalgo, file_digest, flp->fl_mode,
++ rpmstrPoolStr(fl->pool, flp->uname),
++ rpmstrPoolStr(fl->pool, flp->gname), flp->caps &&
++ strlen(flp->caps) ? flp->caps : "");
++ appendStringBuf(check_fileList_bin_pkg, file_info);
++ }
++
++ if (S_ISREG(flp->fl_mode) &&
++ !strncmp(flp->cpioPath, DEST_DIGEST_LIST_DIR,
++ sizeof(DEST_DIGEST_LIST_DIR) - 1))
++ gen_digest_lists = 0;
++ }
++
++ if (gen_digest_lists &&
++ genDigestList(pkg->header, fl, check_fileList_bin_pkg) > 0)
++ fl->processingFailed = 1;
++}
++
++/**
++ * Add file entries to header.
++ * @todo Should directories have %doc/%config attributes? (#14531)
++ * @todo Remove RPMTAG_OLDFILENAMES, add dirname/basename instead.
++ * @param fl package file tree walk data
++ * @param pkg (sub) package
++ * @param isSrc pass 1 for source packages 0 otherwise
++ */
+ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc)
+ {
+ FileListRec flp;
+@@ -1003,6 +1144,11 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc)
+ int override_date = 0;
+ time_t source_date_epoch = 0;
+ char *srcdate = getenv("SOURCE_DATE_EPOCH");
++ struct rpmtd_s oldfiledigests;
++
++ headerGet(h, RPMTAG_FILEDIGESTS, &oldfiledigests, HEADERGET_ALLOC);
++ headerDel(h, RPMTAG_FILEDIGESTS);
++ rpmtdInit(&oldfiledigests);
+
+ /* Limit the maximum date to SOURCE_DATE_EPOCH if defined
+ * similar to the tar --clamp-mtime option
+@@ -1200,13 +1346,18 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc)
+ if (fl->haveCaps) {
+ headerPutString(h, RPMTAG_FILECAPS, flp->caps);
+ }
+-
++
+ buf[0] = '\0';
+- if (S_ISREG(flp->fl_mode) && !(flp->flags & RPMFILE_GHOST))
+- (void) rpmDoDigest(digestalgo, flp->diskPath, 1,
+- (unsigned char *)buf);
+- headerPutString(h, RPMTAG_FILEDIGESTS, buf);
+-
++ if (strstr(flp->diskPath, DIGEST_LIST_DIR) || !oldfiledigests.count) {
++ if (S_ISREG(flp->fl_mode) && !(flp->flags & RPMFILE_GHOST))
++ (void) rpmDoDigest(digestalgo, flp->diskPath, 1,
++ (unsigned char *)buf);
++ headerPutString(h, RPMTAG_FILEDIGESTS, buf);
++ } else {
++ headerPutString(h, RPMTAG_FILEDIGESTS,
++ rpmtdNextString(&oldfiledigests));
++ }
++
+ buf[0] = '\0';
+ if (S_ISLNK(flp->fl_mode)) {
+ ssize_t llen = readlink(flp->diskPath, buf, BUFSIZ-1);
+@@ -1247,6 +1398,7 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc)
+
+ headerPutUint32(h, RPMTAG_FILEFLAGS, &(flp->flags) ,1);
+ }
++
+ pkg->dpaths[npaths] = NULL;
+
+ if (totalFileSize < UINT32_MAX) {
+@@ -1285,6 +1437,7 @@ static void genCpioListAndHeader(FileList fl, Package pkg, int isSrc)
+ /* Binary packages with dirNames cannot be installed by legacy rpm. */
+ (void) rpmlibNeedsFeature(pkg, "CompressedFileNames", "3.0.4-1");
+ }
++ rpmtdFreeData(&oldfiledigests);
+ }
+
+ static FileRecords FileRecordsFree(FileRecords files)
+@@ -1359,8 +1512,8 @@ static int validFilename(const char *fn)
+ * @param statp file stat (possibly NULL)
+ * @return RPMRC_OK on success
+ */
+-static rpmRC addFile(FileList fl, const char * diskPath,
+- struct stat * statp)
++static rpmRC addFile_common(FileList fl, const char * diskPath,
++ struct stat * statp, int digest_list)
+ {
+ size_t plen = strlen(diskPath);
+ char buf[plen + 1];
+@@ -1371,6 +1524,10 @@ static rpmRC addFile(FileList fl, const char * diskPath,
+ gid_t fileGid;
+ const char *fileUname;
+ const char *fileGname;
++ char realPath[PATH_MAX];
++ int digest_list_prefix = 0;
++ struct stat st;
++ int exclude = 0;
+ rpmRC rc = RPMRC_FAIL; /* assume failure */
+
+ /* Strip trailing slash. The special case of '/' path is handled below. */
+@@ -1406,6 +1563,33 @@ static rpmRC addFile(FileList fl, const char * diskPath,
+ if (*cpioPath == '\0')
+ cpioPath = "/";
+
++ snprintf(realPath, sizeof(realPath), "%s", diskPath);
++ rpmCleanPath(realPath);
++
++ digest_list_prefix = (!strncmp(realPath, digest_list_dir,
++ strlen(digest_list_dir)));
++
++ if ((!digest_list && digest_list_prefix) ||
++ (digest_list && !digest_list_prefix)) {
++ rc = RPMRC_OK;
++ goto exit;
++ }
++
++ if (digest_list) {
++ if (strncmp(cpioPath, DIGEST_LIST_DIR, sizeof(DIGEST_LIST_DIR) - 1)) {
++ rc = RPMRC_OK;
++ goto exit;
++ }
++
++ cpioPath += sizeof(DIGEST_LIST_DIR) - 1;
++
++ snprintf(realPath, sizeof(realPath), "%.*s%s",
++ (int)(strlen(digest_list_dir) - sizeof(DIGEST_LIST_DIR) + 1),
++ digest_list_dir, cpioPath);
++ if (!stat(realPath, &st))
++ exclude = 1;
++ }
++
+ /*
+ * Unless recursing, we dont have stat() info at hand. Handle the
+ * various cases, preserving historical behavior wrt %dev():
+@@ -1543,6 +1727,8 @@ static rpmRC addFile(FileList fl, const char * diskPath,
+ }
+
+ flp->flags = fl->cur.attrFlags;
++ if (exclude)
++ flp->flags |= RPMFILE_EXCLUDE;
+ flp->specdFlags = fl->cur.specdFlags;
+ flp->verifyFlags = fl->cur.verifyFlags;
+
+@@ -1563,6 +1749,32 @@ exit:
+ return rc;
+ }
+
++/**
++ * Add a file to the package manifest.
++ * @param fl package file tree walk data
++ * @param diskPath path to file
++ * @param statp file stat (possibly NULL)
++ * @return RPMRC_OK on success
++ */
++static rpmRC addFile(FileList fl, const char * diskPath,
++ struct stat * statp)
++{
++ return addFile_common(fl, diskPath, statp, 0);
++}
++
++/**
++ * Add a digest list to the package manifest.
++ * @param fl package file tree walk data
++ * @param diskPath path to digest list
++ * @param statp file stat (possibly NULL)
++ * @return RPMRC_OK on success
++ */
++static rpmRC addDigestList(FileList fl, const char * diskPath,
++ struct stat * statp)
++{
++ return addFile_common(fl, diskPath, statp, 1);
++}
++
+ /**
+ * Add directory (and all of its files) to the package manifest.
+ * @param fl package file tree walk data
+@@ -2584,6 +2796,61 @@ static void addPackageFileList (struct FileList_s *fl, Package pkg,
+ argvFree(fileNames);
+ }
+
++/**
++ * Generate digest lists list for current binary package.
++ * @header package header
++ * @fl file list
++ * @param fileList packaged file list
++ * @return -1 if skipped, 0 on OK, 1 on error
++ */
++static int genDigestList(Header header, FileList fl, StringBuf fileList)
++{
++ const char *errorString;
++ char *binFormat = rpmGetPath("%{_rpmfilename}", NULL);
++ char *binRpm = headerFormat(header, binFormat, &errorString);
++ static char * av_brp[] = { "%{?__brp_digest_list}", DIGEST_LIST_DIR + 1, NULL, NULL };
++ StringBuf sb_stdout = NULL;
++ int rc = -1;
++ char * s = rpmExpand(av_brp[0], NULL);
++
++ if (!(s && *s))
++ goto exit;
++
++ if (!strchr(binRpm, '/'))
++ goto exit;
++
++ av_brp[2] = strchr(binRpm, '/') + 1;
++ rpmlog(RPMLOG_NOTICE, _("Generating digest list: %s\n"), s);
++
++ rc = rpmfcExec(av_brp, fileList, &sb_stdout, 0, binRpm);
++ if (sb_stdout && getStringBuf(sb_stdout)) {
++ const char * t = getStringBuf(sb_stdout), *ptr;
++ char *digest_list_path;
++
++ while((ptr = strchr(t, '\n'))) {
++ digest_list_path = strndup(t, ptr - t);
++ if (!digest_list_path) {
++ rc = -1;
++ goto exit;
++ }
++ FileEntryFree(&fl->cur);
++ resetPackageFilesDefaults(fl, fl->pkgFlags);
++ rc = addDigestList(fl, digest_list_path, NULL);
++ free(digest_list_path);
++ if (rc != RPMRC_OK)
++ break;
++
++ t = ptr + 1;
++ }
++ }
++exit:
++ free(binFormat);
++ free(binRpm);
++ free(s);
++ freeStringBuf(sb_stdout);
++ return rc;
++}
++
+ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
+ Package pkg, int didInstall, int test)
+ {
+@@ -2597,6 +2861,10 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
+ if (readFilesManifest(spec, pkg, *fp))
+ return RPMRC_FAIL;
+ }
++
++ /* Init the buffer containing the list of packaged files */
++ check_fileList_bin_pkg = newStringBuf();
++
+ /* Init the file list structure */
+ memset(&fl, 0, sizeof(fl));
+
+@@ -2652,12 +2920,17 @@ static rpmRC processPackageFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
+ if (checkHardLinks(&fl.files))
+ (void) rpmlibNeedsFeature(pkg, "PartialHardlinkSets", "4.0.4-1");
+
++ genDigestListInput(&fl, pkg, 0);
++ if (fl.processingFailed)
++ goto exit;
++
+ genCpioListAndHeader(&fl, pkg, 0);
+
+ exit:
+ FileListFree(&fl);
+ specialDirFree(specialDoc);
+ specialDirFree(specialLic);
++ freeStringBuf(check_fileList_bin_pkg);
+ return fl.processingFailed ? RPMRC_FAIL : RPMRC_OK;
+ }
+
+@@ -3126,6 +3399,7 @@ static void addPackageDeps(Package from, Package to, enum rpmTag_e tag)
+ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
+ int didInstall, int test)
+ {
++ struct stat st;
+ Package pkg;
+ rpmRC rc = RPMRC_OK;
+ char *buildroot;
+@@ -3142,7 +3416,14 @@ rpmRC processBinaryFiles(rpmSpec spec, rpmBuildPkgFlags pkgFlags,
+ check_fileList = newStringBuf();
+ genSourceRpmName(spec);
+ buildroot = rpmGenPath(spec->rootDir, spec->buildRoot, NULL);
+-
++
++ digest_list_dir = rpmGenPath(buildroot, DIGEST_LIST_DIR, NULL);
++ if (!digest_list_dir)
++ goto exit;
++
++ if (!stat(digest_list_dir, &st))
++ rpmlog(RPMLOG_NOTICE, _("Ignoring files in: %s\n"), digest_list_dir);
++
+ if (rpmExpandNumeric("%{?_debuginfo_subpackages}")) {
+ maindbg = findDebuginfoPackage(spec);
+ if (maindbg) {
+@@ -3248,6 +3529,7 @@ exit:
+ check_fileList = freeStringBuf(check_fileList);
+ _free(buildroot);
+ _free(uniquearch);
+-
++ _free(digest_list_dir);
++
+ return rc;
+ }
+diff --git a/build/parsePreamble.c b/build/parsePreamble.c
+index 729fd4f..306a029 100644
+--- a/build/parsePreamble.c
++++ b/build/parsePreamble.c
+@@ -801,7 +801,8 @@ static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag,
+ SINGLE_TOKEN_ONLY;
+ if (tag == RPMTAG_RELEASE) {
+ char *dist = rpmExpand("%{?dist}",NULL);
+- rasprintf(&field,"%s%s",field,dist);
++ rasprintf(&field,"%s%s",field,
++ (dist && strstr(field, dist)) ? "" : dist);
+ free(dist);
+ }
+ if (rpmCharCheck(spec, field, ALLOWED_CHARS_VERREL, NULL))
+diff --git a/macros.in b/macros.in
+index 949fd7d..c00d270 100644
+--- a/macros.in
++++ b/macros.in
+@@ -1135,6 +1135,7 @@ package or when debugging this package.\
+ %__transaction_prioreset %{__plugindir}/prioreset.so
+ %__transaction_audit %{__plugindir}/audit.so
+ %__transaction_dbus_announce %{__plugindir}/dbus_announce.so
++%__transaction_digest_list %{__plugindir}/digest_list.so
+
+ #------------------------------------------------------------------------------
+ # Macros for further automated spec %setup and patch application
+diff --git a/plugins/Makefile.am b/plugins/Makefile.am
+index 822c7d2..161fe4c 100644
+--- a/plugins/Makefile.am
++++ b/plugins/Makefile.am
+@@ -69,3 +69,7 @@ audit_la_sources = audit.c
+ audit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_AUDIT_LIB@
+ plugins_LTLIBRARIES += audit.la
+ endif
++
++digest_list_la_sources = digest_list.c
++digest_list_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
++plugins_LTLIBRARIES += digest_list.la
+diff --git a/plugins/selinux.c b/plugins/selinux.c
+index 316ff88..ac1e354 100644
+--- a/plugins/selinux.c
++++ b/plugins/selinux.c
+@@ -64,7 +64,8 @@ static rpmRC selinux_tsm_pre(rpmPlugin plugin, rpmts ts)
+ rpmRC rc = RPMRC_OK;
+
+ /* If SELinux isn't enabled on the system, dont mess with it */
+- if (!is_selinux_enabled()) {
++ if (!is_selinux_enabled() || selinux_file_context_path() == NULL ||
++ access(selinux_file_context_path(), F_OK)) {
+ rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
+ }
+
+diff --git a/rpmio/rpmpgp_internal.c b/rpmio/rpmpgp_internal.c
+index 19947be..16bf57e 100644
+--- a/rpmio/rpmpgp_internal.c
++++ b/rpmio/rpmpgp_internal.c
+@@ -19,34 +19,6 @@
+
+ static int _print = 0;
+
+-/** \ingroup rpmio
+- * Values parsed from OpenPGP signature/pubkey packet(s).
+- */
+-struct pgpDigParams_s {
+- char * userid;
+- uint8_t * hash;
+- uint8_t tag;
+-
+- uint8_t key_flags; /*!< key usage flags */
+- uint8_t version; /*!< version number. */
+- uint32_t time; /*!< key/signature creation time. */
+- uint8_t pubkey_algo; /*!< public key algorithm. */
+-
+- uint8_t hash_algo;
+- uint8_t sigtype;
+- uint32_t hashlen;
+- uint8_t signhash16[2];
+- pgpKeyID_t signid;
+- uint8_t saved; /*!< Various flags. `PGPDIG_SAVED_*` are never reset.
+- * `PGPDIG_SIG_HAS_*` are reset for each signature. */
+-#define PGPDIG_SAVED_TIME (1 << 0)
+-#define PGPDIG_SAVED_ID (1 << 1)
+-#define PGPDIG_SIG_HAS_CREATION_TIME (1 << 2)
+-#define PGPDIG_SIG_HAS_KEY_FLAGS (1 << 3)
+-
+- pgpDigAlg alg;
+-};
+-
+ /** \ingroup rpmio
+ * Container for values parsed from an OpenPGP signature and public key.
+ */
+@@ -484,6 +456,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
+ }
+
+ p = ((uint8_t *)v) + sizeof(*v);
++ _digp->data = p;
+ rc = tag ? pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp) : 0;
+ } break;
+ case 4:
+@@ -545,7 +518,7 @@ static int pgpPrtSig(pgpTag tag, const uint8_t *h, size_t hlen,
+ p += 2;
+ if (p > hend)
+ return 1;
+-
++ _digp->data = p;
+ rc = tag ? pgpPrtSigParams(tag, v->pubkey_algo, p, h, hlen, _digp) : 0;
+ } break;
+ default:
+@@ -636,6 +609,7 @@ static int pgpPrtKey(pgpTag tag, const uint8_t *h, size_t hlen,
+ }
+
+ p = ((uint8_t *)v) + sizeof(*v);
++ _digp->data = p;
+ rc = pgpPrtPubkeyParams(v->pubkey_algo, p, h, hlen, _digp);
+ }
+ } break;
+diff --git a/rpmio/rpmpgp_internal.h b/rpmio/rpmpgp_internal.h
+index 64b50de..67fecb0 100644
+--- a/rpmio/rpmpgp_internal.h
++++ b/rpmio/rpmpgp_internal.h
+@@ -10,6 +10,35 @@ typedef int (*verifyfunc)(pgpDigAlg pgpkey, pgpDigAlg pgpsig,
+ uint8_t *hash, size_t hashlen, int hash_algo);
+ typedef void (*freefunc)(pgpDigAlg digp);
+
++/** \ingroup rpmio
++ * Values parsed from OpenPGP signature/pubkey packet(s).
++ */
++struct pgpDigParams_s {
++ char * userid;
++ uint8_t * hash;
++ const uint8_t * data;
++ uint8_t tag;
++
++ uint8_t key_flags; /*!< key usage flags */
++ uint8_t version; /*!< version number. */
++ uint32_t time; /*!< key/signature creation time. */
++ uint8_t pubkey_algo; /*!< public key algorithm. */
++
++ uint8_t hash_algo;
++ uint8_t sigtype;
++ uint32_t hashlen;
++ uint8_t signhash16[2];
++ pgpKeyID_t signid;
++ uint8_t saved; /*!< Various flags. `PGPDIG_SAVED_*` are never reset.
++ * `PGPDIG_SIG_HAS_*` are reset for each signature. */
++#define PGPDIG_SAVED_TIME (1 << 0)
++#define PGPDIG_SAVED_ID (1 << 1)
++#define PGPDIG_SIG_HAS_CREATION_TIME (1 << 2)
++#define PGPDIG_SIG_HAS_KEY_FLAGS (1 << 3)
++
++ pgpDigAlg alg;
++};
++
+ struct pgpDigAlg_s {
+ setmpifunc setmpi;
+ verifyfunc verify;
+--
+2.39.1
+