From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001
From: Jes Sorensen <jsorensen@fb.com>
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 <jsorensen@fb.com>
---
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