summaryrefslogtreecommitdiff
path: root/sign
diff options
context:
space:
mode:
authorwangbiao <biao716.wang@samsung.com>2023-11-16 18:17:42 +0900
committerwangbiao <biao716.wang@samsung.com>2023-11-16 18:17:42 +0900
commitc30d127e8780dc678168ee121b9f2eeb1a8aaafa (patch)
treecdc9ddc3123edd5741e5151f3076c9bfc9535916 /sign
parent258ff2bdb80c458b743417c427f66fa5f27bf7c5 (diff)
downloadlibrpm-tizen-c30d127e8780dc678168ee121b9f2eeb1a8aaafa.tar.gz
librpm-tizen-c30d127e8780dc678168ee121b9f2eeb1a8aaafa.tar.bz2
librpm-tizen-c30d127e8780dc678168ee121b9f2eeb1a8aaafa.zip
Upgrade version to 4.14tizen/4.14.1.1.tizen20230628
Change-Id: I21bf1a3a7c25cbec43022202cf2e5865b603a309 Signed-off-by: wangbiao <biao716.wang@samsung.com>
Diffstat (limited to 'sign')
-rw-r--r--sign/Makefile.am9
-rw-r--r--sign/rpmgensig.c756
-rw-r--r--sign/rpmsign.h13
-rw-r--r--sign/rpmsignfiles.c135
-rw-r--r--sign/rpmsignfiles.h25
5 files changed, 687 insertions, 251 deletions
diff --git a/sign/Makefile.am b/sign/Makefile.am
index db82702bc..db774de0e 100644
--- a/sign/Makefile.am
+++ b/sign/Makefile.am
@@ -1,8 +1,10 @@
# Makefile for rpm library.
include $(top_srcdir)/rpm.am
+AM_CFLAGS = @RPMCFLAGS@
AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir) -I$(top_builddir)/include/
+AM_CPPFLAGS += @WITH_BEECRYPT_INCLUDE@
AM_CPPFLAGS += @WITH_NSS_INCLUDE@
AM_CPPFLAGS += @WITH_POPT_INCLUDE@
AM_CPPFLAGS += -I$(top_srcdir)/misc
@@ -11,9 +13,14 @@ usrlibdir = $(libdir)
usrlib_LTLIBRARIES = librpmsign.la
librpmsign_la_SOURCES = rpmgensig.c
-librpmsign_la_LDFLAGS = -version-info 2:0:1
+librpmsign_la_LDFLAGS = -version-info $(rpm_version_info)
librpmsign_la_LIBADD = \
$(top_builddir)/lib/librpm.la \
$(top_builddir)/rpmio/librpmio.la \
@WITH_POPT_LIB@ \
@LIBINTL@
+
+if WITH_IMAEVM
+librpmsign_la_SOURCES += rpmsignfiles.c rpmsignfiles.h
+librpmsign_la_LIBADD += @WITH_IMAEVM_LIB@
+endif
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
index 7695ffad7..d29c17837 100644
--- a/sign/rpmgensig.c
+++ b/sign/rpmgensig.c
@@ -8,6 +8,7 @@
#include <errno.h>
#include <sys/wait.h>
#include <popt.h>
+#include <libgen.h>
#include <rpm/rpmlib.h> /* RPMSIGTAG & related */
#include <rpm/rpmmacro.h>
@@ -16,15 +17,82 @@
#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 "sign/rpmsignfiles.h"
#include "debug.h"
-#if !defined(__GLIBC__) && !defined(__APPLE__)
-char ** environ = NULL;
-#endif
+typedef struct sigTarget_s {
+ FD_t fd;
+ const char *fileName;
+ off_t start;
+ rpm_loff_t size;
+} *sigTarget;
+
+/*
+ * There is no function for creating unique temporary fifos so create
+ * unique temporary directory and then create fifo in it.
+ */
+static char *mkTempFifo(void)
+{
+ char *tmppath = NULL, *tmpdir = NULL, *fifofn = NULL;
+ mode_t mode;
+
+ tmppath = rpmExpand("%{_tmppath}", NULL);
+ if (rpmioMkpath(tmppath, 0755, (uid_t) -1, (gid_t) -1))
+ goto exit;
+
+
+ tmpdir = rpmGetPath(tmppath, "/rpm-tmp.XXXXXX", NULL);
+ mode = umask(0077);
+ tmpdir = mkdtemp(tmpdir);
+ umask(mode);
+ if (tmpdir == NULL) {
+ rpmlog(RPMLOG_ERR, _("error creating temp directory %s: %m\n"),
+ tmpdir);
+ tmpdir = _free(tmpdir);
+ goto exit;
+ }
+
+ fifofn = rpmGetPath(tmpdir, "/fifo", NULL);
+ if (mkfifo(fifofn, 0600) == -1) {
+ rpmlog(RPMLOG_ERR, _("error creating fifo %s: %m\n"), fifofn);
+ fifofn = _free(fifofn);
+ }
+
+exit:
+ if (fifofn == NULL && tmpdir != NULL)
+ unlink(tmpdir);
+
+ free(tmppath);
+ free(tmpdir);
+
+ return fifofn;
+}
+
+/* Delete fifo and then temporary directory in which it was located */
+static int rpmRmTempFifo(const char *fn)
+{
+ int rc = 0;
+ char *dfn = NULL, *dir = NULL;
+
+ if ((rc = unlink(fn)) != 0) {
+ rpmlog(RPMLOG_ERR, _("error delete fifo %s: %m\n"), fn);
+ return rc;
+ }
+
+ dfn = xstrdup(fn);
+ dir = dirname(dfn);
+
+ if ((rc = rmdir(dir)) != 0)
+ rpmlog(RPMLOG_ERR, _("error delete directory %s: %m\n"), dir);
+ free(dfn);
+
+ return rc;
+}
static int closeFile(FD_t *fdp)
{
@@ -42,13 +110,26 @@ static int closeFile(FD_t *fdp)
static int manageFile(FD_t *fdp, const char *fn, int flags)
{
FD_t fd;
+ const char *fmode;
if (fdp == NULL || fn == NULL) /* programmer error */
return 1;
/* open a file and set *fdp */
if (*fdp == NULL && fn != NULL) {
- fd = Fopen(fn, (flags & O_ACCMODE) == O_WRONLY ? "w.ufdio" : "r.ufdio");
+ switch (flags & O_ACCMODE) {
+ case O_WRONLY:
+ fmode = "w.ufdio";
+ break;
+ case O_RDONLY:
+ fmode = "r.ufdio";
+ break;
+ default:
+ case O_RDWR:
+ fmode = "r+.ufdio";
+ break;
+ }
+ fd = Fopen(fn, fmode);
if (fd == NULL || Ferror(fd)) {
rpmlog(RPMLOG_ERR, _("%s: open failed: %s\n"), fn,
Fstrerror(fd));
@@ -68,6 +149,10 @@ static int manageFile(FD_t *fdp, const char *fn, int flags)
/**
* Copy header+payload, calculating digest(s) on the fly.
+ * @param sfdp source file
+ * @param sfnp source path
+ * @param tfdp destination file
+ * @param tfnp destination path
*/
static int copyFile(FD_t *sfdp, const char *sfnp,
FD_t *tfdp, const char *tfnp)
@@ -76,11 +161,6 @@ static int copyFile(FD_t *sfdp, const char *sfnp,
ssize_t count;
int rc = 1;
- if (manageFile(sfdp, sfnp, O_RDONLY))
- goto exit;
- if (manageFile(tfdp, tfnp, O_WRONLY|O_CREAT|O_TRUNC))
- goto exit;
-
while ((count = Fread(buf, sizeof(buf[0]), sizeof(buf), *sfdp)) > 0)
{
if (Fwrite(buf, sizeof(buf[0]), count, *tfdp) != count) {
@@ -101,8 +181,6 @@ static int copyFile(FD_t *sfdp, const char *sfnp,
rc = 0;
exit:
- if (*sfdp) (void) closeFile(sfdp);
- if (*tfdp) (void) closeFile(tfdp);
return rc;
}
@@ -110,14 +188,13 @@ exit:
* Validate generated signature and insert to header if it looks sane.
* NSS doesn't support everything GPG does. Basic tests to see if the
* generated signature is something we can use.
- * Return 0 on success, 1 on failure.
+ * Return generated signature tag data on success, NULL on failure.
*/
-static int putSignature(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen)
+static rpmtd makeSigTag(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen)
{
pgpDigParams sigp = NULL;
rpmTagVal sigtag;
- struct rpmtd_s sigtd;
- int rc = 1; /* assume failure */
+ rpmtd sigtd = NULL;
unsigned int hash_algo;
unsigned int pubkey_algo;
@@ -147,48 +224,42 @@ static int putSignature(Header sigh, int ishdr, uint8_t *pkt, size_t pktlen)
break;
}
- /* Looks sane, insert into header */
- rpmtdReset(&sigtd);
- sigtd.count = pktlen;
- sigtd.data = pkt;
- sigtd.type = RPM_BIN_TYPE;
- sigtd.tag = sigtag;
-
- /* Argh, reversed return codes */
- rc = (headerPut(sigh, &sigtd, HEADERPUT_DEFAULT) == 0);
+ /* Looks sane, create the tag data */
+ sigtd = rpmtdNew();
+ sigtd->count = pktlen;
+ sigtd->data = memcpy(xmalloc(pktlen), pkt, pktlen);;
+ sigtd->type = RPM_BIN_TYPE;
+ sigtd->tag = sigtag;
+ sigtd->flags |= RPMTD_ALLOCED;
exit:
pgpDigParamsFree(sigp);
- return rc;
+ return sigtd;
}
-static int runGPG(const char *file, const char *sigfile, const char * passPhrase)
+static int runGPG(sigTarget sigt, const char *sigfile)
{
- int pid, status;
- int inpipe[2];
- FILE * fpipe;
+ int pid = 0, status;
+ FD_t fnamedPipe = NULL;
+ char *namedPipeName = NULL;
+ unsigned char buf[BUFSIZ];
+ ssize_t count;
+ ssize_t wantCount;
+ rpm_loff_t size;
int rc = 1; /* assume failure */
- inpipe[0] = inpipe[1] = 0;
- if (pipe(inpipe) < 0) {
- rpmlog(RPMLOG_ERR, _("Couldn't create pipe for signing: %m"));
- goto exit;
- }
+ namedPipeName = mkTempFifo();
- addMacro(NULL, "__plaintext_filename", NULL, file, -1);
- addMacro(NULL, "__signature_filename", NULL, sigfile, -1);
+ rpmPushMacro(NULL, "__plaintext_filename", NULL, namedPipeName, -1);
+ rpmPushMacro(NULL, "__signature_filename", NULL, sigfile, -1);
if (!(pid = fork())) {
char *const *av;
char *cmd = NULL;
const char *gpg_path = rpmExpand("%{?_gpg_path}", NULL);
- (void) dup2(inpipe[0], 3);
- (void) close(inpipe[1]);
-
if (gpg_path && *gpg_path != '\0')
(void) setenv("GNUPGHOME", gpg_path, 1);
- (void) setenv("LC_ALL", "C", 1);
unsetenv("MALLOC_CHECK_");
cmd = rpmExpand("%{?__gpg_sign_cmd}", NULL);
@@ -201,23 +272,61 @@ static int runGPG(const char *file, const char *sigfile, const char * passPhrase
_exit(EXIT_FAILURE);
}
- delMacro(NULL, "__plaintext_filename");
- delMacro(NULL, "__signature_filename");
+ rpmPopMacro(NULL, "__plaintext_filename");
+ rpmPopMacro(NULL, "__signature_filename");
- fpipe = fdopen(inpipe[1], "w");
- (void) close(inpipe[0]);
- if (fpipe) {
- fprintf(fpipe, "%s\n", (passPhrase ? passPhrase : ""));
- (void) fclose(fpipe);
+ fnamedPipe = Fopen(namedPipeName, "w");
+ if (!fnamedPipe) {
+ rpmlog(RPMLOG_ERR, _("Fopen failed\n"));
+ goto exit;
+ }
+
+ if (Fseek(sigt->fd, sigt->start, SEEK_SET) < 0) {
+ rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
+ sigt->fileName, Fstrerror(sigt->fd));
+ goto exit;
}
+ size = sigt->size;
+ wantCount = size < sizeof(buf) ? size : sizeof(buf);
+ while ((count = Fread(buf, sizeof(buf[0]), wantCount, sigt->fd)) > 0) {
+ Fwrite(buf, sizeof(buf[0]), count, fnamedPipe);
+ if (Ferror(fnamedPipe)) {
+ rpmlog(RPMLOG_ERR, _("Could not write to pipe\n"));
+ goto exit;
+ }
+ size -= count;
+ wantCount = size < sizeof(buf) ? size : sizeof(buf);
+ }
+ if (count < 0) {
+ rpmlog(RPMLOG_ERR, _("Could not read from file %s: %s\n"),
+ sigt->fileName, Fstrerror(sigt->fd));
+ goto exit;
+ }
+ Fclose(fnamedPipe);
+ fnamedPipe = NULL;
+
(void) waitpid(pid, &status, 0);
+ pid = 0;
if (!WIFEXITED(status) || WEXITSTATUS(status)) {
rpmlog(RPMLOG_ERR, _("gpg exec failed (%d)\n"), WEXITSTATUS(status));
} else {
rc = 0;
}
+
exit:
+
+ if (fnamedPipe)
+ Fclose(fnamedPipe);
+
+ if (pid)
+ waitpid(pid, &status, 0);
+
+ if (namedPipeName) {
+ rpmRmTempFifo(namedPipeName);
+ free(namedPipeName);
+ }
+
return rc;
}
@@ -225,20 +334,19 @@ exit:
* Generate GPG signature(s) for a header+payload file.
* @param sigh signature header
* @param ishdr header-only signature?
- * @param file header+payload file name
+ * @param sigt signature target
* @param passPhrase private key pass phrase
- * @return 0 on success, 1 on failure
+ * @return generated sigtag on success, 0 on failure
*/
-static int makeGPGSignature(Header sigh, int ishdr,
- const char * file, const char * passPhrase)
+static rpmtd makeGPGSignature(Header sigh, int ishdr, sigTarget sigt)
{
- char * sigfile = rstrscat(NULL, file, ".sig", NULL);
+ char * sigfile = rstrscat(NULL, sigt->fileName, ".sig", NULL);
struct stat st;
uint8_t * pkt = NULL;
size_t pktlen = 0;
- int rc = 1; /* assume failure */
+ rpmtd sigtd = NULL;
- if (runGPG(file, sigfile, passPhrase))
+ if (runGPG(sigt, sigfile))
goto exit;
if (stat(sigfile, &st)) {
@@ -253,7 +361,7 @@ static int makeGPGSignature(Header sigh, int ishdr,
{ FD_t fd;
- rc = 0;
+ int rc = 0;
fd = Fopen(sigfile, "r.ufdio");
if (fd != NULL && !Ferror(fd)) {
rc = Fread(pkt, sizeof(*pkt), pktlen, fd);
@@ -268,233 +376,346 @@ static int makeGPGSignature(Header sigh, int ishdr,
rpmlog(RPMLOG_DEBUG, "Got %zd bytes of GPG sig\n", pktlen);
/* Parse the signature, change signature tag as appropriate. */
- rc = putSignature(sigh, ishdr, pkt, pktlen);
+ sigtd = makeSigTag(sigh, ishdr, pkt, pktlen);
exit:
(void) unlink(sigfile);
free(sigfile);
free(pkt);
- return rc;
+ return sigtd;
}
-/**
- * Generate header only signature(s) from a header+payload file.
- * @param sigh signature header
- * @param file header+payload file name
- * @param passPhrase private key pass phrase
- * @return 0 on success, -1 on failure
- */
-static int makeHDRSignature(Header sigh, const char * file,
- const char * passPhrase)
+static void deleteSigs(Header sigh)
{
- Header h = NULL;
- FD_t fd = NULL;
- char * fn = NULL;
- int ret = -1; /* assume failure. */
+ headerDel(sigh, RPMSIGTAG_GPG);
+ headerDel(sigh, RPMSIGTAG_PGP);
+ headerDel(sigh, RPMSIGTAG_DSA);
+ headerDel(sigh, RPMSIGTAG_RSA);
+ headerDel(sigh, RPMSIGTAG_PGP5);
+}
+
+static int haveSignature(rpmtd sigtd, Header h)
+{
+ pgpDigParams sig1 = NULL;
+ pgpDigParams sig2 = NULL;
+ struct rpmtd_s oldtd;
+ int rc = 0; /* assume no */
+
+ if (!headerGet(h, rpmtdTag(sigtd), &oldtd, HEADERGET_DEFAULT))
+ return rc;
+
+ pgpPrtParams(sigtd->data, sigtd->count, PGPTAG_SIGNATURE, &sig1);
+ while (rpmtdNext(&oldtd) >= 0 && rc == 0) {
+ pgpPrtParams(oldtd.data, oldtd.count, PGPTAG_SIGNATURE, &sig2);
+ if (pgpDigParamsCmp(sig1, sig2) == 0)
+ rc = 1;
+ pgpDigParamsFree(sig2);
+ }
+ pgpDigParamsFree(sig1);
+ rpmtdFreeData(&oldtd);
+
+ return rc;
+}
- fd = Fopen(file, "r.fdio");
- if (fd == NULL || Ferror(fd))
+static int replaceSignature(Header sigh, sigTarget sigt_v3, sigTarget sigt_v4)
+{
+ int rc = -1;
+ rpmtd sigtd = NULL;
+
+ /* Make the cheaper v4 signature first */
+ if ((sigtd = makeGPGSignature(sigh, 1, sigt_v4)) == NULL)
goto exit;
- h = headerRead(fd, HEADER_MAGIC_YES);
- if (h == NULL)
+
+ /* See if we already have a signature by the same key and parameters */
+ if (haveSignature(sigtd, sigh)) {
+ rc = 1;
goto exit;
- (void) Fclose(fd);
+ }
+ /* Nuke all signature tags */
+ deleteSigs(sigh);
- fd = rpmMkTempFile(NULL, &fn);
- if (fd == NULL || Ferror(fd))
+ if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)
goto exit;
- if (headerWrite(fd, h, HEADER_MAGIC_YES))
+ rpmtdFree(sigtd);
+
+ /* Assume the same signature test holds for v3 signature too */
+ if ((sigtd = makeGPGSignature(sigh, 0, sigt_v3)) == NULL)
goto exit;
- ret = makeGPGSignature(sigh, 1, fn, passPhrase);
+ if (headerPut(sigh, sigtd, HEADERPUT_DEFAULT) == 0)
+ goto exit;
+ rc = 0;
exit:
- if (fn) {
- (void) unlink(fn);
- free(fn);
+ rpmtdFree(sigtd);
+ return rc;
+}
+
+static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag)
+{
+ struct rpmtd_s td;
+ rpmtd utd = &td;
+ Header nh;
+ Header oh;
+
+ if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) {
+ oh = headerCopyLoad(utd->data);
+ nh = headerCopy(oh);
+ headerFree(oh);
+ rpmtdFreeData(utd);
+ headerFree(*hdrp);
+ *hdrp = headerLink(nh);
+ headerFree(nh);
}
- headerFree(h);
- if (fd != NULL) (void) Fclose(fd);
- return ret;
}
-static int rpmGenSignature(Header sigh, const char * file,
- const char * passPhrase)
+#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)
{
- int ret = -1; /* assume failure. */
+ off_t archiveSize;
+ rpmRC rc = RPMRC_OK;
- if (makeGPGSignature(sigh, 0, file, passPhrase) == 0) {
- /* XXX Piggyback a header-only DSA/RSA signature as well. */
- ret = makeHDRSignature(sigh, file, passPhrase);
+ 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;
}
- return ret;
-}
+ /* Get payload size from signature tag */
+ archiveSize = headerGetNumber(*sigp, RPMSIGTAG_PAYLOADSIZE);
+ if (!archiveSize) {
+ archiveSize = headerGetNumber(*sigp, RPMSIGTAG_LONGARCHIVESIZE);
+ }
-/**
- * Retrieve signature from header tag
- * @param sigh signature header
- * @param sigtag signature tag
- * @return parsed pgp dig or NULL
- */
-static pgpDigParams getSig(Header sigh, rpmTagVal sigtag)
-{
- struct rpmtd_s pkt;
- pgpDigParams sig = NULL;
+ /* Set reserved space to 0 */
+ rpmPushMacro(NULL, "__gpg_reserved_space", NULL, 0, RMIL_GLOBAL);
- if (headerGet(sigh, sigtag, &pkt, HEADERGET_DEFAULT) && pkt.data != NULL) {
- pgpPrtParams(pkt.data, pkt.count, PGPTAG_SIGNATURE, &sig);
- rpmtdFreeData(&pkt);
+ /* 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;
}
- return sig;
-}
-static void deleteSigs(Header sigh)
-{
- headerDel(sigh, RPMSIGTAG_GPG);
- headerDel(sigh, RPMSIGTAG_PGP);
- headerDel(sigh, RPMSIGTAG_DSA);
- headerDel(sigh, RPMSIGTAG_RSA);
- headerDel(sigh, RPMSIGTAG_PGP5);
+ 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 int sameSignature(rpmTagVal sigtag, Header h1, Header h2)
+static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
+ Header *sigp, Header *hdrp,
+ off_t sigStart, off_t headerStart)
{
- pgpDigParams sig1 = getSig(h1, sigtag);
- pgpDigParams sig2 = getSig(h2, sigtag);;
+#ifdef WITH_IMAEVM
+ FD_t ofd = NULL;
+ char *trpm = NULL;
+ 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);
+
+ keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
+ if (rstreq(keypass, "")) {
+ free(keypass);
+ keypass = NULL;
+ }
- int rc = pgpDigParamsCmp(sig1, sig2);
+ rc = rpmSignFiles(*hdrp, key, keypass);
+ if (rc != RPMRC_OK) {
+ goto exit;
+ }
- pgpDigParamsFree(sig1);
- pgpDigParamsFree(sig2);
- return (rc == 0);
-}
+ *hdrp = headerReload(*hdrp, RPMTAG_HEADERIMMUTABLE);
+ if (*hdrp == NULL) {
+ rc = RPMRC_FAIL;
+ rpmlog(RPMLOG_ERR, _("headerReload failed\n"));
+ goto exit;
+ }
-static int replaceSignature(Header sigh, const char *sigtarget,
- const char *passPhrase)
-{
- /* Grab a copy of the header so we can compare the result */
- Header oldsigh = headerCopy(sigh);
- int rc = -1;
-
- /* Nuke all signature tags */
- deleteSigs(sigh);
+ 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;
+ }
- /*
- * rpmGenSignature() internals parse the actual signing result and
- * adds appropriate tags for DSA/RSA.
- */
- if (rpmGenSignature(sigh, sigtarget, passPhrase) == 0) {
- /* Lets see what we got and whether its the same signature as before */
- rpmTagVal sigtag = headerIsEntry(sigh, RPMSIGTAG_DSA) ?
- RPMSIGTAG_DSA : RPMSIGTAG_RSA;
+ /* Start MD5 calculation */
+ fdInitDigestID(fd, PGPHASHALGO_MD5, RPMSIGTAG_MD5, 0);
- rc = sameSignature(sigtag, sigh, oldsigh);
+ /* 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);
}
- headerFree(oldsigh);
+ 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"));
+ return RPMRC_FAIL;
+#endif
}
/** \ingroup rpmcli
* Create/modify elements in signature header.
* @param rpm path to package
* @param deleting adding or deleting signature?
- * @param passPhrase passPhrase (ignored when deleting)
+ * @param signfiles sign files if non-zero
* @return 0 on success, -1 on error
*/
-static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
+static int rpmSign(const char *rpm, int deleting, int signfiles)
{
FD_t fd = NULL;
FD_t ofd = NULL;
- rpmlead lead = NULL;
- char *sigtarget = NULL, *trpm = NULL;
+ char *trpm = NULL;
Header sigh = NULL;
- char * msg = NULL;
+ Header h = NULL;
+ char *msg = NULL;
int res = -1; /* assume failure */
rpmRC rc;
struct rpmtd_s utd;
+ off_t headerStart;
+ off_t sigStart;
+ struct sigTarget_s sigt_v3;
+ struct sigTarget_s sigt_v4;
+ unsigned int origSigSize;
+ int insSig = 0;
fprintf(stdout, "%s:\n", rpm);
- if (manageFile(&fd, rpm, O_RDONLY))
+ if (manageFile(&fd, rpm, O_RDWR))
goto exit;
- if ((rc = rpmLeadRead(fd, &lead, NULL, &msg)) != RPMRC_OK) {
+ if ((rc = rpmLeadRead(fd, NULL, &msg)) != RPMRC_OK) {
rpmlog(RPMLOG_ERR, "%s: %s\n", rpm, msg);
- free(msg);
goto exit;
}
- rc = rpmReadSignature(fd, &sigh, RPMSIGTYPE_HEADERSIG, &msg);
- switch (rc) {
- default:
+ sigStart = Ftell(fd);
+ rc = rpmReadSignature(fd, &sigh, &msg);
+ if (rc != RPMRC_OK) {
rpmlog(RPMLOG_ERR, _("%s: rpmReadSignature failed: %s"), rpm,
(msg && *msg ? msg : "\n"));
- msg = _free(msg);
goto exit;
- break;
- case RPMRC_OK:
- if (sigh == NULL) {
- rpmlog(RPMLOG_ERR, _("%s: No signature available\n"), rpm);
- goto exit;
- }
- break;
}
- msg = _free(msg);
- ofd = rpmMkTempFile(NULL, &sigtarget);
- if (ofd == NULL || Ferror(ofd)) {
- rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
+ headerStart = Ftell(fd);
+ if (rpmReadHeader(NULL, fd, &h, &msg) != RPMRC_OK) {
+ rpmlog(RPMLOG_ERR, _("%s: headerRead failed: %s\n"), rpm, msg);
goto exit;
}
- /* Write the header and archive to a temp file */
- if (copyFile(&fd, rpm, &ofd, sigtarget))
- goto exit;
- /* Both fd and ofd are now closed. sigtarget contains tempfile name. */
-
- /* Dump the immutable region (if present). */
- if (headerGet(sigh, RPMTAG_HEADERSIGNATURES, &utd, HEADERGET_DEFAULT)) {
- struct rpmtd_s copytd;
- Header nh = headerNew();
- Header oh = headerCopyLoad(utd.data);
- HeaderIterator hi = headerInitIterator(oh);
- while (headerNext(hi, &copytd)) {
- if (copytd.data)
- headerPut(nh, &copytd, HEADERPUT_DEFAULT);
- rpmtdFreeData(&copytd);
- }
- headerFreeIterator(hi);
- headerFree(oh);
- headerFree(sigh);
- sigh = headerLink(nh);
- headerFree(nh);
+ if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
+ rpmlog(RPMLOG_ERR, _("Cannot sign RPM v3 packages\n"));
+ goto exit;
}
- /* Eliminate broken digest values. */
- headerDel(sigh, RPMSIGTAG_BADSHA1_1);
- headerDel(sigh, RPMSIGTAG_BADSHA1_2);
-
- /* Toss and recalculate header+payload size and digests. */
- {
- rpmTagVal const sigs[] = { RPMSIGTAG_SIZE,
- RPMSIGTAG_MD5,
- RPMSIGTAG_SHA1,
- };
- int nsigs = sizeof(sigs) / sizeof(rpmTagVal);
- for (int i = 0; i < nsigs; i++) {
- (void) headerDel(sigh, sigs[i]);
- if (rpmGenDigest(sigh, sigtarget, sigs[i]))
- goto exit;
- }
+ 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. */
deleteSigs(sigh);
} else {
- res = replaceSignature(sigh, sigtarget, passPhrase);
+ /* Signature target containing header + payload */
+ sigt_v3.fd = fd;
+ sigt_v3.start = headerStart;
+ sigt_v3.fileName = rpm;
+ sigt_v3.size = fdSize(fd) - headerStart;
+
+ /* Signature target containing only header */
+ sigt_v4 = sigt_v3;
+ sigt_v4.size = headerSizeof(h, HEADER_MAGIC_YES);
+
+ res = replaceSignature(sigh, &sigt_v3, &sigt_v4);
if (res != 0) {
if (res == 1) {
rpmlog(RPMLOG_WARNING,
@@ -505,6 +726,31 @@ static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
}
goto exit;
}
+ res = -1;
+ }
+
+ /* Try to make new signature smaller to have size of original signature */
+ rpmtdReset(&utd);
+ if (headerGet(sigh, RPMSIGTAG_RESERVEDSPACE, &utd, HEADERGET_MINMEM)) {
+ int diff;
+ int count;
+ char *reservedSpace = NULL;
+
+ count = utd.count;
+ diff = headerSizeof(sigh, HEADER_MAGIC_YES) - origSigSize;
+
+ if (diff < count) {
+ reservedSpace = xcalloc(count - diff, sizeof(char));
+ headerDel(sigh, RPMSIGTAG_RESERVEDSPACE);
+ rpmtdReset(&utd);
+ utd.tag = RPMSIGTAG_RESERVEDSPACE;
+ utd.count = count - diff;
+ utd.type = RPM_BIN_TYPE;
+ utd.data = reservedSpace;
+ headerPut(sigh, &utd, HEADERPUT_DEFAULT);
+ free(reservedSpace);
+ insSig = 1;
+ }
}
/* Reallocate the signature into one contiguous region. */
@@ -512,38 +758,60 @@ static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
if (sigh == NULL) /* XXX can't happen */
goto exit;
- rasprintf(&trpm, "%s.XXXXXX", rpm);
- ofd = rpmMkTemp(trpm);
- if (ofd == NULL || Ferror(ofd)) {
- rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
- goto exit;
- }
+ if (insSig) {
+ /* Insert new signature into original rpm */
+ if (Fseek(fd, sigStart, SEEK_SET) < 0) {
+ rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
+ rpm, Fstrerror(fd));
+ goto exit;
+ }
- /* Write the lead/signature of the output rpm */
- rc = rpmLeadWrite(ofd, lead);
- if (rc != RPMRC_OK) {
- rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm,
- Fstrerror(ofd));
- goto exit;
- }
+ if (rpmWriteSignature(fd, sigh)) {
+ rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), rpm,
+ Fstrerror(fd));
+ goto exit;
+ }
+ res = 0;
+ } else {
+ /* Replace orignal rpm with new rpm containing new signature */
+ rasprintf(&trpm, "%s.XXXXXX", rpm);
+ ofd = rpmMkTemp(trpm);
+ if (ofd == NULL || Ferror(ofd)) {
+ rpmlog(RPMLOG_ERR, _("rpmMkTemp failed\n"));
+ goto exit;
+ }
- if (rpmWriteSignature(ofd, sigh)) {
- rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm,
- Fstrerror(ofd));
- goto exit;
- }
+ /* Write the lead/signature of the output rpm */
+ rc = rpmLeadWrite(ofd, h);
+ if (rc != RPMRC_OK) {
+ rpmlog(RPMLOG_ERR, _("%s: writeLead failed: %s\n"), trpm,
+ Fstrerror(ofd));
+ goto exit;
+ }
- /* Append the header and archive from the temp file */
- if (copyFile(&fd, sigtarget, &ofd, trpm) == 0) {
- struct stat st;
+ if (rpmWriteSignature(ofd, sigh)) {
+ rpmlog(RPMLOG_ERR, _("%s: rpmWriteSignature failed: %s\n"), trpm,
+ Fstrerror(ofd));
+ goto exit;
+ }
- /* Move final target into place, restore file permissions. */
- if (stat(rpm, &st) == 0 && unlink(rpm) == 0 &&
- rename(trpm, rpm) == 0 && chmod(rpm, st.st_mode) == 0) {
- res = 0;
- } else {
- rpmlog(RPMLOG_ERR, _("replacing %s failed: %s\n"),
- rpm, strerror(errno));
+ if (Fseek(fd, headerStart, SEEK_SET) < 0) {
+ rpmlog(RPMLOG_ERR, _("Could not seek in file %s: %s\n"),
+ rpm, Fstrerror(fd));
+ goto exit;
+ }
+ /* Append the header and archive from the temp file */
+ if (copyFile(&fd, rpm, &ofd, trpm) == 0) {
+ struct stat st;
+
+ /* Move final target into place, restore file permissions. */
+ if (stat(rpm, &st) == 0 && unlink(rpm) == 0 &&
+ rename(trpm, rpm) == 0 && chmod(rpm, st.st_mode) == 0) {
+ res = 0;
+ } else {
+ rpmlog(RPMLOG_ERR, _("replacing %s failed: %s\n"),
+ rpm, strerror(errno));
+ }
}
}
@@ -551,14 +819,11 @@ exit:
if (fd) (void) closeFile(&fd);
if (ofd) (void) closeFile(&ofd);
- rpmFreeSignature(sigh);
- rpmLeadFree(lead);
+ headerFree(sigh);
+ headerFree(h);
+ free(msg);
/* Clean up intermediate target */
- if (sigtarget) {
- unlink(sigtarget);
- free(sigtarget);
- }
if (trpm) {
(void) unlink(trpm);
free(trpm);
@@ -567,8 +832,7 @@ exit:
return res;
}
-int rpmPkgSign(const char *path,
- const struct rpmSignArgs * args, const char *passPhrase)
+int rpmPkgSign(const char *path, const struct rpmSignArgs * args)
{
int rc;
@@ -576,29 +840,29 @@ int rpmPkgSign(const char *path,
if (args->hashalgo) {
char *algo = NULL;
rasprintf(&algo, "%d", args->hashalgo);
- addMacro(NULL, "_gpg_digest_algo", NULL, algo, RMIL_GLOBAL);
+ rpmPushMacro(NULL, "_gpg_digest_algo", NULL, algo, RMIL_GLOBAL);
free(algo);
}
if (args->keyid) {
- addMacro(NULL, "_gpg_name", NULL, args->keyid, RMIL_GLOBAL);
+ rpmPushMacro(NULL, "_gpg_name", NULL, args->keyid, RMIL_GLOBAL);
}
}
- rc = rpmSign(path, 0, passPhrase);
+ rc = rpmSign(path, 0, args ? args->signfiles : 0);
if (args) {
if (args->hashalgo) {
- delMacro(NULL, "_gpg_digest_algo");
+ rpmPopMacro(NULL, "_gpg_digest_algo");
}
if (args->keyid) {
- delMacro(NULL, "_gpg_name");
+ rpmPopMacro(NULL, "_gpg_name");
}
}
return rc;
}
-int rpmPkgDelSign(const char *path)
+int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args)
{
- return rpmSign(path, 1, NULL);
+ return rpmSign(path, 1, 0);
}
diff --git a/sign/rpmsign.h b/sign/rpmsign.h
index 15b3e0fe8..bed8d6245 100644
--- a/sign/rpmsign.h
+++ b/sign/rpmsign.h
@@ -1,6 +1,11 @@
#ifndef _RPMSIGN_H
#define _RPMSIGN_H
+/** \file sign/rpmsign.h
+ *
+ * Signature API
+ */
+
#include <rpm/argv.h>
#include <rpm/rpmpgp.h>
@@ -11,6 +16,7 @@ extern "C" {
struct rpmSignArgs {
char *keyid;
pgpHashAlgo hashalgo;
+ int signfiles;
/* ... what else? */
};
@@ -18,18 +24,17 @@ struct rpmSignArgs {
* Sign a package
* @param path path to package
* @param args signing parameters (or NULL for defaults)
- * @param passPhrase passphrase for the signing key
* @return 0 on success
*/
-int rpmPkgSign(const char *path,
- const struct rpmSignArgs * args, const char *passPhrase);
+int rpmPkgSign(const char *path, const struct rpmSignArgs * args);
/** \ingroup rpmsign
* Delete signature(s) from a package
* @param path path to package
+ * @param args signing parameters (or NULL for defaults)
* @return 0 on success
*/
-int rpmPkgDelSign(const char *path);
+int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args);
#ifdef __cplusplus
}
diff --git a/sign/rpmsignfiles.c b/sign/rpmsignfiles.c
new file mode 100644
index 000000000..61b73bd40
--- /dev/null
+++ b/sign/rpmsignfiles.c
@@ -0,0 +1,135 @@
+/**
+ * Copyright (C) 2014 IBM Corporation
+ *
+ * Author: Fionnuala Gunter <fin@linux.vnet.ibm.com>
+ */
+
+#include "system.h"
+#include "imaevm.h"
+
+#include <rpm/rpmlog.h> /* rpmlog */
+#include <rpm/rpmstring.h> /* rnibble */
+#include <rpm/rpmpgp.h> /* rpmDigestLength */
+#include "lib/header.h" /* HEADERGET_MINMEM */
+#include "lib/rpmtypes.h" /* rpmRC */
+
+#include "sign/rpmsignfiles.h"
+
+#define MAX_SIGNATURE_LENGTH 1024
+
+static const char *hash_algo_name[] = {
+ [PGPHASHALGO_MD5] = "md5",
+ [PGPHASHALGO_SHA1] = "sha1",
+ [PGPHASHALGO_RIPEMD160] = "rmd160",
+ [PGPHASHALGO_MD2] = "md2",
+ [PGPHASHALGO_TIGER192] = "tgr192",
+ [PGPHASHALGO_HAVAL_5_160] = "haval5160",
+ [PGPHASHALGO_SHA256] = "sha256",
+ [PGPHASHALGO_SHA384] = "sha384",
+ [PGPHASHALGO_SHA512] = "sha512",
+ [PGPHASHALGO_SHA224] = "sha224",
+};
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+static char *signFile(const char *algo, const char *fdigest, int diglen,
+const char *key, char *keypass)
+{
+ char *fsignature;
+ unsigned char digest[diglen];
+ 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)
+ 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';
+
+ /* calculate file signature */
+ siglen = sign_hash(algo, digest, diglen, key, keypass, signature+1);
+ if (siglen < 0) {
+ rpmlog(RPMLOG_ERR, _("sign_hash failed\n"));
+ return NULL;
+ }
+
+ /* 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 h, const char *key, char *keypass)
+{
+ struct rpmtd_s digests;
+ int algo;
+ int diglen;
+ uint32_t siglen;
+ const char *algoname;
+ const char *digest;
+ char *signature;
+ rpmRC rc = RPMRC_OK;
+
+ 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;
+ }
+
+ diglen = rpmDigestLength(algo);
+ algoname = hash_algo_name[algo];
+ if (!algoname) {
+ rpmlog(RPMLOG_ERR, _("hash_algo_name failed\n"));
+ return RPMRC_FAIL;
+ }
+
+ headerDel(h, RPMTAG_FILESIGNATURELENGTH);
+ headerDel(h, RPMTAG_FILESIGNATURES);
+ siglen = signatureLength(algoname, diglen, key, keypass);
+ headerPutUint32(h, RPMTAG_FILESIGNATURELENGTH, &siglen, 1);
+
+ headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);
+ while ((digest = rpmtdNextString(&digests))) {
+ signature = signFile(algoname, digest, diglen, key, keypass);
+ if (!signature) {
+ rpmlog(RPMLOG_ERR, _("signFile failed\n"));
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+ if (!headerPutString(h, RPMTAG_FILESIGNATURES, signature)) {
+ free(signature);
+ rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+ free(signature);
+ }
+
+exit:
+ rpmtdFreeData(&digests);
+ return rc;
+}
diff --git a/sign/rpmsignfiles.h b/sign/rpmsignfiles.h
new file mode 100644
index 000000000..4163fafde
--- /dev/null
+++ b/sign/rpmsignfiles.h
@@ -0,0 +1,25 @@
+#ifndef H_RPMSIGNFILES
+#define H_RPMSIGNFILES
+
+#include <rpm/rpmtypes.h>
+#include <rpm/rpmutil.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Sign file digests in header and store the signatures in 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);
+
+#ifdef _cplusplus
+}
+#endif
+
+#endif /* H_RPMSIGNFILES */