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