chantra / rpms / rpm

Forked from rpms/rpm 2 years ago
Clone
Blob Blame History Raw
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(&params, 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, &params, &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(&params, 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,
-					    &params, &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