malmond / rpms / rpm

Forked from rpms/rpm 4 years ago
Clone

Blame SOURCES/0020-Implement-rpmSignVerity.patch

657fb1
From 77bfd446e345fb65b9d1695116a82eb37cfba640 Mon Sep 17 00:00:00 2001
657fb1
From: Jes Sorensen <jsorensen@fb.com>
657fb1
Date: Fri, 3 Apr 2020 16:38:08 -0400
657fb1
Subject: [PATCH 20/33] Implement rpmSignVerity()
657fb1
657fb1
This generates the root Merkle tree hash and signs it using the
657fb1
specified key and certificate.
657fb1
657fb1
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
657fb1
---
657fb1
 sign/rpmgensig.c     |  36 +++++++++++++++
657fb1
 sign/rpmsignverity.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++
657fb1
 sign/rpmsignverity.h |  29 ++++++++++++
657fb1
 3 files changed, 186 insertions(+)
657fb1
 create mode 100644 sign/rpmsignverity.c
657fb1
 create mode 100644 sign/rpmsignverity.h
657fb1
657fb1
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
657fb1
index 0c6646d85..78da1347b 100644
657fb1
--- a/sign/rpmgensig.c
657fb1
+++ b/sign/rpmgensig.c
657fb1
@@ -22,6 +22,7 @@
657fb1
 #include "lib/signature.h"
657fb1
 #include "lib/rpmvs.h"
657fb1
 #include "sign/rpmsignfiles.h"
657fb1
+#include "sign/rpmsignverity.h"
657fb1
 
657fb1
 #include "debug.h"
657fb1
 
657fb1
@@ -439,6 +440,36 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
657fb1
 #endif
657fb1
 }
657fb1
 
657fb1
+static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)
657fb1
+{
657fb1
+#ifdef WITH_FSVERITY
657fb1
+    rpmRC rc;
657fb1
+    char *key = rpmExpand("%{?_file_signing_key}", NULL);
657fb1
+    char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
657fb1
+    char *cert = rpmExpand("%{?_file_signing_cert}", NULL);
657fb1
+
657fb1
+    if (rstreq(keypass, "")) {
657fb1
+	free(keypass);
657fb1
+	keypass = NULL;
657fb1
+    }
657fb1
+
657fb1
+    if (key && cert) {
657fb1
+	rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert);
657fb1
+    } else {
657fb1
+	rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));
657fb1
+	rc = RPMRC_FAIL;
657fb1
+    }
657fb1
+
657fb1
+    free(keypass);
657fb1
+    free(key);
657fb1
+    free(cert);
657fb1
+    return rc;
657fb1
+#else
657fb1
+    rpmlog(RPMLOG_ERR, _("fsverity signing support not built in\n"));
657fb1
+    return RPMRC_FAIL;
657fb1
+#endif
657fb1
+}
657fb1
+
657fb1
 static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata)
657fb1
 {
657fb1
     char **msg = cbdata;
657fb1
@@ -538,6 +569,11 @@ static int rpmSign(const char *rpm, int deleting, int flags)
657fb1
 	    goto exit;
657fb1
     }
657fb1
 
657fb1
+    if (flags & RPMSIGN_FLAG_FSVERITY) {
657fb1
+	if (includeVeritySignatures(fd, &sigh, &h))
657fb1
+	    goto exit;
657fb1
+    }
657fb1
+
657fb1
     if (deleting) {	/* Nuke all the signature tags. */
657fb1
 	deleteSigs(sigh);
657fb1
     } else {
657fb1
diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
657fb1
new file mode 100644
657fb1
index 000000000..5346c3bc8
657fb1
--- /dev/null
657fb1
+++ b/sign/rpmsignverity.c
657fb1
@@ -0,0 +1,121 @@
657fb1
+/**
657fb1
+ * Copyright (C) 2020 Facebook
657fb1
+ *
657fb1
+ * Author: Jes Sorensen <jsorensen@fb.com>
657fb1
+ */
657fb1
+
657fb1
+#include "system.h"
657fb1
+
657fb1
+#include <rpm/rpmlib.h>		/* RPMSIGTAG & related */
657fb1
+#include <rpm/rpmlog.h>		/* rpmlog */
657fb1
+#include <rpm/rpmfi.h>
657fb1
+#include <rpm/rpmpgp.h>		/* rpmDigestLength */
657fb1
+#include "lib/header.h"		/* HEADERGET_MINMEM */
657fb1
+#include "lib/header_internal.h"
657fb1
+#include "lib/rpmtypes.h"	/* rpmRC */
657fb1
+#include <libfsverity.h>
657fb1
+#include "rpmio/rpmio_internal.h"
657fb1
+#include "lib/rpmvs.h"
657fb1
+
657fb1
+#include "sign/rpmsignverity.h"
657fb1
+
657fb1
+#define MAX_SIGNATURE_LENGTH 1024
657fb1
+
657fb1
+static int rpmVerityRead(void *opaque, void *buf, size_t size)
657fb1
+{
657fb1
+	int retval;
657fb1
+	rpmfi fi = (rpmfi)opaque;
657fb1
+
657fb1
+	retval = rpmfiArchiveRead(fi, buf, size);
657fb1
+
657fb1
+	if (retval > 0)
657fb1
+		retval = 0;
657fb1
+	return retval;
657fb1
+}
657fb1
+
657fb1
+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
657fb1
+		    char *keypass, char *cert)
657fb1
+{
657fb1
+    int rc, status;
657fb1
+    FD_t gzdi;
657fb1
+    rpmfiles files = NULL;
657fb1
+    rpmfi fi = NULL;
657fb1
+    rpmts ts = rpmtsCreate();
657fb1
+    struct libfsverity_digest *digest = NULL;
657fb1
+    struct libfsverity_merkle_tree_params params;
657fb1
+    struct libfsverity_signature_params sig_params;
657fb1
+    rpm_loff_t file_size;
657fb1
+    off_t offset = Ftell(fd);
657fb1
+    const char *compr;
657fb1
+    char *rpmio_flags = NULL;
657fb1
+    char *digest_hex;
657fb1
+    uint8_t *sig;
657fb1
+    size_t sig_size;
657fb1
+
657fb1
+    Fseek(fd, 0, SEEK_SET);
657fb1
+    rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
657fb1
+		    RPMVSF_NOHDRCHK);
657fb1
+    rc = rpmReadPackageFile(ts, fd, "fsverity", &h);
657fb1
+    if (rc != RPMRC_OK) {
657fb1
+	rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),
657fb1
+	       __func__, rc);
657fb1
+	goto out;
657fb1
+    }
657fb1
+
657fb1
+    rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key);
657fb1
+    rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert);
657fb1
+
657fb1
+    compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
657fb1
+    rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
657fb1
+
657fb1
+    gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);
657fb1
+    free(rpmio_flags);
657fb1
+
657fb1
+    files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
657fb1
+    fi = rpmfiNewArchiveReader(gzdi, files,
657fb1
+			       RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS);
657fb1
+
657fb1
+    while (rpmfiNext(fi) >= 0) {
657fb1
+	if (!S_ISREG(rpmfiFMode(fi)))
657fb1
+	    continue;
657fb1
+	file_size = rpmfiFSize(fi);
657fb1
+	rpmlog(RPMLOG_DEBUG, _("file: %s, (size %li)\n"),
657fb1
+	       rpmfiFN(fi), file_size);
657fb1
+
657fb1
+	memset(&params, 0, sizeof(struct libfsverity_merkle_tree_params));
657fb1
+	params.version = 1;
657fb1
+	params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256;
657fb1
+	params.block_size = sysconf(_SC_PAGESIZE);
657fb1
+	params.salt_size = 0 /* salt_size */;
657fb1
+	params.salt = NULL /* salt */;
657fb1
+	params.file_size = file_size;
657fb1
+	status = libfsverity_compute_digest(fi, rpmVerityRead,
657fb1
+					    &params, &digest);
657fb1
+	if (!status) {
657fb1
+	    digest_hex = pgpHexStr(digest->digest, digest->digest_size);
657fb1
+	    rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"),
657fb1
+		   digest->digest_size, digest_hex);
657fb1
+	    free(digest_hex);
657fb1
+	}
657fb1
+	memset(&sig_params, 0, sizeof(struct libfsverity_signature_params));
657fb1
+	sig_params.keyfile = key;
657fb1
+	sig_params.certfile = cert;
657fb1
+	if (libfsverity_sign_digest(digest, &sig_params, &sig, &sig_size)) {
657fb1
+	    rpmlog(RPMLOG_DEBUG, _("failed to sign digest\n"));
657fb1
+	    rc = RPMRC_FAIL;
657fb1
+	    goto out;
657fb1
+	}
657fb1
+	rpmlog(RPMLOG_DEBUG, _("digest signing success\n"));
657fb1
+
657fb1
+	free(digest);
657fb1
+	free(sig);
657fb1
+    }
657fb1
+
657fb1
+out:
657fb1
+    Fseek(fd, offset, SEEK_SET);
657fb1
+
657fb1
+    rpmfilesFree(files);
657fb1
+    rpmfiFree(fi);
657fb1
+    rpmtsFree(ts);
657fb1
+    return rc;
657fb1
+}
657fb1
diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
657fb1
new file mode 100644
657fb1
index 000000000..f3ad3bb18
657fb1
--- /dev/null
657fb1
+++ b/sign/rpmsignverity.h
657fb1
@@ -0,0 +1,29 @@
657fb1
+#ifndef H_RPMSIGNVERITY
657fb1
+#define H_RPMSIGNVERITY
657fb1
+
657fb1
+#include <rpm/rpmtypes.h>
657fb1
+#include <rpm/rpmutil.h>
657fb1
+
657fb1
+#ifdef __cplusplus
657fb1
+extern "C" {
657fb1
+#endif
657fb1
+
657fb1
+/**
657fb1
+ * Sign file digests in header into signature header
657fb1
+ * @param fd		file descriptor of RPM
657fb1
+ * @param sigh		package signature header
657fb1
+ * @param h		package header
657fb1
+ * @param key		signing key
657fb1
+ * @param keypass	signing key password
657fb1
+ * @param cert		signing cert
657fb1
+ * @return		RPMRC_OK on success
657fb1
+ */
657fb1
+RPM_GNUC_INTERNAL
657fb1
+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
657fb1
+		    char *keypass, char *cert);
657fb1
+
657fb1
+#ifdef _cplusplus
657fb1
+}
657fb1
+#endif
657fb1
+
657fb1
+#endif /* H_RPMSIGNVERITY */
657fb1
-- 
657fb1
2.13.5
657fb1