Sign file digests and store signatures in header

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

[lkardos@redhat.com: fixed indentation]
Signed-off-by: Lubos Kardos <lkardos@redhat.com>
This commit is contained in:
fin@linux.vnet.ibm.com 2015-07-21 12:00:41 -05:00 committed by Lubos Kardos
parent 12e5e52242
commit b07c13e5ca
3 changed files with 150 additions and 0 deletions

View File

@ -50,6 +50,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@

126
lib/rpmsignfiles.c Normal file
View File

@ -0,0 +1,126 @@
/**
* Copyright (C) 2014 IBM Corporation
*
* Author: Fionnuala Gunter <fin@linux.vnet.ibm.com>
*/
#include "system.h"
#include "imaevm.h"
#include <rpm/rpmlog.h> /* rpmlog */
#include <rpm/rpmstring.h> /* rnibble */
#include <rpm/rpmpgp.h> /* rpmDigestLength */
#include "lib/header.h" /* HEADERGET_MINMEM */
#include "lib/rpmtypes.h" /* rpmRC */
#include "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;
}

20
lib/rpmsignfiles.h Normal file
View File

@ -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 */