michal-grzedzicki / rpms / rpm

Forked from rpms/rpm 5 months ago
Clone
Blob Blame History Raw
From 22420d9ee652a25357727b00585dc3cfe78b2a80 Mon Sep 17 00:00:00 2001
From: Jes Sorensen <jsorensen@fb.com>
Date: Mon, 13 Apr 2020 18:14:15 -0400
Subject: [PATCH 22/33] rpmSignVerity: Generate signatures for files not
 present in archive

This generates signatures for all files in the archive, then picks up
ghost files from the header metadata and generates signatures for them
as well. It finally submits them to RPMTAG_VERITYSIGNATURES in header
file order as we cannot rely on archive order and header order being
the same.

Signed-off-by: Jes Sorensen <jsorensen@fb.com>
---
 lib/package.c        |  1 +
 sign/rpmsignverity.c | 55 ++++++++++++++++++++++++++++++++++----------
 2 files changed, 44 insertions(+), 12 deletions(-)

diff --git a/lib/package.c b/lib/package.c
index b7d996a12..c6108f686 100644
--- a/lib/package.c
+++ b/lib/package.c
@@ -45,6 +45,7 @@ struct taglate_s {
     { RPMSIGTAG_PAYLOADSIZE, RPMTAG_ARCHIVESIZE, 1, 1 },
     { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 },
     { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 },
+    { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 },
     { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 },
     { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 },
     { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 },
diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
index a9818bd08..3bb23a18d 100644
--- a/sign/rpmsignverity.c
+++ b/sign/rpmsignverity.c
@@ -41,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
     struct libfsverity_digest *digest = NULL;
     rpm_loff_t file_size;
     char *digest_hex, *sig_hex = NULL;
-    uint8_t *sig;
+    uint8_t *sig = NULL;
     int status;
 
     file_size = rpmfiFSize(fi);
@@ -72,7 +72,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key,
 	goto out;
     }
 
-    sig_hex = pgpHexStr(sig, *sig_size + 1);
+    sig_hex = pgpHexStr(sig, *sig_size);
  out:
     free(digest);
     free(sig);
@@ -86,6 +86,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
     FD_t gzdi;
     rpmfiles files = NULL;
     rpmfi fi = NULL;
+    rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
     rpmts ts = rpmtsCreate();
     struct rpmtd_s td;
     rpm_loff_t file_size;
@@ -93,11 +94,14 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
     const char *compr;
     char *rpmio_flags = NULL;
     char *sig_hex;
+    char **signatures = NULL;
     size_t sig_size;
+    int nr_files, idx;
 
     Fseek(fd, 0, SEEK_SET);
     rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
 		    RPMVSF_NOHDRCHK);
+
     rc = rpmReadPackageFile(ts, fd, "fsverity", &h);
     if (rc != RPMRC_OK) {
 	rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),
@@ -113,6 +117,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
 
     gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);
     free(rpmio_flags);
+    if (!gzdi)
+	rpmlog(RPMLOG_DEBUG, _("Fdopen() failed\n"));
 
     files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
     fi = rpmfiNewArchiveReader(gzdi, files,
@@ -123,39 +129,64 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
      */
     headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES);
 
-    rpmtdReset(&td);
-    td.tag = RPMSIGTAG_VERITYSIGNATURES;
-    td.type = RPM_STRING_ARRAY_TYPE;
-    td.count = 1;
+    /*
+     * The payload doesn't include special files, like ghost files, and
+     * we cannot rely on the file order in the payload to match that of
+     * the header. Instead we allocate an array of pointers and populate
+     * it as we go along. Then walk the header fi and account for the
+     * special files. Last we walk the array and populate the header.
+     */
+    nr_files = rpmfiFC(hfi);
+    signatures = xcalloc(nr_files, sizeof(char *));
+
+    rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"),
+	   nr_files, rpmfiFC(fi));
 
     while (rpmfiNext(fi) >= 0) {
 	file_size = rpmfiFSize(fi);
+	idx = rpmfiFX(fi);
 
 	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);
+	signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert);
+    }
+
+    while (rpmfiNext(hfi) >= 0) {
+	idx = rpmfiFX(hfi);
+	if (signatures[idx])
+	    continue;
+	signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert);
+    }
+
+    rpmtdReset(&td);
+    td.tag = RPMSIGTAG_VERITYSIGNATURES;
+    td.type = RPM_STRING_ARRAY_TYPE;
+    td.count = 1;
+    for (idx = 0; idx < nr_files; idx++) {
+	sig_hex = signatures[idx];
 	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;
 	}
-	free(sig_hex);
+	rpmlog(RPMLOG_DEBUG, _("signature: %s\n"), signatures[idx]);
+	rpmlog(RPMLOG_DEBUG, _("digest signed, len: %li\n"), sig_size);
+	free(signatures[idx]);
+	signatures[idx] = NULL;
     }
 
     rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0));
 
     rc = RPMRC_OK;
  out:
+    signatures = _free(signatures);
     Fseek(fd, offset, SEEK_SET);
 
     rpmfilesFree(files);
     rpmfiFree(fi);
+    rpmfiFree(hfi);
     rpmtsFree(ts);
     return rc;
 }
-- 
2.27.0