From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Thu, 9 Apr 2020 12:58:17 -0400 Subject: [PATCH 21/33] rpmsignverity: Add verity signature headers to the package This adds the array of verity signatures, and a signature length header. We use 4K block for the Merkle tree, and rely on the kernel doing the right thing. Signed-off-by: Jes Sorensen --- lib/rpmtag.h | 6 ++- sign/rpmsignverity.c | 112 +++++++++++++++++++++++++++++-------------- sign/rpmsignverity.h | 7 +++ 3 files changed, 87 insertions(+), 38 deletions(-) diff --git a/lib/rpmtag.h b/lib/rpmtag.h index 40ff5fa5d..478457ecb 100644 --- a/lib/rpmtag.h +++ b/lib/rpmtag.h @@ -67,6 +67,7 @@ typedef enum rpmTag_e { RPMTAG_SHA256HEADER = RPMTAG_SIG_BASE+17, /* s */ /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */ /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */ + RPMTAG_VERITYSIGNATURES = RPMTAG_SIG_BASE+20, /* s[] */ RPMTAG_NAME = 1000, /* s */ #define RPMTAG_N RPMTAG_NAME /* s */ @@ -427,8 +428,9 @@ typedef enum rpmSigTag_e { RPMSIGTAG_LONGSIZE = RPMTAG_LONGSIGSIZE, /*!< internal Header+Payload size (64bit) in bytes. */ RPMSIGTAG_LONGARCHIVESIZE = RPMTAG_LONGARCHIVESIZE, /*!< internal uncompressed payload size (64bit) in bytes. */ RPMSIGTAG_SHA256 = RPMTAG_SHA256HEADER, - RPMSIGTAG_FILESIGNATURES = RPMTAG_SIG_BASE + 18, - RPMSIGTAG_FILESIGNATURELENGTH = RPMTAG_SIG_BASE + 19, + RPMSIGTAG_FILESIGNATURES = RPMTAG_SIG_BASE + 18, + RPMSIGTAG_FILESIGNATURELENGTH = RPMTAG_SIG_BASE + 19, + RPMSIGTAG_VERITYSIGNATURES = RPMTAG_VERITYSIGNATURES, } rpmSigTag; diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c index 5346c3bc8..a9818bd08 100644 --- a/sign/rpmsignverity.c +++ b/sign/rpmsignverity.c @@ -33,23 +33,66 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size) return retval; } +static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, + char *keypass, char *cert) +{ + struct libfsverity_merkle_tree_params params; + struct libfsverity_signature_params sig_params; + struct libfsverity_digest *digest = NULL; + rpm_loff_t file_size; + char *digest_hex, *sig_hex = NULL; + uint8_t *sig; + int status; + + file_size = rpmfiFSize(fi); + + memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); + params.version = 1; + params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + params.block_size = RPM_FSVERITY_BLKSZ; + params.salt_size = 0 /* salt_size */; + params.salt = NULL /* salt */; + params.file_size = file_size; + status = libfsverity_compute_digest(fi, rpmVerityRead, ¶ms, &digest); + if (status) { + rpmlog(RPMLOG_DEBUG, _("failed to compute digest\n")); + goto out; + } + + digest_hex = pgpHexStr(digest->digest, digest->digest_size); + rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"), + digest->digest_size, digest_hex); + free(digest_hex); + + memset(&sig_params, 0, sizeof(struct libfsverity_signature_params)); + sig_params.keyfile = key; + sig_params.certfile = cert; + if (libfsverity_sign_digest(digest, &sig_params, &sig, sig_size)) { + rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n")); + goto out; + } + + sig_hex = pgpHexStr(sig, *sig_size + 1); + out: + free(digest); + free(sig); + return sig_hex; +} + rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, char *keypass, char *cert) { - int rc, status; + int rc; FD_t gzdi; rpmfiles files = NULL; rpmfi fi = NULL; rpmts ts = rpmtsCreate(); - struct libfsverity_digest *digest = NULL; - struct libfsverity_merkle_tree_params params; - struct libfsverity_signature_params sig_params; + struct rpmtd_s td; rpm_loff_t file_size; off_t offset = Ftell(fd); const char *compr; char *rpmio_flags = NULL; - char *digest_hex; - uint8_t *sig; + char *sig_hex; size_t sig_size; Fseek(fd, 0, SEEK_SET); @@ -75,43 +118,40 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, fi = rpmfiNewArchiveReader(gzdi, files, RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS); + /* + * Should this be sigh from the cloned fd or the sigh we received? + */ + headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES); + + rpmtdReset(&td); + td.tag = RPMSIGTAG_VERITYSIGNATURES; + td.type = RPM_STRING_ARRAY_TYPE; + td.count = 1; + while (rpmfiNext(fi) >= 0) { - if (!S_ISREG(rpmfiFMode(fi))) - continue; file_size = rpmfiFSize(fi); - rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"), - rpmfiFN(fi), file_size); - - memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); - params.version = 1; - params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; - params.block_size = sysconf(_SC_PAGESIZE); - params.salt_size = 0 /* salt_size */; - params.salt = NULL /* salt */; - params.file_size = file_size; - status = libfsverity_compute_digest(fi, rpmVerityRead, - ¶ms, &digest); - if (!status) { - digest_hex = pgpHexStr(digest->digest, digest->digest_size); - rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"), - digest->digest_size, digest_hex); - free(digest_hex); - } - memset(&sig_params, 0, sizeof(struct libfsverity_signature_params)); - sig_params.keyfile = key; - sig_params.certfile = cert; - if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) { - rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n")); + + rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li, link %s, idx %i)\n"), + rpmfiFN(fi), file_size, rpmfiFLink(fi), rpmfiFX(fi)); + + sig_hex = rpmVeritySignFile(fi, &sig_size, key, keypass, cert); + td.data = &sig_hex; + rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size); +#if 0 + rpmlog(RPMLOG_DEBUG, _("digest: %s\n"), (char *)sig_hex); +#endif + if (!headerPut(sigh, &td, HEADERPUT_APPEND)) { + rpmlog(RPMLOG_ERR, _("headerPutString failed\n")); rc = RPMRC_FAIL; goto out; } - rpmlog(RPMLOG_DEBUG, _("digest signing success\n")); - - free(digest); - free(sig); + free(sig_hex); } -out: + rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0)); + + rc = RPMRC_OK; + out: Fseek(fd, offset, SEEK_SET); rpmfilesFree(files); diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h index f3ad3bb18..69bbaf7f7 100644 --- a/sign/rpmsignverity.h +++ b/sign/rpmsignverity.h @@ -8,6 +8,13 @@ extern "C" { #endif +/* + * Block size used to generate the Merkle tree for fsverity. For now + * we only support 4K blocks, if we ever decide to support different + * block sizes, we will need a tag to indicate this. + */ +#define RPM_FSVERITY_BLKSZ 4096 + /** * Sign file digests in header into signature header * @param fd file descriptor of RPM -- 2.27.0