|
From: <fi...@li...> - 2014-10-07 20:20:16
|
From: Fionnuala Gunter <fi...@li...> The Linux kernel's ima-appraisal module verifies file signatures. The problem with verifying digital signatures of files is how the files are signed in the first place. In our current prototype, we sign all files after system installation, but this doesn't handle ongoing updates. We propose that Linux distributors sign all files as part of the normal package signing. RPM already maintains hashes of all files in the rpm package, and this can be extended to add file signatures. This patch set extends the rpm signing tool to include file signatures in packages, and extends the rpm install tool to install file signatures. Changelog v2: -support for inline signing of files -command line option for file signing key -included missing file -fixed type in rpmDigestAlgo Changelog v3: -split up patch Fionnuala Gunter (4): Add file signature to fsm_file_post parameter list Sign package files and include signatures in package header Label ima xattr when signed files are installed Sign package files during installation configure.ac | 8 ++ doc/rpm.8 | 28 +++-- doc/rpmsign.8 | 22 +++- lib/Makefile.am | 3 +- lib/fsm.c | 68 ++++++++++- lib/poptI.c | 7 ++ lib/rpmcli.h | 2 + lib/rpminstall.c | 10 +- lib/rpmplugin.h | 3 +- lib/rpmplugins.c | 5 +- lib/rpmplugins.h | 4 +- lib/rpmsignfiles.c | 130 +++++++++++++++++++++ lib/rpmsignfiles.h | 45 ++++++++ lib/rpmtag.h | 1 + lib/rpmts.c | 15 +++ lib/rpmts.h | 15 +++ lib/rpmts_internal.h | 2 + macros.in | 1 + plugins/Makefile.am | 4 + plugins/ima.c | 83 ++++++++++++++ rpmpopt.in | 1 + rpmsign.c | 14 ++- sign/rpmgensig.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++---- sign/rpmsign.h | 7 +- 24 files changed, 750 insertions(+), 47 deletions(-) create mode 100644 lib/rpmsignfiles.c create mode 100644 lib/rpmsignfiles.h create mode 100644 plugins/ima.c -- 1.9.3 |
|
From: <fi...@li...> - 2014-10-07 20:20:17
|
From: Fionnuala Gunter <fi...@li...>
The ima plugin instantiates fsm_file_post hook, but needs access to the
file's signature, so this patch adds a file signature parameter to the
fsm_file_post parameter list.
Signed-off-by: Fionnuala Gunter <fi...@li...>
---
lib/fsm.c | 7 ++++---
lib/rpmplugin.h | 3 ++-
lib/rpmplugins.c | 5 +++--
lib/rpmplugins.h | 4 +++-
4 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/lib/fsm.c b/lib/fsm.c
index 7ae4747..e7c2a3b 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -449,7 +449,8 @@ static int fsmMkdirs(rpmfiles files, rpmfs fs, rpmPlugins plugins)
}
/* Run fsm file post hook for all plugins */
- rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, rc);
+ rpmpluginsCallFsmFilePost(plugins, NULL, dn, mode, op, NULL,
+ rc);
if (!rc) {
rpmlog(RPMLOG_DEBUG,
@@ -954,7 +955,7 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
/* Run fsm file post hook for all plugins */
rpmpluginsCallFsmFilePost(plugins, fi, fpath,
- sb.st_mode, action, rc);
+ sb.st_mode, action, NULL, rc);
fpath = _free(fpath);
}
@@ -1034,7 +1035,7 @@ int rpmPackageFilesRemove(rpmts ts, rpmte te, rpmfiles files,
/* Run fsm file post hook for all plugins */
rpmpluginsCallFsmFilePost(plugins, fi, fpath,
- sb.st_mode, action, rc);
+ sb.st_mode, action, NULL, rc);
/* XXX Failure to remove is not (yet) cause for failure. */
if (!strict_erasures) rc = 0;
diff --git a/lib/rpmplugin.h b/lib/rpmplugin.h
index fd81aec..f755378 100644
--- a/lib/rpmplugin.h
+++ b/lib/rpmplugin.h
@@ -55,7 +55,8 @@ typedef rpmRC (*plugin_fsm_file_pre_func)(rpmPlugin plugin, rpmfi fi,
rpmFsmOp op);
typedef rpmRC (*plugin_fsm_file_post_func)(rpmPlugin plugin, rpmfi fi,
const char* path, mode_t file_mode,
- rpmFsmOp op, int res);
+ rpmFsmOp op, const char *sig,
+ int res);
typedef rpmRC (*plugin_fsm_file_prepare_func)(rpmPlugin plugin, rpmfi fi,
const char* path,
const char *dest,
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
index da04c73..bf856f2 100644
--- a/lib/rpmplugins.c
+++ b/lib/rpmplugins.c
@@ -349,7 +349,8 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char *path,
}
rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,
- mode_t file_mode, rpmFsmOp op, int res)
+ mode_t file_mode, rpmFsmOp op, const char *sig,
+ int res)
{
plugin_fsm_file_post_func hookFunc;
int i;
@@ -358,7 +359,7 @@ rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char *path,
for (i = 0; i < plugins->count; i++) {
rpmPlugin plugin = plugins->plugins[i];
RPMPLUGINS_SET_HOOK_FUNC(fsm_file_post);
- if (hookFunc && hookFunc(plugin, fi, path, file_mode, op, res) == RPMRC_FAIL)
+ if (hookFunc && hookFunc(plugin, fi, path, file_mode, op, sig, res) == RPMRC_FAIL)
rc = RPMRC_FAIL;
}
diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
index ecfa68b..93ab7b9 100644
--- a/lib/rpmplugins.h
+++ b/lib/rpmplugins.h
@@ -144,12 +144,14 @@ rpmRC rpmpluginsCallFsmFilePre(rpmPlugins plugins, rpmfi fi, const char* path,
* @param path file object path
* @param file_mode file object mode
* @param op file operation + associated flags
+ * @param sig file signature
* @param res fsm result code
* @return RPMRC_OK on success, RPMRC_FAIL otherwise
*/
RPM_GNUC_INTERNAL
rpmRC rpmpluginsCallFsmFilePost(rpmPlugins plugins, rpmfi fi, const char* path,
- mode_t file_mode, rpmFsmOp op, int res);
+ mode_t file_mode, rpmFsmOp op, const char *sig,
+ int res);
/** \ingroup rpmplugins
* Call the fsm file prepare plugin hook. Called after setting
--
1.9.3
|
|
From: <fi...@li...> - 2014-10-07 20:20:19
|
From: Fionnuala Gunter <fi...@li...>
This patch extends the existing rpm signing tool to also sign package files
and include them in the package header. It defines a tag,
RPMTAG_FILESIGNATURES, an RPM macro %_file_signing_key, and new options
fskpath, and signfiles.
rpm --addsign [--signfiles [--fskpath <file signing key>]] PACKAGE_FILE ...
The new option to rpmsign signs all the file digests included in the
package. When a package is signed with the new option, the file digests are
signed with libimaevm and the key %file_signing_key. The resulting
signatures are included in the package header as an RPMTAG_FILESIGNATURES
tag. Since the header is modified, the SHA1 and MD5 header digests are
recalculated and inserted in the signature header.
After including file signatures, the package is signed normally.
Signed-off-by: Fionnuala Gunter <fi...@li...>
---
configure.ac | 8 ++
doc/rpmsign.8 | 22 +++-
lib/Makefile.am | 3 +-
lib/rpmsignfiles.c | 130 ++++++++++++++++++++++
lib/rpmsignfiles.h | 45 ++++++++
lib/rpmtag.h | 1 +
rpmpopt.in | 1 +
rpmsign.c | 14 ++-
sign/rpmgensig.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++-----
sign/rpmsign.h | 7 +-
10 files changed, 520 insertions(+), 30 deletions(-)
create mode 100644 lib/rpmsignfiles.c
create mode 100644 lib/rpmsignfiles.h
diff --git a/configure.ac b/configure.ac
index cbb869f..21a6a95 100644
--- a/configure.ac
+++ b/configure.ac
@@ -658,6 +658,14 @@ AC_SUBST(WITH_SELINUX_LIB)
AC_SUBST(WITH_SEMANAGE_LIB)
AM_CONDITIONAL(SELINUX,[test "$with_selinux" = yes])
+# libimaevm
+with_iamevm=no
+AC_ARG_WITH(imaevm, [AS_HELP_STRING([--with-imaevm],[build with imaevm support])])
+if test "$with_imaevm" = yes ; then
+ AC_DEFINE(IMAEVM, 1, [Build with imaevm support?])
+ LIBS="$LIBS -limaevm"
+fi
+
# libcap
WITH_CAP_LIB=
AC_ARG_WITH(cap, [AS_HELP_STRING([--with-cap],[build with capability support])],
diff --git a/doc/rpmsign.8 b/doc/rpmsign.8
index 53f2d70..b19f172 100644
--- a/doc/rpmsign.8
+++ b/doc/rpmsign.8
@@ -2,11 +2,17 @@
.SH NAME
rpmsign \- RPM Package Signing
.SH SYNOPSIS
+.SS "SIGNING PACKAGES:"
+.PP
-\fBrpm\fR \fB--addsign|--resign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
+\fBrpm\fR \fB--addsign|--resign\fR [\fBrpmsign-options\fR] \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
\fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
+.SS "rpmsign-options"
+.PP
+ \fB--fskpath \fIKEY\fB\fR] [\fB--signfiles\fR]
+
.SH DESCRIPTION
.PP
Both of the \fB--addsign\fR and \fB--resign\fR
@@ -20,6 +26,19 @@ there is no difference in behavior currently.
.PP
Delete all signatures from each package \fIPACKAGE_FILE\fR given.
+.SS "SIGN OPTIONS"
+.PP
+.TP
+\fB--fskpath \fIKEY\fB\fR
+Used with \fB--signfiles\fR, use file signing key \fIKEY\fR.
+.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.
+
.SS "USING GPG TO SIGN PACKAGES"
.PP
In order to sign packages using GPG, \fBrpm\fR
@@ -78,4 +97,5 @@ Marc Ewing <ma...@re...>
Jeff Johnson <jb...@re...>
Erik Troan <ew...@re...>
Panu Matilainen <pma...@re...>
+Fionnuala Gunter <fi...@li...>
.fi
diff --git a/lib/Makefile.am b/lib/Makefile.am
index a65eb80..f80a47a 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -38,7 +38,8 @@ librpm_la_SOURCES = \
verify.c rpmlock.c rpmlock.h misc.h relocation.c \
rpmscript.h rpmscript.c legacy.c \
rpmchroot.c rpmchroot.h \
- rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h
+ rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \
+ rpmsignfiles.c rpmsignfiles.h
librpm_la_LDFLAGS = -version-info $(rpm_version_info)
diff --git a/lib/rpmsignfiles.c b/lib/rpmsignfiles.c
new file mode 100644
index 0000000..9c33103
--- /dev/null
+++ b/lib/rpmsignfiles.c
@@ -0,0 +1,130 @@
+/**
+ * Copyright (C) 2014 IBM Corporation
+ *
+ * Author: Fionnuala Gunter <fi...@li...>
+ */
+
+#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 "lib/rpmsignfiles.h"
+
+static char *rpmDigestAlgo(uint32_t dalgo)
+{
+ switch (dalgo) {
+ case 0:
+ case 1: return "md5";
+ case 2: return "sha1";
+ case 8: return "sha256";
+ case 9: return "sha384";
+ case 10: return "sha512";
+ default: return NULL;
+ }
+}
+
+char *getDigestAlgo(Header h)
+{
+ struct rpmtd_s digalgo;
+ uint32_t *dalgo;
+ char *algo;
+
+ headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM);
+ dalgo = rpmtdGetUint32(&digalgo);
+ if (!dalgo) {
+ rpmlog(RPMLOG_ERR, _("rpmtdGetUint32 failed\n"));
+ return NULL;
+ }
+ algo = rpmDigestAlgo(*dalgo);
+ return algo;
+}
+
+int getDigestLength(Header h)
+{
+ struct rpmtd_s digalgo;
+ uint32_t *dalgo;
+ int diglen;
+
+ headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM);
+ dalgo = rpmtdGetUint32(&digalgo);
+ if (!dalgo) {
+ rpmlog(RPMLOG_ERR, _("rpmtdGetUint32 failed\n"));
+ return -1;
+ }
+
+ diglen = rpmDigestLength(*dalgo);
+ return diglen;
+}
+
+char *signFile(const char *algo, const char *fdigest, int diglen, const char *key)
+{
+ char *fsignature;
+ unsigned char digest[BUFSIZ];
+ unsigned char signature[BUFSIZ];
+ int siglen;
+
+#ifndef IMAEVM
+ rpmlog(RPMLOG_ERR, _("missing libimaevm\n"));
+ return NULL;
+#endif
+
+ /* convert file digest hex to binary */
+ memset(digest, 0, BUFSIZ);
+ for (int i = 0; i < diglen; ++i, fdigest += 2)
+ digest[i] = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
+
+ /* prepare file signature */
+ memset(signature, 0, BUFSIZ);
+ signature[0] = '\x03';
+
+ /* calculate file signature */
+ siglen = sign_hash(algo, digest, diglen, key, 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;
+}
+
+rpmRC signFiles(Header h, const char *key)
+{
+ struct rpmtd_s digests;
+ const char *algo;
+ const char *digest;
+ char *signature;
+ int diglen;
+
+ algo = getDigestAlgo(h);
+ if (!algo) {
+ rpmlog(RPMLOG_ERR, _("getDigestAlgo failed\n"));
+ return RPMRC_FAIL;
+ }
+
+ diglen = getDigestLength(h);
+ if (diglen < 0) {
+ rpmlog(RPMLOG_ERR, _("getDigestLength failed\n"));
+ return RPMRC_FAIL;
+ }
+
+ headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);
+ while ((digest = rpmtdNextString(&digests))) {
+ signature = signFile(algo, digest, diglen, key);
+ if (!signature) {
+ rpmlog(RPMLOG_ERR, _("signFile failed\n"));
+ return RPMRC_FAIL;
+ }
+ if (!headerPutString(h, RPMTAG_FILESIGNATURES, signature)) {
+ rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
+ return RPMRC_FAIL;
+ }
+ }
+ return RPMRC_OK;
+}
diff --git a/lib/rpmsignfiles.h b/lib/rpmsignfiles.h
new file mode 100644
index 0000000..05459f0
--- /dev/null
+++ b/lib/rpmsignfiles.h
@@ -0,0 +1,45 @@
+#ifndef H_RPMSIGNFILES
+#define H_RPMSIGNFILES
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Get file digest algorithm from header
+ * @param header package header
+ * @return file digest algorithm
+ */
+char *getDigestAlgo(Header h);
+
+/**
+ * Get file digest length from header
+ * @param header package header
+ * @return file digest length
+ */
+int getDigestLength(Header h);
+
+/**
+ * Sign a file digest with libimaevm
+ * @param algo file digest algorithm
+ * @param fdigest file digest hex
+ * @param diglen digest length
+ * @param key file signing key
+ * @return file signature hex
+ */
+char *signFile(const char *algo, const char *fdigest, int diglen,
+ const char *key);
+
+/**
+ * Sign file digests in header and store the signatures in header
+ * @param h package header
+ * @param key signing key
+ * @return RPMRC_OK on success
+ */
+rpmRC signFiles(Header h, const char *key);
+
+#ifdef _cplusplus
+}
+#endif
+
+#endif /* H_RPMSIGNFILES */
diff --git a/lib/rpmtag.h b/lib/rpmtag.h
index 58b2479..bd6a36a 100644
--- a/lib/rpmtag.h
+++ b/lib/rpmtag.h
@@ -329,6 +329,7 @@ typedef enum rpmTag_e {
RPMTAG_SUPPLEMENTNEVRS = 5060, /* s[] extension */
RPMTAG_ENHANCENEVRS = 5061, /* s[] extension */
RPMTAG_ENCODING = 5062, /* s */
+ RPMTAG_FILESIGNATURES = 5063, /* s[] */
RPMTAG_FIRSTFREE_TAG /*!< internal */
} rpmTag;
diff --git a/rpmpopt.in b/rpmpopt.in
index 036ab4e..df5e2ec 100644
--- a/rpmpopt.in
+++ b/rpmpopt.in
@@ -162,6 +162,7 @@ rpm alias --httpproxy --define '_httpproxy !#:+'
rpm exec --addsign rpmsign --addsign
rpm exec --delsign rpmsign --delsign
rpm exec --resign rpmsign --resign
+#rpm exec --signfiles rpmsign --signfiles
rpm exec --checksig rpmkeys --checksig
rpm exec -K rpmkeys --checksig
rpm exec --import rpmkeys --import
diff --git a/rpmsign.c b/rpmsign.c
index b8e5598..a2692b9 100644
--- a/rpmsign.c
+++ b/rpmsign.c
@@ -20,6 +20,9 @@ enum modes {
static int mode = 0;
+static int signfiles = 0;
+static char * fileSigningKey = NULL;
+
static struct poptOption signOptsTable[] = {
{ "addsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_ADDSIGN,
N_("sign package(s)"), NULL },
@@ -27,6 +30,11 @@ static struct poptOption signOptsTable[] = {
N_("sign package(s) (identical to --addsign)"), NULL },
{ "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,
N_("delete package signatures"), NULL },
+ { "signfiles", '\0', POPT_ARG_NONE, &signfiles, 0,
+ N_("sign package(s) files"), NULL},
+ { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,
+ N_("use file signing key <key>"),
+ N_("<key>") },
POPT_TABLEEND
};
@@ -119,6 +127,10 @@ static int doSign(poptContext optCon)
goto exit;
}
+ if (fileSigningKey && signfiles) {
+ addMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
+ }
+
/* XXX FIXME: eliminate obsolete getpass() usage */
passPhrase = getpass(_("Enter pass phrase: "));
passPhrase = (passPhrase != NULL) ? rstrdup(passPhrase) : NULL;
@@ -127,7 +139,7 @@ static int doSign(poptContext optCon)
fprintf(stderr, _("Pass phrase is good.\n"));
rc = 0;
while ((arg = poptGetArg(optCon)) != NULL) {
- rc += rpmPkgSign(arg, NULL, passPhrase);
+ rc += rpmPkgSign(arg, NULL, passPhrase, signfiles);
}
} else {
fprintf(stderr, _("Pass phrase check failed or gpg key expired\n"));
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
index 0bd14e3..f07c87e 100644
--- a/sign/rpmgensig.c
+++ b/sign/rpmgensig.c
@@ -1,4 +1,10 @@
-/** \ingroup rpmcli
+/**
+ * Copyright (C) 2014 IBM Corporation
+ *
+ * Author: Fionnuala Gunter <fi...@li...>
+ * added support for file signatures
+ *
+ * \ingroup rpmcli
* \file lib/rpmchecksig.c
* Verify the signature of a package.
*/
@@ -8,17 +14,23 @@
#include <errno.h>
#include <sys/wait.h>
#include <popt.h>
+#include <imaevm.h>
+#include <ctype.h>
#include <rpm/rpmlib.h> /* RPMSIGTAG & related */
#include <rpm/rpmmacro.h>
#include <rpm/rpmpgp.h>
#include <rpm/rpmsign.h>
-#include <rpm/rpmfileutil.h> /* rpmMkTemp() */
+#include <rpm/rpmfileutil.h> /* rpmMkTemp() */
#include <rpm/rpmlog.h>
#include <rpm/rpmstring.h>
#include "lib/rpmlead.h"
#include "lib/signature.h"
+#include "lib/header.h"
+#include "lib/cpio.h" /* rpmcpioOpen, rpmcpioTell */
+#include "lib/rpmsignfiles.h" /* signFiles */
+#include "rpmio/rpmio_internal.h" /* fdInitDigest, fdFiniDigest */
#include "debug.h"
@@ -88,6 +100,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)
@@ -121,8 +137,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;
}
@@ -458,14 +472,277 @@ static int replaceSignature(Header sigh, sigTarget sigt1, sigTarget sigt2,
return rc;
}
+static rpmRC generateSignature(char *SHA1, uint8_t *MD5, rpm_loff_t size,
+ rpm_loff_t payloadSize, FD_t fd)
+{
+ Header sig = NULL;
+ struct rpmtd_s td;
+ rpmTagVal sizetag;
+ rpmTagVal payloadtag;
+ rpm_tagtype_t typetag;
+ rpmRC rc = RPMRC_OK;
+ char *reservedSpace;
+ int spaceSize = 0;
+
+ /* Prepare signature */
+ sig = rpmNewSignature();
+
+ rpmtdReset(&td);
+ td.tag = RPMSIGTAG_SHA1;
+ td.count = 1;
+ td.type = RPM_STRING_TYPE;
+ td.data = SHA1;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+
+ rpmtdReset(&td);
+ td.tag = RPMSIGTAG_MD5;
+ td.count = 16;
+ td.type = RPM_BIN_TYPE;
+ td.data = MD5;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+
+ if (payloadSize < UINT32_MAX) {
+ sizetag = RPMSIGTAG_SIZE;
+ payloadtag = RPMSIGTAG_PAYLOADSIZE;
+ typetag = RPM_INT32_TYPE;
+ } else {
+ sizetag = RPMSIGTAG_LONGSIZE;
+ payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
+ typetag = RPM_INT64_TYPE;
+ }
+
+ rpmtdReset(&td);
+ td.tag = payloadtag;
+ td.count = 1;
+ td.type = typetag;
+ td.data = &payloadSize;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+
+ rpmtdReset(&td);
+ td.tag = sizetag;
+ td.count = 1;
+ td.type = typetag;
+ td.data = &size;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+
+ spaceSize = rpmExpandNumeric("%{__gpg_reserved_space}");
+ if(spaceSize > 0) {
+ reservedSpace = xcalloc(spaceSize, sizeof(char));
+ rpmtdReset(&td);
+ td.tag = RPMSIGTAG_RESERVEDSPACE;
+ td.count = spaceSize;
+ td.type = RPM_BIN_TYPE;
+ td.data = reservedSpace;
+ headerPut(sig, &td, HEADERPUT_DEFAULT);
+ free(reservedSpace);
+ }
+
+ /* Reallocate the signature into one contiguous region. */
+ sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
+ if (sig == NULL) { /* XXX can't happen */
+ rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+
+ /* Write the signature section into the package. */
+ if (rpmWriteSignature(fd, sig)) {
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+
+exit:
+ rpmFreeSignature(sig);
+ return rc;
+}
+
+static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag, rpmtd utd)
+{
+ struct rpmtd_s copytd;
+ Header nh;
+ Header oh;
+ HeaderIterator hi;
+
+ if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) {
+ nh = headerNew();
+ oh = headerCopyLoad(utd->data);
+ hi = headerInitIterator(oh);
+
+ while (headerNext(hi, ©td)) {
+ if (copytd.data)
+ headerPut(nh, ©td, HEADERPUT_DEFAULT);
+ rpmtdFreeData(©td);
+ }
+
+ headerFreeIterator(hi);
+ headerFree(oh);
+ rpmtdFreeData(utd);
+
+ *hdrp = headerLink(nh);
+ headerFree(nh);
+ }
+}
+
+/**
+ * Include file signatures in header
+ * @param fd
+ * @param rpm path to package
+ * @param sigp pointer to signature header
+ * @param hdrp pointer to header
+ * @param sigStart signature offset in rpm
+ * @param headerStart header offset in rpm
+ */
+static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
+ Header *sigp, Header *hdrp,
+ off_t sigStart, off_t headerStart)
+{
+ FD_t ofd = NULL;
+ struct rpmtd_s td;
+ char *trpm = NULL;
+ const char *key;
+ char *SHA1 = NULL;
+ uint8_t *MD5 = NULL;
+ unsigned char buf[32*BUFSIZ];
+ size_t sha1len;
+ size_t md5len;
+ size_t headerSize;
+ off_t archiveSize;
+ rpmRC rc = RPMRC_OK;
+
+ unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE, &td);
+
+ 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"));
+ goto exit;
+ }
+
+ rc = signFiles(*hdrp, key);
+ if (rc != RPMRC_OK) {
+ rpmlog(RPMLOG_ERR, _("signFiles failed\n"));
+ 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);
+ headerSize = 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 (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 signature */
+ rc = generateSignature(SHA1, MD5, headerSize, archiveSize, fd);
+ if (rc != RPMRC_OK) {
+ rpmlog(RPMLOG_ERR, _("insertDigests 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;
+ }
+
+ rc = rpmReadSignature(fd, sigp, RPMSIGTYPE_HEADERSIG, NULL);
+ if (rc != RPMRC_OK) {
+ rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n"));
+ goto exit;
+ }
+
+exit:
+ return rc;
+}
+
/** \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, const char *passPhrase,
+ int signfiles)
{
FD_t fd = NULL;
FD_t ofd = NULL;
@@ -516,25 +793,15 @@ static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
goto exit;
}
- /* 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, ©td)) {
- if (copytd.data)
- headerPut(nh, ©td, HEADERPUT_DEFAULT);
- rpmtdFreeData(©td);
+ if (signfiles) {
+ rc = includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart);
+ if (rc != RPMRC_OK) {
+ rpmlog(RPMLOG_ERR, _("includeFileSignatures failed\n"));
+ goto exit;
}
- headerFreeIterator(hi);
- headerFree(oh);
- rpmtdFreeData(&utd);
-
- headerFree(sigh);
- sigh = headerLink(nh);
- headerFree(nh);
}
+
+ unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES, &utd);
origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
if (deleting) { /* Nuke all the signature tags. */
@@ -566,6 +833,7 @@ static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
/* 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;
@@ -668,7 +936,8 @@ exit:
}
int rpmPkgSign(const char *path,
- const struct rpmSignArgs * args, const char *passPhrase)
+ const struct rpmSignArgs * args, const char *passPhrase,
+ int signfiles)
{
int rc;
@@ -684,7 +953,7 @@ int rpmPkgSign(const char *path,
}
}
- rc = rpmSign(path, 0, passPhrase);
+ rc = rpmSign(path, 0, passPhrase, signfiles);
if (args) {
if (args->hashalgo) {
@@ -700,5 +969,5 @@ int rpmPkgSign(const char *path,
int rpmPkgDelSign(const char *path)
{
- return rpmSign(path, 1, NULL);
+ return rpmSign(path, 1, NULL, 0);
}
diff --git a/sign/rpmsign.h b/sign/rpmsign.h
index 15b3e0f..0ec37c1 100644
--- a/sign/rpmsign.h
+++ b/sign/rpmsign.h
@@ -11,6 +11,8 @@ extern "C" {
struct rpmSignArgs {
char *keyid;
pgpHashAlgo hashalgo;
+ int signFiles;
+ const char *fileSigningKey;
/* ... what else? */
};
@@ -19,10 +21,11 @@ struct rpmSignArgs {
* @param path path to package
* @param args signing parameters (or NULL for defaults)
* @param passPhrase passphrase for the signing key
+ * @param signfiles sign files if non-zero
* @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,
+ const char *passPhrase, int signfiles);
/** \ingroup rpmsign
* Delete signature(s) from a package
--
1.9.3
|
|
From: <fi...@li...> - 2014-10-07 20:20:23
|
From: Fionnuala Gunter <fi...@li...>
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 <fi...@li...>
---
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 <ma...@re...>
Jeff Johnson <jb...@re...>
Erik Troan <ew...@re...>
+Fionnuala Gunter <fi...@li...>
.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);
+ 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);
} 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
--
1.9.3
|
|
From: <fi...@li...> - 2014-10-07 20:20:23
|
From: Fionnuala Gunter <fi...@li...>
This patch creates a new rpm-plugin for IMA and extends the rpm installer.
When a package with signed files is installed, the file signatures are
extracted from the package header, and passed to the IMA plugin. The IMA
plugin labels the security.ima xattr with the file signature.
Signed-off-by: Fionnuala Gunter <fi...@li...>
---
lib/fsm.c | 23 ++++++++++++++-
macros.in | 1 +
plugins/Makefile.am | 4 +++
plugins/ima.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 110 insertions(+), 1 deletion(-)
create mode 100644 plugins/ima.c
diff --git a/lib/fsm.c b/lib/fsm.c
index e7c2a3b..dbeeaab 100644
--- a/lib/fsm.c
+++ b/lib/fsm.c
@@ -20,6 +20,7 @@
#include "lib/rpmte_internal.h" /* XXX rpmfs */
#include "lib/rpmplugins.h" /* rpm plugins hooks */
#include "lib/rpmug.h"
+#include "lib/rpmlib.h"
#include "debug.h"
@@ -823,12 +824,22 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
char *tid = NULL;
const char *suffix;
char *fpath = NULL;
+ Header h = rpmteHeader(te);
+ struct rpmtd_s sigs;
+ char *sig = NULL;
if (fi == NULL) {
rc = RPMERR_BAD_MAGIC;
goto exit;
}
+ if (h == NULL) {
+ rc = RPMRC_FAIL;
+ goto exit;
+ }
+
+ headerGet(h, RPMTAG_FILESIGNATURES, &sigs, HEADERGET_MINMEM);
+
/* transaction id used for temporary path suffix while installing */
rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
@@ -953,9 +964,17 @@ 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)) {
+ sig = rpmtdNextString(&sigs);
+ } else {
+ sig = NULL;
+ rpmtdNextString(&sigs);
+ }
+
/* Run fsm file post hook for all plugins */
rpmpluginsCallFsmFilePost(plugins, fi, fpath,
- sb.st_mode, action, NULL, rc);
+ sb.st_mode, action, sig, rc);
fpath = _free(fpath);
}
@@ -965,6 +984,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
exit:
/* No need to bother with close errors on read */
+ rpmtdFreeData(&sigs);
+ headerFree(h);
rpmfiArchiveClose(fi);
rpmfiFree(fi);
Fclose(payload);
diff --git a/macros.in b/macros.in
index 1647104..0b62991 100644
--- a/macros.in
+++ b/macros.in
@@ -1043,6 +1043,7 @@ done \
%__transaction_systemd_inhibit %{__plugindir}/systemd_inhibit.so
%__transaction_selinux %{__plugindir}/selinux.so
%__transaction_syslog %{__plugindir}/syslog.so
+%__transaction_ima %{__plugindir}/ima.so
#------------------------------------------------------------------------------
# Macros for further automated spec %setup and patch application
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
index 53b2450..18f6170 100644
--- a/plugins/Makefile.am
+++ b/plugins/Makefile.am
@@ -31,3 +31,7 @@ endif
syslog_la_SOURCES = syslog.c
syslog_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
plugins_LTLIBRARIES += syslog.la
+
+ima_la_sources = ima.c
+ima_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
+plugins_LTLIBRARIES += ima.la
diff --git a/plugins/ima.c b/plugins/ima.c
new file mode 100644
index 0000000..6b739db
--- /dev/null
+++ b/plugins/ima.c
@@ -0,0 +1,83 @@
+/**
+ * Copyright (C) 2014 IBM Corporation
+ *
+ * Author: Fionnuala Gunter <fi...@li...>
+ */
+#include <syslog.h>
+
+#include <sys/types.h>
+#include <sys/xattr.h>
+#include <rpm/rpmts.h>
+#include <rpm/rpmlog.h>
+#include <lib/rpmplugin.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include "debug.h"
+
+#define XATTR_NAME_IMA "security.ima"
+
+static int hex_to_bin(char ch)
+{
+ if ((ch >= '0') && (ch <= '9'))
+ return ch - '0';
+ ch = tolower(ch);
+ if ((ch >= 'a') && (ch <= 'f'))
+ return ch - 'a' + 10;
+ return -1;
+}
+
+static int hex2bin(char *dst, const char *src, size_t count)
+{
+ int hi, lo;
+
+ while (count--) {
+ if (*src == ' ')
+ src++;
+
+ hi = hex_to_bin(*src++);
+ lo = hex_to_bin(*src++);
+
+ if ((hi < 0) || (lo < 0))
+ return -1;
+
+ *dst++ = (hi << 4) | lo;
+ }
+ return 0;
+}
+
+static rpmRC ima_init(rpmPlugin plugin, rpmts ts)
+{
+ return RPMRC_OK;
+}
+
+static void ima_cleanup(rpmPlugin plugin)
+{
+}
+
+static rpmRC ima_fsm_file_post(rpmPlugin plugin, rpmfi fi, const char *path,
+ mode_t file_mode, rpmFsmOp op, const char *sig,
+ int res)
+{
+ rpmRC rc = RPMRC_OK;
+ if (sig == NULL) {
+ return rc;
+ }
+
+ int siglen = strlen(sig) + 1;
+ char bin[siglen/2];
+ hex2bin(bin, sig, siglen);
+ rc = lsetxattr(path, XATTR_NAME_IMA, bin, siglen/2, 0);
+
+ if (rpmIsDebug())
+ rpmlog(RPMLOG_DEBUG, "lsetxattr: (%s) %s\n",
+ path, (rc < 0 ? strerror(errno) : ""));
+
+ return rc;
+}
+
+struct rpmPluginHooks_s ima_hooks = {
+ .init = ima_init,
+ .cleanup = ima_cleanup,
+ .fsm_file_post = ima_fsm_file_post,
+};
--
1.9.3
|
|
From: Dmitry K. <dmi...@gm...> - 2014-10-10 13:14:24
|
Hi Fin, I will get some time now so I will review patches by Tuesday... Thanks, Dmitry On 7 October 2014 23:19, <fi...@li...> wrote: > From: Fionnuala Gunter <fi...@li...> > > The Linux kernel's ima-appraisal module verifies file signatures. The problem > with verifying digital signatures of files is how the files are signed in the > first place. In our current prototype, we sign all files after system > installation, but this doesn't handle ongoing updates. We propose that Linux > distributors sign all files as part of the normal package signing. RPM already > maintains hashes of all files in the rpm package, and this can be extended to > add file signatures. > > This patch set extends the rpm signing tool to include file signatures in > packages, and extends the rpm install tool to install file signatures. > > Changelog v2: > -support for inline signing of files > -command line option for file signing key > -included missing file > -fixed type in rpmDigestAlgo > > Changelog v3: > -split up patch > > Fionnuala Gunter (4): > Add file signature to fsm_file_post parameter list > Sign package files and include signatures in package header > Label ima xattr when signed files are installed > Sign package files during installation > > configure.ac | 8 ++ > doc/rpm.8 | 28 +++-- > doc/rpmsign.8 | 22 +++- > lib/Makefile.am | 3 +- > lib/fsm.c | 68 ++++++++++- > lib/poptI.c | 7 ++ > lib/rpmcli.h | 2 + > lib/rpminstall.c | 10 +- > lib/rpmplugin.h | 3 +- > lib/rpmplugins.c | 5 +- > lib/rpmplugins.h | 4 +- > lib/rpmsignfiles.c | 130 +++++++++++++++++++++ > lib/rpmsignfiles.h | 45 ++++++++ > lib/rpmtag.h | 1 + > lib/rpmts.c | 15 +++ > lib/rpmts.h | 15 +++ > lib/rpmts_internal.h | 2 + > macros.in | 1 + > plugins/Makefile.am | 4 + > plugins/ima.c | 83 ++++++++++++++ > rpmpopt.in | 1 + > rpmsign.c | 14 ++- > sign/rpmgensig.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++---- > sign/rpmsign.h | 7 +- > 24 files changed, 750 insertions(+), 47 deletions(-) > create mode 100644 lib/rpmsignfiles.c > create mode 100644 lib/rpmsignfiles.h > create mode 100644 plugins/ima.c > > -- > 1.9.3 > > > ------------------------------------------------------------------------------ > Meet PCI DSS 3.0 Compliance Requirements with EventLog Analyzer > Achieve PCI DSS 3.0 Compliant Status with Out-of-the-box PCI DSS Reports > Are you Audit-Ready for PCI DSS 3.0 Compliance? Download White paper > Comply to PCI DSS 3.0 Requirement 10 and 11.5 with EventLog Analyzer > http://pubads.g.doubleclick.net/gampad/clk?id=154622311&iu=/4140/ostg.clktrk > _______________________________________________ > Linux-ima-user mailing list > Lin...@li... > https://lists.sourceforge.net/lists/listinfo/linux-ima-user -- Thanks, Dmitry |
|
From: Mimi Z. <zo...@li...> - 2014-10-13 17:48:21
|
On Tue, 2014-10-07 at 15:19 -0500, fi...@li... wrote: > From: Fionnuala Gunter <fi...@li...> > > The Linux kernel's ima-appraisal module verifies file signatures. The problem > with verifying digital signatures of files is how the files are signed in the > first place. In our current prototype, we sign all files after system > installation, but this doesn't handle ongoing updates. We propose that Linux > distributors sign all files as part of the normal package signing. RPM already > maintains hashes of all files in the rpm package, and this can be extended to > add file signatures. > > This patch set extends the rpm signing tool to include file signatures in > packages, and extends the rpm install tool to install file signatures. Splitting up the patches like this looks a lot better! thanks, Mimi > Changelog v2: > -support for inline signing of files > -command line option for file signing key > -included missing file > -fixed type in rpmDigestAlgo > > Changelog v3: > -split up patch > > Fionnuala Gunter (4): > Add file signature to fsm_file_post parameter list > Sign package files and include signatures in package header > Label ima xattr when signed files are installed > Sign package files during installation > > configure.ac | 8 ++ > doc/rpm.8 | 28 +++-- > doc/rpmsign.8 | 22 +++- > lib/Makefile.am | 3 +- > lib/fsm.c | 68 ++++++++++- > lib/poptI.c | 7 ++ > lib/rpmcli.h | 2 + > lib/rpminstall.c | 10 +- > lib/rpmplugin.h | 3 +- > lib/rpmplugins.c | 5 +- > lib/rpmplugins.h | 4 +- > lib/rpmsignfiles.c | 130 +++++++++++++++++++++ > lib/rpmsignfiles.h | 45 ++++++++ > lib/rpmtag.h | 1 + > lib/rpmts.c | 15 +++ > lib/rpmts.h | 15 +++ > lib/rpmts_internal.h | 2 + > macros.in | 1 + > plugins/Makefile.am | 4 + > plugins/ima.c | 83 ++++++++++++++ > rpmpopt.in | 1 + > rpmsign.c | 14 ++- > sign/rpmgensig.c | 319 +++++++++++++++++++++++++++++++++++++++++++++++---- > sign/rpmsign.h | 7 +- > 24 files changed, 750 insertions(+), 47 deletions(-) > create mode 100644 lib/rpmsignfiles.c > create mode 100644 lib/rpmsignfiles.h > create mode 100644 plugins/ima.c > |
|
From: Dmitry K. <d.k...@sa...> - 2014-10-20 14:05:33
|
On 07/10/14 23:19, fi...@li... wrote:
> From: Fionnuala Gunter <fi...@li...>
>
> 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 <fi...@li...>
> ---
> 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 <ma...@re...>
> Jeff Johnson <jb...@re...>
> Erik Troan <ew...@re...>
> +Fionnuala Gunter <fi...@li...>
> .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
|
|
From: Fionnuala G. <fi...@li...> - 2014-10-20 15:53:03
|
>> - /* 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?
Hi,
The file signature list corresponds to the order of the file list, so
sig is the file signature for the file fpath.
Yes, the file list has an order. In build/files.c:genCpioListAndHeader
the file list sorted using qsort, and then a file digest list is
generated. The file signature list is generated from the file digest
list in lib/rpmsignfiles.c:signFiles.
Thanks,
Fin
>
>
> Thanks,
> Dmitry
|
|
From: Dmitry K. <d.k...@sa...> - 2014-10-22 09:05:30
|
On 07/10/14 23:19, fi...@li... wrote:
> From: Fionnuala Gunter <fi...@li...>
>
> This patch extends the existing rpm signing tool to also sign package files
> and include them in the package header. It defines a tag,
> RPMTAG_FILESIGNATURES, an RPM macro %_file_signing_key, and new options
> fskpath, and signfiles.
>
> rpm --addsign [--signfiles [--fskpath <file signing key>]] PACKAGE_FILE ...
>
> The new option to rpmsign signs all the file digests included in the
> package. When a package is signed with the new option, the file digests are
> signed with libimaevm and the key %file_signing_key. The resulting
> signatures are included in the package header as an RPMTAG_FILESIGNATURES
> tag. Since the header is modified, the SHA1 and MD5 header digests are
> recalculated and inserted in the signature header.
>
> After including file signatures, the package is signed normally.
>
> Signed-off-by: Fionnuala Gunter <fi...@li...>
> ---
> configure.ac | 8 ++
> doc/rpmsign.8 | 22 +++-
> lib/Makefile.am | 3 +-
> lib/rpmsignfiles.c | 130 ++++++++++++++++++++++
> lib/rpmsignfiles.h | 45 ++++++++
> lib/rpmtag.h | 1 +
> rpmpopt.in | 1 +
> rpmsign.c | 14 ++-
> sign/rpmgensig.c | 319 ++++++++++++++++++++++++++++++++++++++++++++++++-----
> sign/rpmsign.h | 7 +-
> 10 files changed, 520 insertions(+), 30 deletions(-)
> create mode 100644 lib/rpmsignfiles.c
> create mode 100644 lib/rpmsignfiles.h
>
> diff --git a/configure.ac b/configure.ac
> index cbb869f..21a6a95 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -658,6 +658,14 @@ AC_SUBST(WITH_SELINUX_LIB)
> AC_SUBST(WITH_SEMANAGE_LIB)
> AM_CONDITIONAL(SELINUX,[test "$with_selinux" = yes])
>
> +# libimaevm
> +with_iamevm=no
> +AC_ARG_WITH(imaevm, [AS_HELP_STRING([--with-imaevm],[build with imaevm support])])
> +if test "$with_imaevm" = yes ; then
> + AC_DEFINE(IMAEVM, 1, [Build with imaevm support?])
> + LIBS="$LIBS -limaevm"
> +fi
> +
> # libcap
> WITH_CAP_LIB=
> AC_ARG_WITH(cap, [AS_HELP_STRING([--with-cap],[build with capability support])],
> diff --git a/doc/rpmsign.8 b/doc/rpmsign.8
> index 53f2d70..b19f172 100644
> --- a/doc/rpmsign.8
> +++ b/doc/rpmsign.8
> @@ -2,11 +2,17 @@
> .SH NAME
> rpmsign \- RPM Package Signing
> .SH SYNOPSIS
> +.SS "SIGNING PACKAGES:"
> +.PP
>
> -\fBrpm\fR \fB--addsign|--resign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
> +\fBrpm\fR \fB--addsign|--resign\fR [\fBrpmsign-options\fR] \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
>
> \fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR
>
> +.SS "rpmsign-options"
> +.PP
> + \fB--fskpath \fIKEY\fB\fR] [\fB--signfiles\fR]
> +
> .SH DESCRIPTION
> .PP
> Both of the \fB--addsign\fR and \fB--resign\fR
> @@ -20,6 +26,19 @@ there is no difference in behavior currently.
> .PP
> Delete all signatures from each package \fIPACKAGE_FILE\fR given.
>
> +.SS "SIGN OPTIONS"
> +.PP
> +.TP
> +\fB--fskpath \fIKEY\fB\fR
> +Used with \fB--signfiles\fR, use file signing key \fIKEY\fR.
> +.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.
> +
> .SS "USING GPG TO SIGN PACKAGES"
> .PP
> In order to sign packages using GPG, \fBrpm\fR
> @@ -78,4 +97,5 @@ Marc Ewing <ma...@re...>
> Jeff Johnson <jb...@re...>
> Erik Troan <ew...@re...>
> Panu Matilainen <pma...@re...>
> +Fionnuala Gunter <fi...@li...>
> .fi
> diff --git a/lib/Makefile.am b/lib/Makefile.am
> index a65eb80..f80a47a 100644
> --- a/lib/Makefile.am
> +++ b/lib/Makefile.am
> @@ -38,7 +38,8 @@ librpm_la_SOURCES = \
> verify.c rpmlock.c rpmlock.h misc.h relocation.c \
> rpmscript.h rpmscript.c legacy.c \
> rpmchroot.c rpmchroot.h \
> - rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h
> + rpmplugins.c rpmplugins.h rpmplugin.h rpmug.c rpmug.h \
> + rpmsignfiles.c rpmsignfiles.h
>
> librpm_la_LDFLAGS = -version-info $(rpm_version_info)
>
> diff --git a/lib/rpmsignfiles.c b/lib/rpmsignfiles.c
> new file mode 100644
> index 0000000..9c33103
> --- /dev/null
> +++ b/lib/rpmsignfiles.c
> @@ -0,0 +1,130 @@
> +/**
> + * Copyright (C) 2014 IBM Corporation
> + *
> + * Author: Fionnuala Gunter <fi...@li...>
> + */
> +
> +#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 "lib/rpmsignfiles.h"
> +
> +static char *rpmDigestAlgo(uint32_t dalgo)
> +{
> + switch (dalgo) {
> + case 0:
> + case 1: return "md5";
> + case 2: return "sha1";
> + case 8: return "sha256";
> + case 9: return "sha384";
> + case 10: return "sha512";
> + default: return NULL;
> + }
> +}
This does not match kernel digest algo enumeration...
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/hash_info.h
http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/crypto/hash_info.c
I think you could define hash_algo_name structure as well instead of
using "switch"...
Actually hash_info.h is since 3.13 and Ubuntu has 3.13 now but there is
no /usr/include/linux/hash_info.h
Anyone has any ideas why is that?
- Dmitry
> +
> +char *getDigestAlgo(Header h)
> +{
> + struct rpmtd_s digalgo;
> + uint32_t *dalgo;
> + char *algo;
> +
> + headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM);
> + dalgo = rpmtdGetUint32(&digalgo);
> + if (!dalgo) {
> + rpmlog(RPMLOG_ERR, _("rpmtdGetUint32 failed\n"));
> + return NULL;
> + }
> + algo = rpmDigestAlgo(*dalgo);
> + return algo;
> +}
> +
> +int getDigestLength(Header h)
> +{
> + struct rpmtd_s digalgo;
> + uint32_t *dalgo;
> + int diglen;
> +
> + headerGet(h, RPMTAG_FILEDIGESTALGO, &digalgo, HEADERGET_MINMEM);
> + dalgo = rpmtdGetUint32(&digalgo);
> + if (!dalgo) {
> + rpmlog(RPMLOG_ERR, _("rpmtdGetUint32 failed\n"));
> + return -1;
> + }
> +
> + diglen = rpmDigestLength(*dalgo);
> + return diglen;
> +}
> +
> +char *signFile(const char *algo, const char *fdigest, int diglen, const char *key)
> +{
> + char *fsignature;
> + unsigned char digest[BUFSIZ];
> + unsigned char signature[BUFSIZ];
> + int siglen;
> +
> +#ifndef IMAEVM
> + rpmlog(RPMLOG_ERR, _("missing libimaevm\n"));
> + return NULL;
> +#endif
> +
> + /* convert file digest hex to binary */
> + memset(digest, 0, BUFSIZ);
> + for (int i = 0; i < diglen; ++i, fdigest += 2)
> + digest[i] = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
> +
> + /* prepare file signature */
> + memset(signature, 0, BUFSIZ);
> + signature[0] = '\x03';
> +
> + /* calculate file signature */
> + siglen = sign_hash(algo, digest, diglen, key, 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;
> +}
> +
> +rpmRC signFiles(Header h, const char *key)
> +{
> + struct rpmtd_s digests;
> + const char *algo;
> + const char *digest;
> + char *signature;
> + int diglen;
> +
> + algo = getDigestAlgo(h);
> + if (!algo) {
> + rpmlog(RPMLOG_ERR, _("getDigestAlgo failed\n"));
> + return RPMRC_FAIL;
> + }
> +
> + diglen = getDigestLength(h);
> + if (diglen < 0) {
> + rpmlog(RPMLOG_ERR, _("getDigestLength failed\n"));
> + return RPMRC_FAIL;
> + }
> +
> + headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);
> + while ((digest = rpmtdNextString(&digests))) {
> + signature = signFile(algo, digest, diglen, key);
> + if (!signature) {
> + rpmlog(RPMLOG_ERR, _("signFile failed\n"));
> + return RPMRC_FAIL;
> + }
> + if (!headerPutString(h, RPMTAG_FILESIGNATURES, signature)) {
> + rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
> + return RPMRC_FAIL;
> + }
> + }
> + return RPMRC_OK;
> +}
> diff --git a/lib/rpmsignfiles.h b/lib/rpmsignfiles.h
> new file mode 100644
> index 0000000..05459f0
> --- /dev/null
> +++ b/lib/rpmsignfiles.h
> @@ -0,0 +1,45 @@
> +#ifndef H_RPMSIGNFILES
> +#define H_RPMSIGNFILES
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif
> +
> +/**
> + * Get file digest algorithm from header
> + * @param header package header
> + * @return file digest algorithm
> + */
> +char *getDigestAlgo(Header h);
> +
> +/**
> + * Get file digest length from header
> + * @param header package header
> + * @return file digest length
> + */
> +int getDigestLength(Header h);
> +
> +/**
> + * Sign a file digest with libimaevm
> + * @param algo file digest algorithm
> + * @param fdigest file digest hex
> + * @param diglen digest length
> + * @param key file signing key
> + * @return file signature hex
> + */
> +char *signFile(const char *algo, const char *fdigest, int diglen,
> + const char *key);
> +
> +/**
> + * Sign file digests in header and store the signatures in header
> + * @param h package header
> + * @param key signing key
> + * @return RPMRC_OK on success
> + */
> +rpmRC signFiles(Header h, const char *key);
> +
> +#ifdef _cplusplus
> +}
> +#endif
> +
> +#endif /* H_RPMSIGNFILES */
> diff --git a/lib/rpmtag.h b/lib/rpmtag.h
> index 58b2479..bd6a36a 100644
> --- a/lib/rpmtag.h
> +++ b/lib/rpmtag.h
> @@ -329,6 +329,7 @@ typedef enum rpmTag_e {
> RPMTAG_SUPPLEMENTNEVRS = 5060, /* s[] extension */
> RPMTAG_ENHANCENEVRS = 5061, /* s[] extension */
> RPMTAG_ENCODING = 5062, /* s */
> + RPMTAG_FILESIGNATURES = 5063, /* s[] */
>
> RPMTAG_FIRSTFREE_TAG /*!< internal */
> } rpmTag;
> diff --git a/rpmpopt.in b/rpmpopt.in
> index 036ab4e..df5e2ec 100644
> --- a/rpmpopt.in
> +++ b/rpmpopt.in
> @@ -162,6 +162,7 @@ rpm alias --httpproxy --define '_httpproxy !#:+'
> rpm exec --addsign rpmsign --addsign
> rpm exec --delsign rpmsign --delsign
> rpm exec --resign rpmsign --resign
> +#rpm exec --signfiles rpmsign --signfiles
> rpm exec --checksig rpmkeys --checksig
> rpm exec -K rpmkeys --checksig
> rpm exec --import rpmkeys --import
> diff --git a/rpmsign.c b/rpmsign.c
> index b8e5598..a2692b9 100644
> --- a/rpmsign.c
> +++ b/rpmsign.c
> @@ -20,6 +20,9 @@ enum modes {
>
> static int mode = 0;
>
> +static int signfiles = 0;
> +static char * fileSigningKey = NULL;
> +
> static struct poptOption signOptsTable[] = {
> { "addsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_ADDSIGN,
> N_("sign package(s)"), NULL },
> @@ -27,6 +30,11 @@ static struct poptOption signOptsTable[] = {
> N_("sign package(s) (identical to --addsign)"), NULL },
> { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN,
> N_("delete package signatures"), NULL },
> + { "signfiles", '\0', POPT_ARG_NONE, &signfiles, 0,
> + N_("sign package(s) files"), NULL},
> + { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0,
> + N_("use file signing key <key>"),
> + N_("<key>") },
> POPT_TABLEEND
> };
>
> @@ -119,6 +127,10 @@ static int doSign(poptContext optCon)
> goto exit;
> }
>
> + if (fileSigningKey && signfiles) {
> + addMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL);
> + }
> +
> /* XXX FIXME: eliminate obsolete getpass() usage */
> passPhrase = getpass(_("Enter pass phrase: "));
> passPhrase = (passPhrase != NULL) ? rstrdup(passPhrase) : NULL;
> @@ -127,7 +139,7 @@ static int doSign(poptContext optCon)
> fprintf(stderr, _("Pass phrase is good.\n"));
> rc = 0;
> while ((arg = poptGetArg(optCon)) != NULL) {
> - rc += rpmPkgSign(arg, NULL, passPhrase);
> + rc += rpmPkgSign(arg, NULL, passPhrase, signfiles);
> }
> } else {
> fprintf(stderr, _("Pass phrase check failed or gpg key expired\n"));
> diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
> index 0bd14e3..f07c87e 100644
> --- a/sign/rpmgensig.c
> +++ b/sign/rpmgensig.c
> @@ -1,4 +1,10 @@
> -/** \ingroup rpmcli
> +/**
> + * Copyright (C) 2014 IBM Corporation
> + *
> + * Author: Fionnuala Gunter <fi...@li...>
> + * added support for file signatures
> + *
> + * \ingroup rpmcli
> * \file lib/rpmchecksig.c
> * Verify the signature of a package.
> */
> @@ -8,17 +14,23 @@
> #include <errno.h>
> #include <sys/wait.h>
> #include <popt.h>
> +#include <imaevm.h>
> +#include <ctype.h>
>
> #include <rpm/rpmlib.h> /* RPMSIGTAG & related */
> #include <rpm/rpmmacro.h>
> #include <rpm/rpmpgp.h>
> #include <rpm/rpmsign.h>
> -#include <rpm/rpmfileutil.h> /* rpmMkTemp() */
> +#include <rpm/rpmfileutil.h> /* rpmMkTemp() */
> #include <rpm/rpmlog.h>
> #include <rpm/rpmstring.h>
>
> #include "lib/rpmlead.h"
> #include "lib/signature.h"
> +#include "lib/header.h"
> +#include "lib/cpio.h" /* rpmcpioOpen, rpmcpioTell */
> +#include "lib/rpmsignfiles.h" /* signFiles */
> +#include "rpmio/rpmio_internal.h" /* fdInitDigest, fdFiniDigest */
>
> #include "debug.h"
>
> @@ -88,6 +100,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)
> @@ -121,8 +137,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;
> }
>
> @@ -458,14 +472,277 @@ static int replaceSignature(Header sigh, sigTarget sigt1, sigTarget sigt2,
> return rc;
> }
>
> +static rpmRC generateSignature(char *SHA1, uint8_t *MD5, rpm_loff_t size,
> + rpm_loff_t payloadSize, FD_t fd)
> +{
> + Header sig = NULL;
> + struct rpmtd_s td;
> + rpmTagVal sizetag;
> + rpmTagVal payloadtag;
> + rpm_tagtype_t typetag;
> + rpmRC rc = RPMRC_OK;
> + char *reservedSpace;
> + int spaceSize = 0;
> +
> + /* Prepare signature */
> + sig = rpmNewSignature();
> +
> + rpmtdReset(&td);
> + td.tag = RPMSIGTAG_SHA1;
> + td.count = 1;
> + td.type = RPM_STRING_TYPE;
> + td.data = SHA1;
> + headerPut(sig, &td, HEADERPUT_DEFAULT);
> +
> + rpmtdReset(&td);
> + td.tag = RPMSIGTAG_MD5;
> + td.count = 16;
> + td.type = RPM_BIN_TYPE;
> + td.data = MD5;
> + headerPut(sig, &td, HEADERPUT_DEFAULT);
> +
> + if (payloadSize < UINT32_MAX) {
> + sizetag = RPMSIGTAG_SIZE;
> + payloadtag = RPMSIGTAG_PAYLOADSIZE;
> + typetag = RPM_INT32_TYPE;
> + } else {
> + sizetag = RPMSIGTAG_LONGSIZE;
> + payloadtag = RPMSIGTAG_LONGARCHIVESIZE;
> + typetag = RPM_INT64_TYPE;
> + }
> +
> + rpmtdReset(&td);
> + td.tag = payloadtag;
> + td.count = 1;
> + td.type = typetag;
> + td.data = &payloadSize;
> + headerPut(sig, &td, HEADERPUT_DEFAULT);
> +
> + rpmtdReset(&td);
> + td.tag = sizetag;
> + td.count = 1;
> + td.type = typetag;
> + td.data = &size;
> + headerPut(sig, &td, HEADERPUT_DEFAULT);
> +
> + spaceSize = rpmExpandNumeric("%{__gpg_reserved_space}");
> + if(spaceSize > 0) {
> + reservedSpace = xcalloc(spaceSize, sizeof(char));
> + rpmtdReset(&td);
> + td.tag = RPMSIGTAG_RESERVEDSPACE;
> + td.count = spaceSize;
> + td.type = RPM_BIN_TYPE;
> + td.data = reservedSpace;
> + headerPut(sig, &td, HEADERPUT_DEFAULT);
> + free(reservedSpace);
> + }
> +
> + /* Reallocate the signature into one contiguous region. */
> + sig = headerReload(sig, RPMTAG_HEADERSIGNATURES);
> + if (sig == NULL) { /* XXX can't happen */
> + rpmlog(RPMLOG_ERR, _("Unable to reload signature header.\n"));
> + rc = RPMRC_FAIL;
> + goto exit;
> + }
> +
> + /* Write the signature section into the package. */
> + if (rpmWriteSignature(fd, sig)) {
> + rc = RPMRC_FAIL;
> + goto exit;
> + }
> +
> +exit:
> + rpmFreeSignature(sig);
> + return rc;
> +}
> +
> +static void unloadImmutableRegion(Header *hdrp, rpmTagVal tag, rpmtd utd)
> +{
> + struct rpmtd_s copytd;
> + Header nh;
> + Header oh;
> + HeaderIterator hi;
> +
> + if (headerGet(*hdrp, tag, utd, HEADERGET_DEFAULT)) {
> + nh = headerNew();
> + oh = headerCopyLoad(utd->data);
> + hi = headerInitIterator(oh);
> +
> + while (headerNext(hi, ©td)) {
> + if (copytd.data)
> + headerPut(nh, ©td, HEADERPUT_DEFAULT);
> + rpmtdFreeData(©td);
> + }
> +
> + headerFreeIterator(hi);
> + headerFree(oh);
> + rpmtdFreeData(utd);
> +
> + *hdrp = headerLink(nh);
> + headerFree(nh);
> + }
> +}
> +
> +/**
> + * Include file signatures in header
> + * @param fd
> + * @param rpm path to package
> + * @param sigp pointer to signature header
> + * @param hdrp pointer to header
> + * @param sigStart signature offset in rpm
> + * @param headerStart header offset in rpm
> + */
> +static rpmRC includeFileSignatures(FD_t fd, const char *rpm,
> + Header *sigp, Header *hdrp,
> + off_t sigStart, off_t headerStart)
> +{
> + FD_t ofd = NULL;
> + struct rpmtd_s td;
> + char *trpm = NULL;
> + const char *key;
> + char *SHA1 = NULL;
> + uint8_t *MD5 = NULL;
> + unsigned char buf[32*BUFSIZ];
> + size_t sha1len;
> + size_t md5len;
> + size_t headerSize;
> + off_t archiveSize;
> + rpmRC rc = RPMRC_OK;
> +
> + unloadImmutableRegion(hdrp, RPMTAG_HEADERIMMUTABLE, &td);
> +
> + 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"));
> + goto exit;
> + }
> +
> + rc = signFiles(*hdrp, key);
> + if (rc != RPMRC_OK) {
> + rpmlog(RPMLOG_ERR, _("signFiles failed\n"));
> + 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);
> + headerSize = 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 (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 signature */
> + rc = generateSignature(SHA1, MD5, headerSize, archiveSize, fd);
> + if (rc != RPMRC_OK) {
> + rpmlog(RPMLOG_ERR, _("insertDigests 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;
> + }
> +
> + rc = rpmReadSignature(fd, sigp, RPMSIGTYPE_HEADERSIG, NULL);
> + if (rc != RPMRC_OK) {
> + rpmlog(RPMLOG_ERR, _("rpmReadSignature failed\n"));
> + goto exit;
> + }
> +
> +exit:
> + return rc;
> +}
> +
> /** \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, const char *passPhrase,
> + int signfiles)
> {
> FD_t fd = NULL;
> FD_t ofd = NULL;
> @@ -516,25 +793,15 @@ static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
> goto exit;
> }
>
> - /* 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, ©td)) {
> - if (copytd.data)
> - headerPut(nh, ©td, HEADERPUT_DEFAULT);
> - rpmtdFreeData(©td);
> + if (signfiles) {
> + rc = includeFileSignatures(fd, rpm, &sigh, &h, sigStart, headerStart);
> + if (rc != RPMRC_OK) {
> + rpmlog(RPMLOG_ERR, _("includeFileSignatures failed\n"));
> + goto exit;
> }
> - headerFreeIterator(hi);
> - headerFree(oh);
> - rpmtdFreeData(&utd);
> -
> - headerFree(sigh);
> - sigh = headerLink(nh);
> - headerFree(nh);
> }
> +
> + unloadImmutableRegion(&sigh, RPMTAG_HEADERSIGNATURES, &utd);
> origSigSize = headerSizeof(sigh, HEADER_MAGIC_YES);
>
> if (deleting) { /* Nuke all the signature tags. */
> @@ -566,6 +833,7 @@ static int rpmSign(const char *rpm, int deleting, const char *passPhrase)
>
> /* 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;
> @@ -668,7 +936,8 @@ exit:
> }
>
> int rpmPkgSign(const char *path,
> - const struct rpmSignArgs * args, const char *passPhrase)
> + const struct rpmSignArgs * args, const char *passPhrase,
> + int signfiles)
> {
> int rc;
>
> @@ -684,7 +953,7 @@ int rpmPkgSign(const char *path,
> }
> }
>
> - rc = rpmSign(path, 0, passPhrase);
> + rc = rpmSign(path, 0, passPhrase, signfiles);
>
> if (args) {
> if (args->hashalgo) {
> @@ -700,5 +969,5 @@ int rpmPkgSign(const char *path,
>
> int rpmPkgDelSign(const char *path)
> {
> - return rpmSign(path, 1, NULL);
> + return rpmSign(path, 1, NULL, 0);
> }
> diff --git a/sign/rpmsign.h b/sign/rpmsign.h
> index 15b3e0f..0ec37c1 100644
> --- a/sign/rpmsign.h
> +++ b/sign/rpmsign.h
> @@ -11,6 +11,8 @@ extern "C" {
> struct rpmSignArgs {
> char *keyid;
> pgpHashAlgo hashalgo;
> + int signFiles;
> + const char *fileSigningKey;
> /* ... what else? */
> };
>
> @@ -19,10 +21,11 @@ struct rpmSignArgs {
> * @param path path to package
> * @param args signing parameters (or NULL for defaults)
> * @param passPhrase passphrase for the signing key
> + * @param signfiles sign files if non-zero
> * @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,
> + const char *passPhrase, int signfiles);
>
> /** \ingroup rpmsign
> * Delete signature(s) from a package
|
|
From: Fionnuala G. <fi...@li...> - 2014-10-22 18:37:21
|
>> diff --git a/lib/rpmsignfiles.c b/lib/rpmsignfiles.c
>> new file mode 100644
>> index 0000000..9c33103
>> --- /dev/null
>> +++ b/lib/rpmsignfiles.c
>> @@ -0,0 +1,130 @@
>> +/**
>> + * Copyright (C) 2014 IBM Corporation
>> + *
>> + * Author: Fionnuala Gunter <fi...@li...>
>> + */
>> +
>> +#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 "lib/rpmsignfiles.h"
>> +
>> +static char *rpmDigestAlgo(uint32_t dalgo)
>> +{
>> + switch (dalgo) {
>> + case 0:
>> + case 1: return "md5";
>> + case 2: return "sha1";
>> + case 8: return "sha256";
>> + case 9: return "sha384";
>> + case 10: return "sha512";
>> + default: return NULL;
>> + }
>> +}
>
> This does not match kernel digest algo enumeration...
>
I found the rpm digest algo enumeration in rpmio/rpmpgp.h
typedef enum pgpHashAlgo_e {
PGPHASHALGO_MD5 = 1, /*!< MD5 */
PGPHASHALGO_SHA1 = 2, /*!< SHA1 */
PGPHASHALGO_RIPEMD160 = 3, /*!< RIPEMD160 */
PGPHASHALGO_MD2 = 5, /*!< MD2 */
PGPHASHALGO_TIGER192 = 6, /*!< TIGER192 */
PGPHASHALGO_HAVAL_5_160 = 7, /*!< HAVAL-5-160 */
PGPHASHALGO_SHA256 = 8, /*!< SHA256 */
PGPHASHALGO_SHA384 = 9, /*!< SHA384 */
PGPHASHALGO_SHA512 = 10, /*!< SHA512 */
PGPHASHALGO_SHA224 = 11, /*!< SHA224 */
} pgpHashAlgo;
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/hash_info.h
> http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/crypto/hash_info.c
>
> I think you could define hash_algo_name structure as well instead of
> using "switch"...
>
Yes, I will get rid of the switch.
> Actually hash_info.h is since 3.13 and Ubuntu has 3.13 now but there is
> no /usr/include/linux/hash_info.h
> Anyone has any ideas why is that?
>
> - Dmitry
Thanks,
Fin
|
|
From: Dmitry K. <d.k...@sa...> - 2014-10-22 09:13:37
|
On 07/10/14 23:19, fi...@li... wrote:
> From: Fionnuala Gunter <fi...@li...>
>
> This patch creates a new rpm-plugin for IMA and extends the rpm installer.
> When a package with signed files is installed, the file signatures are
> extracted from the package header, and passed to the IMA plugin. The IMA
> plugin labels the security.ima xattr with the file signature.
>
> Signed-off-by: Fionnuala Gunter <fi...@li...>
> ---
> lib/fsm.c | 23 ++++++++++++++-
> macros.in | 1 +
> plugins/Makefile.am | 4 +++
> plugins/ima.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 110 insertions(+), 1 deletion(-)
> create mode 100644 plugins/ima.c
>
> diff --git a/lib/fsm.c b/lib/fsm.c
> index e7c2a3b..dbeeaab 100644
> --- a/lib/fsm.c
> +++ b/lib/fsm.c
> @@ -20,6 +20,7 @@
> #include "lib/rpmte_internal.h" /* XXX rpmfs */
> #include "lib/rpmplugins.h" /* rpm plugins hooks */
> #include "lib/rpmug.h"
> +#include "lib/rpmlib.h"
>
> #include "debug.h"
>
> @@ -823,12 +824,22 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
> char *tid = NULL;
> const char *suffix;
> char *fpath = NULL;
> + Header h = rpmteHeader(te);
> + struct rpmtd_s sigs;
> + char *sig = NULL;
>
> if (fi == NULL) {
> rc = RPMERR_BAD_MAGIC;
> goto exit;
> }
>
> + if (h == NULL) {
> + rc = RPMRC_FAIL;
> + goto exit;
> + }
> +
> + headerGet(h, RPMTAG_FILESIGNATURES, &sigs, HEADERGET_MINMEM);
> +
> /* transaction id used for temporary path suffix while installing */
> rasprintf(&tid, ";%08x", (unsigned)rpmtsGetTid(ts));
>
> @@ -953,9 +964,17 @@ 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)) {
> + sig = rpmtdNextString(&sigs);
What executable bit means?
> + } else {
> + sig = NULL;
> + rpmtdNextString(&sigs);
> + }
> +
> /* Run fsm file post hook for all plugins */
> rpmpluginsCallFsmFilePost(plugins, fi, fpath,
> - sb.st_mode, action, NULL, rc);
> + sb.st_mode, action, sig, rc);
> fpath = _free(fpath);
> }
>
> @@ -965,6 +984,8 @@ int rpmPackageFilesInstall(rpmts ts, rpmte te, rpmfiles files,
> exit:
>
> /* No need to bother with close errors on read */
> + rpmtdFreeData(&sigs);
> + headerFree(h);
> rpmfiArchiveClose(fi);
> rpmfiFree(fi);
> Fclose(payload);
> diff --git a/macros.in b/macros.in
> index 1647104..0b62991 100644
> --- a/macros.in
> +++ b/macros.in
> @@ -1043,6 +1043,7 @@ done \
> %__transaction_systemd_inhibit %{__plugindir}/systemd_inhibit.so
> %__transaction_selinux %{__plugindir}/selinux.so
> %__transaction_syslog %{__plugindir}/syslog.so
> +%__transaction_ima %{__plugindir}/ima.so
>
> #------------------------------------------------------------------------------
> # Macros for further automated spec %setup and patch application
> diff --git a/plugins/Makefile.am b/plugins/Makefile.am
> index 53b2450..18f6170 100644
> --- a/plugins/Makefile.am
> +++ b/plugins/Makefile.am
> @@ -31,3 +31,7 @@ endif
> syslog_la_SOURCES = syslog.c
> syslog_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
> plugins_LTLIBRARIES += syslog.la
> +
> +ima_la_sources = ima.c
> +ima_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la
> +plugins_LTLIBRARIES += ima.la
> diff --git a/plugins/ima.c b/plugins/ima.c
> new file mode 100644
> index 0000000..6b739db
> --- /dev/null
> +++ b/plugins/ima.c
> @@ -0,0 +1,83 @@
> +/**
> + * Copyright (C) 2014 IBM Corporation
> + *
> + * Author: Fionnuala Gunter <fi...@li...>
> + */
> +#include <syslog.h>
> +
> +#include <sys/types.h>
> +#include <sys/xattr.h>
> +#include <rpm/rpmts.h>
> +#include <rpm/rpmlog.h>
> +#include <lib/rpmplugin.h>
> +#include <errno.h>
> +#include <ctype.h>
> +
> +#include "debug.h"
> +
> +#define XATTR_NAME_IMA "security.ima"
> +
> +static int hex_to_bin(char ch)
> +{
> + if ((ch >= '0') && (ch <= '9'))
> + return ch - '0';
> + ch = tolower(ch);
> + if ((ch >= 'a') && (ch <= 'f'))
> + return ch - 'a' + 10;
> + return -1;
> +}
> +
> +static int hex2bin(char *dst, const char *src, size_t count)
> +{
Does not RPM has any hex conversion facilities yet?
It has digests. Does not it uses it somehow?
- Dmitry
> + int hi, lo;
> +
> + while (count--) {
> + if (*src == ' ')
> + src++;
> +
> + hi = hex_to_bin(*src++);
> + lo = hex_to_bin(*src++);
> +
> + if ((hi < 0) || (lo < 0))
> + return -1;
> +
> + *dst++ = (hi << 4) | lo;
> + }
> + return 0;
> +}
> +
> +static rpmRC ima_init(rpmPlugin plugin, rpmts ts)
> +{
> + return RPMRC_OK;
> +}
> +
> +static void ima_cleanup(rpmPlugin plugin)
> +{
> +}
> +
> +static rpmRC ima_fsm_file_post(rpmPlugin plugin, rpmfi fi, const char *path,
> + mode_t file_mode, rpmFsmOp op, const char *sig,
> + int res)
> +{
> + rpmRC rc = RPMRC_OK;
> + if (sig == NULL) {
> + return rc;
> + }
> +
> + int siglen = strlen(sig) + 1;
> + char bin[siglen/2];
> + hex2bin(bin, sig, siglen);
> + rc = lsetxattr(path, XATTR_NAME_IMA, bin, siglen/2, 0);
> +
> + if (rpmIsDebug())
> + rpmlog(RPMLOG_DEBUG, "lsetxattr: (%s) %s\n",
> + path, (rc < 0 ? strerror(errno) : ""));
> +
> + return rc;
> +}
> +
> +struct rpmPluginHooks_s ima_hooks = {
> + .init = ima_init,
> + .cleanup = ima_cleanup,
> + .fsm_file_post = ima_fsm_file_post,
> +};
|
|
From: Fionnuala G. <fi...@li...> - 2014-10-22 18:48:23
|
>> @@ -953,9 +964,17 @@ 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)) {
>> + sig = rpmtdNextString(&sigs);
>
> What executable bit means?
I already replied to your comments on 4/4, but maybe this filtering of
executable files is unnecessary.
>> diff --git a/plugins/ima.c b/plugins/ima.c
>> new file mode 100644
>> index 0000000..6b739db
>> --- /dev/null
>> +++ b/plugins/ima.c
>> @@ -0,0 +1,83 @@
>> +/**
>> + * Copyright (C) 2014 IBM Corporation
>> + *
>> + * Author: Fionnuala Gunter <fi...@li...>
>> + */
>> +#include <syslog.h>
>> +
>> +#include <sys/types.h>
>> +#include <sys/xattr.h>
>> +#include <rpm/rpmts.h>
>> +#include <rpm/rpmlog.h>
>> +#include <lib/rpmplugin.h>
>> +#include <errno.h>
>> +#include <ctype.h>
>> +
>> +#include "debug.h"
>> +
>> +#define XATTR_NAME_IMA "security.ima"
>> +
>> +static int hex_to_bin(char ch)
>> +{
>> + if ((ch >= '0') && (ch <= '9'))
>> + return ch - '0';
>> + ch = tolower(ch);
>> + if ((ch >= 'a') && (ch <= 'f'))
>> + return ch - 'a' + 10;
>> + return -1;
>> +}
>> +
>> +static int hex2bin(char *dst, const char *src, size_t count)
>> +{
>
> Does not RPM has any hex conversion facilities yet?
> It has digests. Does not it uses it somehow?
>
Good point, I will check before resubmitting.
> - Dmitry
>
Thanks,
Fin
>> + int hi, lo;
>> +
>> + while (count--) {
>> + if (*src == ' ')
>> + src++;
>> +
>> + hi = hex_to_bin(*src++);
>> + lo = hex_to_bin(*src++);
>> +
>> + if ((hi < 0) || (lo < 0))
>> + return -1;
>> +
>> + *dst++ = (hi << 4) | lo;
>> + }
>> + return 0;
>> +}
>> +
>> +static rpmRC ima_init(rpmPlugin plugin, rpmts ts)
>> +{
>> + return RPMRC_OK;
>> +}
>> +
>> +static void ima_cleanup(rpmPlugin plugin)
>> +{
>> +}
>> +
>> +static rpmRC ima_fsm_file_post(rpmPlugin plugin, rpmfi fi, const char *path,
>> + mode_t file_mode, rpmFsmOp op, const char *sig,
>> + int res)
>> +{
>> + rpmRC rc = RPMRC_OK;
>> + if (sig == NULL) {
>> + return rc;
>> + }
>> +
>> + int siglen = strlen(sig) + 1;
>> + char bin[siglen/2];
>> + hex2bin(bin, sig, siglen);
>> + rc = lsetxattr(path, XATTR_NAME_IMA, bin, siglen/2, 0);
>> +
>> + if (rpmIsDebug())
>> + rpmlog(RPMLOG_DEBUG, "lsetxattr: (%s) %s\n",
>> + path, (rc < 0 ? strerror(errno) : ""));
>> +
>> + return rc;
>> +}
>> +
>> +struct rpmPluginHooks_s ima_hooks = {
>> + .init = ima_init,
>> + .cleanup = ima_cleanup,
>> + .fsm_file_post = ima_fsm_file_post,
>> +};
>
|
|
From: Dmitry K. <d.k...@sa...> - 2014-10-22 09:16:10
|
On 07/10/14 23:19, fi...@li... wrote:
> From: Fionnuala Gunter <fi...@li...>
>
> 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 <fi...@li...>
> ---
> 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 <ma...@re...>
> Jeff Johnson <jb...@re...>
> Erik Troan <ew...@re...>
> +Fionnuala Gunter <fi...@li...>
> .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);
Why do you sign only executables?
> + 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);
Also here... It only sets signature for executables??
- 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
|
|
From: Fionnuala G. <fi...@li...> - 2014-10-22 18:42:55
|
>> @@ -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);
>
> Why do you sign only executables?
>
>> + 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);
>
> Also here... It only sets signature for executables??
Right, I only set signatures for executables, should I set signatures
for all files?
>
> - Dmitry
Thanks,
Fin
|
|
From: Dmitry K. <d.k...@sa...> - 2014-10-23 07:24:53
|
On 22/10/14 21:42, Fionnuala Gunter wrote:
>>> @@ -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);
>> Why do you sign only executables?
>>
>>> + 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);
>> Also here... It only sets signature for executables??
> Right, I only set signatures for executables, should I set signatures
> for all files?
>> - Dmitry
I understand that it was a safe bet that binaries can always has signature.
What about libraries or may be some important configuration file which
would have signature..
Files which can be modified should not have a signature.
Signatures should be set for all files in the package which has a signature.
Package maintainer should be able to select what files to sign or not
to sign...
I think it has to be addressed before it can be really used.
- Dmitry
> Thanks,
> Fin
>
>
|
|
From: Dmitry K. <d.k...@sa...> - 2014-10-23 07:30:42
|
On 22/10/14 21:48, Fionnuala Gunter wrote:
>>> @@ -953,9 +964,17 @@ 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)) {
>>> + sig = rpmtdNextString(&sigs);
>> What executable bit means?
> I already replied to your comments on 4/4, but maybe this filtering of
> executable files is unnecessary.
(replied to this as well because first one did not go to the list.. now
I subscribed)
I understand that it was a safe bet that binaries can always has signature.
What about libraries or may be some important configuration file which
would have signature..
Files which can be modified should not have a signature.
Signatures should be set for all files in the package which has a signature.
Package maintainer should be able to select what files to sign or not
to sign...
I think it has to be addressed before it can be really used.
- Dmitry
>>> diff --git a/plugins/ima.c b/plugins/ima.c
>>> new file mode 100644
>>> index 0000000..6b739db
>>> --- /dev/null
>>> +++ b/plugins/ima.c
>>> @@ -0,0 +1,83 @@
>>> +/**
>>> + * Copyright (C) 2014 IBM Corporation
>>> + *
>>> + * Author: Fionnuala Gunter <fi...@li...>
>>> + */
>>> +#include <syslog.h>
>>> +
>>> +#include <sys/types.h>
>>> +#include <sys/xattr.h>
>>> +#include <rpm/rpmts.h>
>>> +#include <rpm/rpmlog.h>
>>> +#include <lib/rpmplugin.h>
>>> +#include <errno.h>
>>> +#include <ctype.h>
>>> +
>>> +#include "debug.h"
>>> +
>>> +#define XATTR_NAME_IMA "security.ima"
>>> +
>>> +static int hex_to_bin(char ch)
>>> +{
>>> + if ((ch >= '0') && (ch <= '9'))
>>> + return ch - '0';
>>> + ch = tolower(ch);
>>> + if ((ch >= 'a') && (ch <= 'f'))
>>> + return ch - 'a' + 10;
>>> + return -1;
>>> +}
>>> +
>>> +static int hex2bin(char *dst, const char *src, size_t count)
>>> +{
>> Does not RPM has any hex conversion facilities yet?
>> It has digests. Does not it uses it somehow?
>>
> Good point, I will check before resubmitting.
>> - Dmitry
>>
> Thanks,
> Fin
>>> + int hi, lo;
>>> +
>>> + while (count--) {
>>> + if (*src == ' ')
>>> + src++;
>>> +
>>> + hi = hex_to_bin(*src++);
>>> + lo = hex_to_bin(*src++);
>>> +
>>> + if ((hi < 0) || (lo < 0))
>>> + return -1;
>>> +
>>> + *dst++ = (hi << 4) | lo;
>>> + }
>>> + return 0;
>>> +}
>>> +
>>> +static rpmRC ima_init(rpmPlugin plugin, rpmts ts)
>>> +{
>>> + return RPMRC_OK;
>>> +}
>>> +
>>> +static void ima_cleanup(rpmPlugin plugin)
>>> +{
>>> +}
>>> +
>>> +static rpmRC ima_fsm_file_post(rpmPlugin plugin, rpmfi fi, const char *path,
>>> + mode_t file_mode, rpmFsmOp op, const char *sig,
>>> + int res)
>>> +{
>>> + rpmRC rc = RPMRC_OK;
>>> + if (sig == NULL) {
>>> + return rc;
>>> + }
>>> +
>>> + int siglen = strlen(sig) + 1;
>>> + char bin[siglen/2];
>>> + hex2bin(bin, sig, siglen);
>>> + rc = lsetxattr(path, XATTR_NAME_IMA, bin, siglen/2, 0);
>>> +
>>> + if (rpmIsDebug())
>>> + rpmlog(RPMLOG_DEBUG, "lsetxattr: (%s) %s\n",
>>> + path, (rc < 0 ? strerror(errno) : ""));
>>> +
>>> + return rc;
>>> +}
>>> +
>>> +struct rpmPluginHooks_s ima_hooks = {
>>> + .init = ima_init,
>>> + .cleanup = ima_cleanup,
>>> + .fsm_file_post = ima_fsm_file_post,
>>> +};
>
|
|
From: Fionnuala G. <fi...@li...> - 2014-10-23 16:40:07
|
On 10/23/2014 02:24 AM, Dmitry Kasatkin wrote:
> On 22/10/14 21:42, Fionnuala Gunter wrote:
>>>> @@ -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);
>>> Why do you sign only executables?
>>>
>>>> + 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);
>>> Also here... It only sets signature for executables??
>> Right, I only set signatures for executables, should I set signatures
>> for all files?
>>> - Dmitry
>
> I understand that it was a safe bet that binaries can always has signature.
> What about libraries or may be some important configuration file which
> would have signature..
> Files which can be modified should not have a signature.
>
> Signatures should be set for all files in the package which has a signature.
> Package maintainer should be able to select what files to sign or not
> to sign...
>
> I think it has to be addressed before it can be really used.
This is a good point, so the files needing signatures should be
enumerated by the package maintainer. Perhaps this can be done in the
rpm spec.
-Fin
>
> - Dmitry
>
>
>> Thanks,
>> Fin
>>
>>
>
|
|
From: Dmitry K. <dmi...@gm...> - 2014-10-23 17:09:27
|
On 23 October 2014 19:34, Fionnuala Gunter <fi...@li...> wrote:
>
>
> On 10/23/2014 02:24 AM, Dmitry Kasatkin wrote:
>> On 22/10/14 21:42, Fionnuala Gunter wrote:
>>>>> @@ -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);
>>>> Why do you sign only executables?
>>>>
>>>>> + 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);
>>>> Also here... It only sets signature for executables??
>>> Right, I only set signatures for executables, should I set signatures
>>> for all files?
>>>> - Dmitry
>>
>> I understand that it was a safe bet that binaries can always has signature.
>> What about libraries or may be some important configuration file which
>> would have signature..
>> Files which can be modified should not have a signature.
>>
>> Signatures should be set for all files in the package which has a signature.
>> Package maintainer should be able to select what files to sign or not
>> to sign...
>>
>> I think it has to be addressed before it can be really used.
> This is a good point, so the files needing signatures should be
> enumerated by the package maintainer. Perhaps this can be done in the
> rpm spec.
>
> -Fin
>>
Yes, something like that..
I am not an expert in package managers, but if I take a code snippet from
ima-evm-utils.spec, then there rules to specify files to include to the package,
like:
%files
%defattr(-,root,root,-)
%{_bindir}/*
%{_libdir}/libimaevm.*
%{_includedir}/*
There should be some way to specify it what should be signed, for example
%sign
%{_etcdir}/path/to/config
%{_bindir}/*
But may be RPM maintainers might comment...
Thanks,
Dmitry
>> - Dmitry
>>
>>
>>> Thanks,
>>> Fin
>>>
>>>
>>
>
> _______________________________________________
> Rpm-maint mailing list
> Rpm...@li...
> http://lists.rpm.org/mailman/listinfo/rpm-maint
--
Thanks,
Dmitry
|
|
From: Fionnuala G. <fi...@li...> - 2014-10-23 21:56:36
|
On 10/23/2014 12:09 PM, Dmitry Kasatkin wrote:
> On 23 October 2014 19:34, Fionnuala Gunter <fi...@li...> wrote:
>>
>>
>> On 10/23/2014 02:24 AM, Dmitry Kasatkin wrote:
>>> On 22/10/14 21:42, Fionnuala Gunter wrote:
>>>>>> @@ -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);
>>>>> Why do you sign only executables?
>>>>>
>>>>>> + 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);
>>>>> Also here... It only sets signature for executables??
>>>> Right, I only set signatures for executables, should I set signatures
>>>> for all files?
>>>>> - Dmitry
>>>
>>> I understand that it was a safe bet that binaries can always has signature.
>>> What about libraries or may be some important configuration file which
>>> would have signature..
>>> Files which can be modified should not have a signature.
>>>
>>> Signatures should be set for all files in the package which has a signature.
>>> Package maintainer should be able to select what files to sign or not
>>> to sign...
>>>
>>> I think it has to be addressed before it can be really used.
>> This is a good point, so the files needing signatures should be
>> enumerated by the package maintainer. Perhaps this can be done in the
>> rpm spec.
>>
>> -Fin
>>>
>
> Yes, something like that..
>
> I am not an expert in package managers, but if I take a code snippet from
> ima-evm-utils.spec, then there rules to specify files to include to the package,
> like:
>
> %files
> %defattr(-,root,root,-)
> %{_bindir}/*
> %{_libdir}/libimaevm.*
> %{_includedir}/*
>
> There should be some way to specify it what should be signed, for example
>
> %sign
> %{_etcdir}/path/to/config
> %{_bindir}/*
>
Yes, this is what I had in mind.
>
> But may be RPM maintainers might comment...
>
> Thanks,
> Dmitry
>
>>> - Dmitry
>>>
>>>
>>>> Thanks,
>>>> Fin
>>>>
>>>>
>>>
>>
>> _______________________________________________
>> Rpm-maint mailing list
>> Rpm...@li...
>> http://lists.rpm.org/mailman/listinfo/rpm-maint
>
>
>
|