[Rpm-maint] [RFC v4 09/11] Sign file digests and store signatures in header

fin at linux.vnet.ibm.com fin at linux.vnet.ibm.com
Tue Jan 13 18:33:12 UTC 2015


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.

Signed-off-by: Fionnuala Gunter <fin at linux.vnet.ibm.com>
---
 lib/Makefile.am    |   3 +-
 lib/rpmsignfiles.c | 118 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/rpmsignfiles.h |  20 +++++++++
 3 files changed, 140 insertions(+), 1 deletion(-)
 create mode 100644 lib/rpmsignfiles.c
 create mode 100644 lib/rpmsignfiles.h

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..1c31757
--- /dev/null
+++ b/lib/rpmsignfiles.c
@@ -0,0 +1,118 @@
+/**
+ * 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;
+}
+
+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;
+
+    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;
+    }
+
+    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"));
+            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..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 */
-- 
1.9.3



More information about the Rpm-maint mailing list