[Rpm-maint] [PATCH v7 09/11] Add file signature support to package signing

Fionnuala Gunter fionnuala.gunter at gmail.com
Mon Jul 20 22:11:25 UTC 2015


From: "fin at linux.vnet.ibm.com" <fin at linux.vnet.ibm.com>

This patch modifies rpmSign to include file signatures in the header.
Since the header is altered, the package digest and package+archive
digest need to be recalculated and updated in the signature header.
Defer resigning the header digests to replaceSignature().

Changelog:
- removed extraneous semicolon - Mimi
- Update signature header digests only if necessary - Mimi
- rename headerSize to more accurate name sigTargetSize - Fin
- deallocate sigp before it's overriden - Fin
- fix dependency on ima - Fin
- replace utd parameter with a local variable - Mimi
---
 lib/rpmsignfiles.c |   2 +-
 sign/rpmgensig.c   | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 180 insertions(+), 7 deletions(-)

diff --git a/lib/rpmsignfiles.c b/lib/rpmsignfiles.c
index 376f47e..414983b 100644
--- a/lib/rpmsignfiles.c
+++ b/lib/rpmsignfiles.c
@@ -37,7 +37,7 @@ static char *signFile(const char *algo, const char *fdigest, int diglen, const c
    unsigned char signature[MAX_SIGNATURE_LENGTH];
    int siglen;
 
-#ifndef IMAEVM
+#ifndef WITH_IMAEVM
     rpmlog(RPMLOG_ERR, _("missing libimaevm\n"));
     return NULL;
 #endif
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
index b0bed44..d5557dc 100644
--- a/sign/rpmgensig.c
+++ b/sign/rpmgensig.c
@@ -17,9 +17,11 @@
 #include <rpm/rpmfileutil.h>	/* rpmMkTemp() */
 #include <rpm/rpmlog.h>
 #include <rpm/rpmstring.h>
+#include <rpmio/rpmio_internal.h>
 
 #include "lib/rpmlead.h"
 #include "lib/signature.h"
+#include "lib/rpmsignfiles.h"
 
 #include "debug.h"
 
@@ -471,9 +473,10 @@ static int replaceSignature(Header sigh, sigTarget sigt1, sigTarget sigt2)
     return rc;
 }
 
-static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag, rpmtd utd)
+static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag)
 {
-    struct rpmtd_s copytd;
+    struct rpmtd_s copytd, td;
+    rpmtd utd = &td;
     Header nh;
     Header oh;
     HeaderIterator hi;
@@ -498,13 +501,179 @@ static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag, rpmtd utd)
     }
 }
 
+static rpmRC replaceSigDigests(FD_t fd, const char *rpm, Header *sigp,
+			       off_t sigStart, off_t sigTargetSize,
+			       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);
+    }
+
+    /* Replace old digests in sigh */
+    rc = rpmGenerateSignature(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, RPMSIGTYPE_HEADERSIG, NULL);
+    if (rc != RPMRC_OK) {
+	rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n"));
+	goto exit;
+    }
+
+exit:
+    return rc;
+}
+
+static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
+				   Header *sigp, Header *hdrp,
+				   off_t sigStart, off_t headerStart)
+{
+    FD_t ofd = NULL;
+    char *trpm = NULL;
+    const char *key;
+    char *SHA1 = NULL;
+    uint8_t *MD5 = NULL;
+    unsigned char buf[32*BUFSIZ];
+    size_t sha1len;
+    size_t md5len;
+    off_t sigTargetSize;
+    rpmRC rc = RPMRC_OK;
+    struct rpmtd_s osigtd;
+    char *o_sha1 = NULL;
+    uint8_t o_md5[16];
+
+#ifndef WITH_IMAEVM
+    rpmlog(RPMLOG_ERR, _("missing libimaevm\n"));
+    return RPMRC_FAIL;
+#endif
+    unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE);
+
+    key = rpmExpand("%{?_file_signing_key}", NULL);
+
+    rc = rpmSignFiles(*hdrp, key);
+    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;
+    }
+
+    /* Write header to rpm and recalculate SHA1 */
+    fdInitDigest(fd, PGPHASHALGO_SHA1, 0);
+    rc = headerWrite(fd, *hdrp, HEADER_MAGIC_YES);
+    if (rc != RPMRC_OK) {
+	rpmlog(RPMLOG_ERR, _("headerWrite failed\n"));
+	goto exit;
+    }
+    fdFiniDigest(fd, PGPHASHALGO_SHA1, (void **)&SHA1, &sha1len, 1);
+    sigTargetSize = Ftell(fd) - headerStart;
+
+    /* 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);
+
+    /* Recalculate MD5 digest of header+archive */
+    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;
+    }
+    fdInitDigest(fd, PGPHASHALGO_MD5, 0);
+
+    while (Fread(buf, sizeof(buf[0]), sizeof(buf), fd) > 0)
+	;
+    if (Ferror(fd)) {
+	rc = RPMRC_FAIL;
+	rpmlog(RPMLOG_ERR, _("Fread failed in file %s: %s\n"),
+		rpm, Fstrerror(fd));
+	goto exit;
+    }
+    fdFiniDigest(fd, PGPHASHALGO_MD5, (void **)&MD5, &md5len, 0);
+
+    if (headerGet(*sigp, RPMSIGTAG_MD5, &osigtd, HEADERGET_DEFAULT))
+	memcpy(o_md5, osigtd.data, 16);
+
+    if (headerGet(*sigp, RPMSIGTAG_SHA1, &osigtd, HEADERGET_DEFAULT))
+	o_sha1 = xstrdup(osigtd.data);
+
+    if (memcmp(MD5, o_md5, md5len) == 0 && strcmp(SHA1, o_sha1) == 0)
+	rpmlog(RPMLOG_WARNING,
+	       _("%s already contains identical file signatures\n"),
+	       rpm);
+    else
+	replaceSigDigests(fd, rpm, sigp, sigStart, sigTargetSize, SHA1, MD5);
+
+exit:
+if (ofd)    (void) closeFile(&ofd);
+    return rc;
+}
+
 /** \ingroup rpmcli
  * Create/modify elements in signature header.
  * @param rpm		path to package
  * @param deleting	adding or deleting signature?
+ * @param signfiles	sign files if non-zero
  * @return		0 on success, -1 on error
  */
-static int rpmSign(const char *rpm, int deleting)
+static int rpmSign(const char *rpm, int deleting, int signfiles)
 {
     FD_t fd = NULL;
     FD_t ofd = NULL;
@@ -555,7 +724,11 @@ static int rpmSign(const char *rpm, int deleting)
 	goto exit;
     }
 
-    unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES, &utd);
+    if (signfiles) {
+	includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart);
+    }
+
+    unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES);
     origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
 
     if (deleting) {	/* Nuke all the signature tags. */
@@ -704,7 +877,7 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args)
 	}
     }
 
-    rc = rpmSign(path, 0);
+    rc = rpmSign(path, 0, args->signfiles);
 
     if (args) {
 	if (args->hashalgo) {
@@ -720,5 +893,5 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args)
 
 int rpmPkgDelSign(const char *path)
 {
-    return rpmSign(path, 1);
+    return rpmSign(path, 1, 0);
 }
-- 
2.4.3



More information about the Rpm-maint mailing list