Blob Blame History Raw
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