[Rpm-maint] [PATCH 4/4] Sign package files during installation

Dmitry Kasatkin d.kasatkin at samsung.com
Mon Oct 20 14:04:57 UTC 2014


On 07/10/14 23:19, fin at linux.vnet.ibm.com wrote:
> From: Fionnuala Gunter <fin at linux.vnet.ibm.com>
>
> It will take some time for distros to adopt the file signing process and 
> distribute packages with file signatures, so this patch extends the rpm 
> installer to support inline file signing. This patch adds a new option,
> signfiles, to the rpm installer.
>
> rpm -ivh [--signfiles [--fskpath <file signing key>]] PACKAGE_FILE ...
>
> Signed-off-by: Fionnuala Gunter <fin at linux.vnet.ibm.com>
> ---
>  doc/rpm.8            | 28 +++++++++++++++++++---------
>  lib/fsm.c            | 50 +++++++++++++++++++++++++++++++++++++++++++++-----
>  lib/poptI.c          |  7 +++++++
>  lib/rpmcli.h         |  2 ++
>  lib/rpminstall.c     | 10 +++++++++-
>  lib/rpmts.c          | 15 +++++++++++++++
>  lib/rpmts.h          | 15 +++++++++++++++
>  lib/rpmts_internal.h |  2 ++
>  8 files changed, 114 insertions(+), 15 deletions(-)
>
> diff --git a/doc/rpm.8 b/doc/rpm.8
> index e583009..4079f71 100644
> --- a/doc/rpm.8
> +++ b/doc/rpm.8
> @@ -84,15 +84,14 @@ rpm \- RPM Package Manager
>  
>  
>   [\fB--allfiles\fR] [\fB--badreloc\fR] [\fB--excludepath \fIOLDPATH\fB\fR]
> - [\fB--excludedocs\fR] [\fB--force\fR] [\fB-h,--hash\fR]
> - [\fB--ignoresize\fR] [\fB--ignorearch\fR] [\fB--ignoreos\fR]
> - [\fB--includedocs\fR] [\fB--justdb\fR] [\fB--nocollections\fR]
> - [\fB--nodeps\fR] [\fB--nodigest\fR] [\fB--nosignature\fR]
> - [\fB--noorder\fR] [\fB--noscripts\fR] [\fB--notriggers\fR] 
> - [\fB--oldpackage\fR] [\fB--percent\fR] [\fB--prefix \fINEWPATH\fB\fR]
> - [\fB--relocate \fIOLDPATH\fB=\fINEWPATH\fB\fR]
> - [\fB--replacefiles\fR] [\fB--replacepkgs\fR]
> - [\fB--test\fR]
> + [\fB--excludedocs\fR] [\fB--force\fR] [\fB--fskpath \fIKEY\fB\fR]
> + [\fB-h,--hash\fR] [\fB--ignoresize\fR] [\fB--ignorearch\fR]
> + [\fB--ignoreos\fR] [\fB--includedocs\fR] [\fB--justdb\fR]
> + [\fB--nocollections\fR] [\fB--nodeps\fR] [\fB--nodigest\fR]
> + [\fB--nosignature\fR] [\fB--noorder\fR] [\fB--noscripts\fR]
> + [\fB--notriggers\fR] [\fB--oldpackage\fR] [\fB--percent\fR]
> + [\fB--prefix \fINEWPATH\fB\fR] [\fB--relocate \fIOLDPATH\fB=\fINEWPATH\fB\fR]
> + [\fB--replacefiles\fR] [\fB--replacepkgs\fR] [\fB--signfiles] [\fB--test\fR]
>  
>  .SH "DESCRIPTION"
>  .PP
> @@ -232,6 +231,9 @@ Don't install files whose name begins with
>  Don't install any files which are marked as documentation
>  (which includes man pages and texinfo documents).
>  .TP
> +\fB--fskpath \fIKEY\fB\fR
> +Used with \fB--signfiles\fR, use file signing key \fIKEY\fR.
> +.TP
>  \fB--force\fR
>  Same as using
>  \fB--replacepkgs\fR,
> @@ -362,6 +364,13 @@ already installed, packages.
>  Install the packages even if some of them are already installed
>  on this system.
>  .TP
> +\fB--signfiles\fR
> +Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must be set
> +before building the package, and the macro must be set to a supported algorithm:
> +2, 8, 9, or 10, which represent SHA1, SHA256, SHA384, and SHA512, respectively.
> +The file signing key (RSA private key) can be configured on the command line
> +with \fB--fskpath\fR or the macro \fB%_file_signing_key\fR.
> +.TP
>  \fB--test\fR
>  Do not install the package, simply check for and report
>  potential conflicts.
> @@ -875,4 +884,5 @@ what's available.
>  Marc Ewing <marc at redhat.com>
>  Jeff Johnson <jbj at redhat.com>
>  Erik Troan <ewt at redhat.com>
> +Fionnuala Gunter <fin at linux.vnet.ibm.com>
>  .fi
> diff --git a/lib/fsm.c b/lib/fsm.c
> index dbeeaab..05ea230 100644
> --- a/lib/fsm.c
> +++ b/lib/fsm.c
> @@ -21,6 +21,7 @@
>  #include "lib/rpmplugins.h"	/* rpm plugins hooks */
>  #include "lib/rpmug.h"
>  #include "lib/rpmlib.h"
> +#include "lib/rpmsignfiles.h"	/* getDigestAlgo, getDigestLength, signFile */
>  
>  #include "debug.h"
>  
> @@ -825,8 +826,13 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
>      const char *suffix;
>      char *fpath = NULL;
>      Header h = rpmteHeader(te);
> -    struct rpmtd_s sigs;
> -    char *sig = NULL;
> +    struct rpmtd_s digests, sigs;
> +    int signFiles = rpmtsSignFiles(ts);
> +    const char *key;
> +    const char *algo;
> +    const char *digest;
> +    const char *sig;
> +    int diglen = 0;
>  
>      if (fi == NULL) {
>  	rc = RPMERR_BAD_MAGIC;
> @@ -838,7 +844,30 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
>  	goto exit;
>      }
>  
> -    headerGet(h, RPMTAG_FILESIGNATURES, &sigs, HEADERGET_MINMEM);
> +    if (signFiles) {
> +	algo = getDigestAlgo(h);
> +	if (!algo) {
> +	    rc = RPMRC_FAIL;
> +	    goto exit;
> +	}
> +
> +	diglen = getDigestLength(h);
> +	if (diglen < 0) {
> +	    rc = RPMRC_FAIL;
> +	    goto exit;
> +	}
> +
> +	key = rpmExpand("%{_file_signing_key}", NULL);
> +	if (rstreq(key, "")) {
> +	    rc = RPMRC_FAIL;
> +	    fprintf(stderr, _("You must set \"$$_file_signing_key\" in your macro file or on the command line with --fskpath\n"));
> +	    rpmlog(RPMLOG_ERR, _("no file signing key provided\n"));
> +	}
> +
> +	headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);
> +    } else {
> +	headerGet(h, RPMTAG_FILESIGNATURES, &sigs, HEADERGET_MINMEM);
> +    }
>  
>      /* transaction id used for temporary path suffix while installing */
>      rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
> @@ -964,12 +993,22 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
>  	if (rc)
>  	    *failedFile = xstrdup(fpath);
>  
> -	/* get file signatures from header */
> -	if (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
> +	/* sign executable files */
> +	if (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH) && signFiles) {
> +	    digest = rpmtdNextString(&digests);
> +	    sig = signFile(algo, digest, diglen, key);

Hi,

'sig' here is exactly signature for the file digest.

Please see my following question...


> +	    if (!sig) {
> +		rpmlog(RPMLOG_ERR, _("signFile failed\n"));
> +		goto exit;
> +	    }
> +	}
> +	/* or get file signatures from header */
> +	else if (sb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) {
>  	    sig = rpmtdNextString(&sigs);

How "sig" is selected from among several sigs?
How does it correspond to a file? Order is known?


Thanks,
Dmitry


>  	} else {
>  	    sig = NULL;
>  	    rpmtdNextString(&sigs);
> +	    rpmtdNextString(&digests);
>  	}
>  
>  	/* Run fsm file post hook for all plugins */
> @@ -984,6 +1023,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
>  exit:
>  
>      /* No need to bother with close errors on read */
> +    rpmtdFreeData(&digests);
>      rpmtdFreeData(&sigs);
>      headerFree(h);
>      rpmfiArchiveClose(fi);
> diff --git a/lib/poptI.c b/lib/poptI.c
> index e21cde1..699c8cd 100644
> --- a/lib/poptI.c
> +++ b/lib/poptI.c
> @@ -16,8 +16,10 @@ struct rpmInstallArguments_s rpmIArgs = {
>      0,			/* numRelocations */
>      0,			/* noDeps */
>      0,			/* incldocs */
> +    0,			/* signFiles */
>      NULL,		/* relocations */
>      NULL,		/* prefix */
> +    NULL,		/* fileSigningKey */
>  };
>  
>  #define	POPT_RELOCATE		-1021
> @@ -146,6 +148,9 @@ struct poptOption rpmInstallPoptTable[] = {
>  	(INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL),
>  	N_("upgrade package(s) if already installed"),
>  	N_("<packagefile>+") },
> + { "fskpath", '\0', POPT_ARG_STRING, &rpmIArgs.fileSigningKey, 0,
> +	N_("use file signing key <key>"),
> +	N_("<key>") },
>   { "hash", 'h', POPT_BIT_SET, &rpmIArgs.installInterfaceFlags, INSTALL_HASH,
>  	N_("print hash marks as package installs (good with -v)"), NULL},
>   { "ignorearch", '\0', POPT_BIT_SET,
> @@ -243,6 +248,8 @@ struct poptOption rpmInstallPoptTable[] = {
>   { "replacepkgs", '\0', POPT_BIT_SET,
>  	&rpmIArgs.probFilter, RPMPROB_FILTER_REPLACEPKG,
>  	N_("reinstall if the package is already present"), NULL},
> + { "signfiles", '\0', POPT_ARG_NONE, &rpmIArgs.signFiles, 0,
> +	N_("sign package files"), NULL},
>   { "test", '\0', POPT_BIT_SET, &rpmIArgs.transFlags, RPMTRANS_FLAG_TEST,
>  	N_("don't install, but tell if it would work or not"), NULL},
>   { "upgrade", 'U', POPT_BIT_SET,
> diff --git a/lib/rpmcli.h b/lib/rpmcli.h
> index 48e8250..ff89171 100644
> --- a/lib/rpmcli.h
> +++ b/lib/rpmcli.h
> @@ -339,8 +339,10 @@ struct rpmInstallArguments_s {
>      int numRelocations;
>      int noDeps;
>      int incldocs;
> +    int signFiles;
>      rpmRelocation * relocations;
>      char * prefix;
> +    char * fileSigningKey;
>  };
>  
>  /** \ingroup rpmcli
> diff --git a/lib/rpminstall.c b/lib/rpminstall.c
> index 2e7da7d..d98d506 100644
> --- a/lib/rpminstall.c
> +++ b/lib/rpminstall.c
> @@ -11,6 +11,7 @@
>  #include <rpm/rpmds.h>
>  #include <rpm/rpmts.h>
>  #include <rpm/rpmlog.h>
> +#include <rpm/rpmmacro.h>
>  #include <rpm/rpmfileutil.h>
>  
>  #include "lib/rpmgi.h"
> @@ -417,7 +418,14 @@ int rpmInstall(rpmts ts, struct rpmInstallArguments_s * ia, ARGV_t fileArgv)
>  
>      relocations = ia->relocations;
>  
> -    setNotifyFlag(ia, ts); 
> +    setNotifyFlag(ia, ts);
> +
> +    rpmtsSetSignFiles(ts, ia->signFiles);
> +
> +    if (ia->fileSigningKey) {
> +	addMacro(NULL, "_file_signing_key", NULL, ia->fileSigningKey,
> +		 RMIL_GLOBAL);
> +    }
>  
>      if ((eiu->relocations = relocations) != NULL) {
>  	while (eiu->relocations->oldPath)
> diff --git a/lib/rpmts.c b/lib/rpmts.c
> index a3b4ed2..6d9eb30 100644
> --- a/lib/rpmts.c
> +++ b/lib/rpmts.c
> @@ -897,6 +897,21 @@ int rpmtsSetNotifyCallback(rpmts ts,
>      return 0;
>  }
>  
> +int rpmtsSignFiles(rpmts ts)
> +{
> +    return ts ? ts->signFiles : NULL;
> +}
> +
> +int rpmtsSetSignFiles(rpmts ts, int signFiles)
> +{
> +    if (ts == NULL) {
> +	return -1;
> +    }
> +
> +    ts->signFiles = signFiles;
> +    return 0;
> +}
> +
>  tsMembers rpmtsMembers(rpmts ts)
>  {
>      return (ts != NULL) ? ts->members : NULL;
> diff --git a/lib/rpmts.h b/lib/rpmts.h
> index 5231c80..5f45972 100644
> --- a/lib/rpmts.h
> +++ b/lib/rpmts.h
> @@ -393,6 +393,21 @@ const char * rpmtsRootDir(rpmts ts);
>   */
>  int rpmtsSetRootDir(rpmts ts, const char * rootDir);
>  
> +/**
> + * Get transaction sign files flag
> + * @param ts		transaction set
> + * @return		non-zero if package files need to be signed
> + */
> +int rpmtsSignFiles(rpmts ts);
> +
> +/**
> + * Set transaction sign files flag
> + * @param ts		transaction set
> + * @param signFiles	new sign files flag
> + * @return		0 on success, -1 on error
> + */
> +int rpmtsSetSignFiles(rpmts ts, int signFiles);
> +
>  /** \ingroup rpmts
>   * Get transaction script file handle, i.e. stdout/stderr on scriptlet execution
>   * @param ts		transaction set
> diff --git a/lib/rpmts_internal.h b/lib/rpmts_internal.h
> index 0caa7cb..a196932 100644
> --- a/lib/rpmts_internal.h
> +++ b/lib/rpmts_internal.h
> @@ -68,6 +68,8 @@ struct rpmts_s {
>      rpmPlugins plugins;		/*!< Transaction plugins */
>  
>      int nrefs;			/*!< Reference count. */
> +
> +    int signFiles;		/*!< Sign package files. */
>  };
>  
>  #ifdef __cplusplus



More information about the Rpm-maint mailing list