[Rpm-maint] [PATCH v7 07/11] Sign file digests and store signatures in header

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


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

This patch introduces rpmSignFiles, which extracts file digests from
the provided header and signs them using libimaevm and the provided key.
The file signatures are stored in the header as hex strings under the
tag RPM_FILESIGNATURES.

Changelog:
- fix signatureLength() - Mimi
- remove existing file signatures and the file signature length, before
adding new file signatures. - Mimi
- fix dependency on ima - Fin
---
 lib/Makefile.am    |   4 ++
 lib/rpmsignfiles.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/rpmsignfiles.h |  20 +++++++++
 3 files changed, 150 insertions(+)
 create mode 100644 lib/rpmsignfiles.c
 create mode 100644 lib/rpmsignfiles.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
index 01e323c..e0d4a47 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -49,6 +49,10 @@ librpm_la_LIBADD = \
 	@WITH_ACL_LIB@ \
 	@LIBINTL@
 
+if WITH_IMAEVM
+librpm_la_SOURCES += rpmsignfiles.c rpmsignfiles.h
+endif
+
 if WITH_LUA
 AM_CPPFLAGS += @LUA_CFLAGS@
 librpm_la_LIBADD += @LUA_LIBS@
diff --git a/lib/rpmsignfiles.c b/lib/rpmsignfiles.c
new file mode 100644
index 0000000..376f47e
--- /dev/null
+++ b/lib/rpmsignfiles.c
@@ -0,0 +1,126 @@
+/**
+ * Copyright (C) 2014 IBM Corporation
+ *
+ * Author: Fionnuala Gunter <fin at linux.vnet.ibm.com>
+ */
+
+#include "system.h"
+#include "imaevm.h"
+
+#include <rpm/rpmlog.h>		/* rpmlog */
+#include <rpm/rpmstring.h>	/* rnibble */
+#include <rpm/rpmpgp.h>		/* rpmDigestLength */
+#include "lib/header.h"		/* HEADERGET_MINMEM */
+#include "lib/rpmtypes.h"	/* rpmRC */
+
+#include "lib/rpmsignfiles.h"
+
+#define MAX_SIGNATURE_LENGTH 1024
+
+static const char *hash_algo_name[] = {
+    [PGPHASHALGO_MD5]          = "md5",
+    [PGPHASHALGO_SHA1]         = "sha1",
+    [PGPHASHALGO_RIPEMD160]    = "rmd160",
+    [PGPHASHALGO_MD2]          = "md2",
+    [PGPHASHALGO_TIGER192]     = "tgr192",
+    [PGPHASHALGO_HAVAL_5_160]  = "haval5160",
+    [PGPHASHALGO_SHA256]       = "sha256",
+    [PGPHASHALGO_SHA384]       = "sha384",
+    [PGPHASHALGO_SHA512]       = "sha512",
+    [PGPHASHALGO_SHA224]       = "sha224",
+};
+
+static char *signFile(const char *algo, const char *fdigest, int diglen, const char *key)
+{
+   char *fsignature;
+   unsigned char digest[diglen];
+   unsigned char signature[MAX_SIGNATURE_LENGTH];
+   int siglen;
+
+#ifndef IMAEVM
+    rpmlog(RPMLOG_ERR, _("missing libimaevm\n"));
+    return NULL;
+#endif
+
+   /* convert file digest hex to binary */
+   memset(digest, 0, diglen);
+   for (int i = 0; i < diglen; ++i, fdigest += 2)
+        digest[i] = (rnibble(fdigest[0]) << 4) | rnibble(fdigest[1]);
+
+   /* prepare file signature */
+   memset(signature, 0, MAX_SIGNATURE_LENGTH);
+   signature[0] = '\x03';
+
+   /* calculate file signature */
+   siglen = sign_hash(algo, digest, diglen, key, signature+1);
+   if (siglen < 0) {
+        rpmlog(RPMLOG_ERR, _("sign_hash failed\n"));
+        return NULL;
+   }
+
+   /* convert file signature binary to hex */
+   fsignature = pgpHexStr(signature, siglen+1);
+   return fsignature;
+}
+
+static uint32_t signatureLength(const char *algo, int diglen, const char *key)
+{
+    unsigned char digest[diglen];
+    unsigned char signature[MAX_SIGNATURE_LENGTH];
+
+    memset(digest, 0, diglen);
+    memset(signature, 0, MAX_SIGNATURE_LENGTH);
+    signature[0] = '\x03';
+
+    uint32_t siglen = sign_hash(algo, digest, diglen, key, signature+1);
+    return siglen + 1;
+}
+
+rpmRC rpmSignFiles(Header h, const char *key)
+{
+    struct rpmtd_s digests;
+    int algo;
+    int diglen;
+    uint32_t siglen;
+    const char *algoname;
+    const char *digest;
+    char *signature;
+    rpmRC rc = RPMRC_OK;
+
+    algo = headerGetNumber(h, RPMTAG_FILEDIGESTALGO);
+    if (!algo) {
+	rpmlog(RPMLOG_ERR, _("missing RPMTAG_FILEDIGESTALGO\n"));
+	return RPMRC_FAIL;
+    }
+
+    diglen = rpmDigestLength(algo);
+    algoname = hash_algo_name[algo];
+    if (!algoname) {
+	rpmlog(RPMLOG_ERR, _("hash_algo_name failed\n"));
+	return RPMRC_FAIL;
+    }
+
+    headerDel(h, RPMTAG_FILESIGNATURELENGTH);
+    headerDel(h, RPMTAG_FILESIGNATURES);
+    siglen = signatureLength(algoname, diglen, key);
+    headerPutUint32(h, RPMTAG_FILESIGNATURELENGTH, &siglen, 1);
+
+    headerGet(h, RPMTAG_FILEDIGESTS, &digests, HEADERGET_MINMEM);
+    while ((digest = rpmtdNextString(&digests))) {
+        signature = signFile(algoname, digest, diglen, key);
+        if (!signature) {
+            rpmlog(RPMLOG_ERR, _("signFile failed\n"));
+            rc = RPMRC_FAIL;
+	    goto exit;
+        }
+        if (!headerPutString(h, RPMTAG_FILESIGNATURES, signature)) {
+            rpmlog(RPMLOG_ERR, _("headerPutString failed\n"));
+            rc = RPMRC_FAIL;
+	    goto exit;
+        }
+    }
+
+exit:
+    rpmtdFreeData(&digests);
+    return rc;
+}
diff --git a/lib/rpmsignfiles.h b/lib/rpmsignfiles.h
new file mode 100644
index 0000000..70a5b9f
--- /dev/null
+++ b/lib/rpmsignfiles.h
@@ -0,0 +1,20 @@
+#ifndef H_RPMSIGNFILES
+#define H_RPMSIGNFILES
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * 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 rpmSignFiles(Header h, const char *key);
+
+#ifdef _cplusplus
+}
+#endif
+
+#endif /* H_RPMSIGNFILES */
-- 
2.4.3



More information about the Rpm-maint mailing list