|
|
45e748 |
From d447376aa2bf66a5d5b6a928fb0c6e65189910ba Mon Sep 17 00:00:00 2001
|
|
|
45e748 |
From: Jes Sorensen <jsorensen@fb.com>
|
|
|
45e748 |
Date: Fri, 3 Apr 2020 16:38:08 -0400
|
|
|
45e748 |
Subject: [PATCH 19/33] Implement rpmSignVerity()
|
|
|
45e748 |
|
|
|
45e748 |
This generates the root Merkle tree hash and signs it using the
|
|
|
45e748 |
specified key and certificate.
|
|
|
45e748 |
|
|
|
45e748 |
Signed-off-by: Jes Sorensen <jsorensen@fb.com>
|
|
|
45e748 |
---
|
|
|
45e748 |
sign/rpmgensig.c | 36 +++++++++++++
|
|
|
45e748 |
sign/rpmsignverity.c | 121 +++++++++++++++++++++++++++++++++++++++++++
|
|
|
45e748 |
sign/rpmsignverity.h | 29 +++++++++++
|
|
|
45e748 |
3 files changed, 186 insertions(+)
|
|
|
45e748 |
create mode 100644 sign/rpmsignverity.c
|
|
|
45e748 |
create mode 100644 sign/rpmsignverity.h
|
|
|
45e748 |
|
|
|
45e748 |
diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c
|
|
|
45e748 |
index a6e37e71b..8d5c5858f 100644
|
|
|
45e748 |
--- a/sign/rpmgensig.c
|
|
|
45e748 |
+++ b/sign/rpmgensig.c
|
|
|
45e748 |
@@ -22,6 +22,7 @@
|
|
|
45e748 |
#include "lib/signature.h"
|
|
|
45e748 |
#include "lib/rpmvs.h"
|
|
|
45e748 |
#include "sign/rpmsignfiles.h"
|
|
|
45e748 |
+#include "sign/rpmsignverity.h"
|
|
|
45e748 |
|
|
|
45e748 |
#include "debug.h"
|
|
|
45e748 |
|
|
|
45e748 |
@@ -446,6 +447,36 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp)
|
|
|
45e748 |
#endif
|
|
|
45e748 |
}
|
|
|
45e748 |
|
|
|
45e748 |
+static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp)
|
|
|
45e748 |
+{
|
|
|
45e748 |
+#ifdef WITH_FSVERITY
|
|
|
45e748 |
+ rpmRC rc;
|
|
|
45e748 |
+ char *key = rpmExpand("%{?_file_signing_key}", NULL);
|
|
|
45e748 |
+ char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL);
|
|
|
45e748 |
+ char *cert = rpmExpand("%{?_file_signing_cert}", NULL);
|
|
|
45e748 |
+
|
|
|
45e748 |
+ if (rstreq(keypass, "")) {
|
|
|
45e748 |
+ free(keypass);
|
|
|
45e748 |
+ keypass = NULL;
|
|
|
45e748 |
+ }
|
|
|
45e748 |
+
|
|
|
45e748 |
+ if (key && cert) {
|
|
|
45e748 |
+ rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert);
|
|
|
45e748 |
+ } else {
|
|
|
45e748 |
+ rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n"));
|
|
|
45e748 |
+ rc = RPMRC_FAIL;
|
|
|
45e748 |
+ }
|
|
|
45e748 |
+
|
|
|
45e748 |
+ free(keypass);
|
|
|
45e748 |
+ free(key);
|
|
|
45e748 |
+ free(cert);
|
|
|
45e748 |
+ return rc;
|
|
|
45e748 |
+#else
|
|
|
45e748 |
+ rpmlog(RPMLOG_ERR, _("fsverity signing support not built in\n"));
|
|
|
45e748 |
+ return RPMRC_FAIL;
|
|
|
45e748 |
+#endif
|
|
|
45e748 |
+}
|
|
|
45e748 |
+
|
|
|
45e748 |
static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata)
|
|
|
45e748 |
{
|
|
|
45e748 |
char **msg = cbdata;
|
|
|
45e748 |
@@ -544,6 +575,11 @@ static int rpmSign(const char *rpm, int deleting, int flags)
|
|
|
45e748 |
goto exit;
|
|
|
45e748 |
}
|
|
|
45e748 |
|
|
|
45e748 |
+ if (flags & RPMSIGN_FLAG_FSVERITY) {
|
|
|
45e748 |
+ if (includeVeritySignatures(fd, &sigh, &h))
|
|
|
45e748 |
+ goto exit;
|
|
|
45e748 |
+ }
|
|
|
45e748 |
+
|
|
|
45e748 |
if (deleting) { /* Nuke all the signature tags. */
|
|
|
45e748 |
deleteSigs(sigh);
|
|
|
45e748 |
} else {
|
|
|
45e748 |
diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c
|
|
|
45e748 |
new file mode 100644
|
|
|
45e748 |
index 000000000..5346c3bc8
|
|
|
45e748 |
--- /dev/null
|
|
|
45e748 |
+++ b/sign/rpmsignverity.c
|
|
|
45e748 |
@@ -0,0 +1,121 @@
|
|
|
45e748 |
+/**
|
|
|
45e748 |
+ * Copyright (C) 2020 Facebook
|
|
|
45e748 |
+ *
|
|
|
45e748 |
+ * Author: Jes Sorensen <jsorensen@fb.com>
|
|
|
45e748 |
+ */
|
|
|
45e748 |
+
|
|
|
45e748 |
+#include "system.h"
|
|
|
45e748 |
+
|
|
|
45e748 |
+#include <rpm/rpmlib.h> /* RPMSIGTAG & related */
|
|
|
45e748 |
+#include <rpm/rpmlog.h> /* rpmlog */
|
|
|
45e748 |
+#include <rpm/rpmfi.h>
|
|
|
45e748 |
+#include <rpm/rpmpgp.h> /* rpmDigestLength */
|
|
|
45e748 |
+#include "lib/header.h" /* HEADERGET_MINMEM */
|
|
|
45e748 |
+#include "lib/header_internal.h"
|
|
|
45e748 |
+#include "lib/rpmtypes.h" /* rpmRC */
|
|
|
45e748 |
+#include <libfsverity.h>
|
|
|
45e748 |
+#include "rpmio/rpmio_internal.h"
|
|
|
45e748 |
+#include "lib/rpmvs.h"
|
|
|
45e748 |
+
|
|
|
45e748 |
+#include "sign/rpmsignverity.h"
|
|
|
45e748 |
+
|
|
|
45e748 |
+#define MAX_SIGNATURE_LENGTH 1024
|
|
|
45e748 |
+
|
|
|
45e748 |
+static int rpmVerityRead(void *opaque, void *buf, size_t size)
|
|
|
45e748 |
+{
|
|
|
45e748 |
+ int retval;
|
|
|
45e748 |
+ rpmfi fi = (rpmfi)opaque;
|
|
|
45e748 |
+
|
|
|
45e748 |
+ retval = rpmfiArchiveRead(fi, buf, size);
|
|
|
45e748 |
+
|
|
|
45e748 |
+ if (retval > 0)
|
|
|
45e748 |
+ retval = 0;
|
|
|
45e748 |
+ return retval;
|
|
|
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 |
+ 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 |
+ 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 |
+ size_t sig_size;
|
|
|
45e748 |
+
|
|
|
45e748 |
+ Fseek(fd, 0, SEEK_SET);
|
|
|
45e748 |
+ rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES |
|
|
|
45e748 |
+ RPMVSF_NOHDRCHK);
|
|
|
45e748 |
+ rc = rpmReadPackageFile(ts, fd, "fsverity", &h);
|
|
|
45e748 |
+ if (rc != RPMRC_OK) {
|
|
|
45e748 |
+ rpmlog(RPMLOG_DEBUG, _("%s: rpmReadPackageFile returned %i\n"),
|
|
|
45e748 |
+ __func__, rc);
|
|
|
45e748 |
+ goto out;
|
|
|
45e748 |
+ }
|
|
|
45e748 |
+
|
|
|
45e748 |
+ rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key);
|
|
|
45e748 |
+ rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert);
|
|
|
45e748 |
+
|
|
|
45e748 |
+ compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR);
|
|
|
45e748 |
+ rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL);
|
|
|
45e748 |
+
|
|
|
45e748 |
+ gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags);
|
|
|
45e748 |
+ free(rpmio_flags);
|
|
|
45e748 |
+
|
|
|
45e748 |
+ files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY);
|
|
|
45e748 |
+ fi = rpmfiNewArchiveReader(gzdi, files,
|
|
|
45e748 |
+ RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS);
|
|
|
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(¶ms, 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 |
+ ¶ms, &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 |
+ rc = RPMRC_FAIL;
|
|
|
45e748 |
+ goto out;
|
|
|
45e748 |
+ }
|
|
|
45e748 |
+ rpmlog(RPMLOG_DEBUG, _("digest signing success\n"));
|
|
|
45e748 |
+
|
|
|
45e748 |
+ free(digest);
|
|
|
45e748 |
+ free(sig);
|
|
|
45e748 |
+ }
|
|
|
45e748 |
+
|
|
|
45e748 |
+out:
|
|
|
45e748 |
+ Fseek(fd, offset, SEEK_SET);
|
|
|
45e748 |
+
|
|
|
45e748 |
+ rpmfilesFree(files);
|
|
|
45e748 |
+ rpmfiFree(fi);
|
|
|
45e748 |
+ rpmtsFree(ts);
|
|
|
45e748 |
+ return rc;
|
|
|
45e748 |
+}
|
|
|
45e748 |
diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h
|
|
|
45e748 |
new file mode 100644
|
|
|
45e748 |
index 000000000..f3ad3bb18
|
|
|
45e748 |
--- /dev/null
|
|
|
45e748 |
+++ b/sign/rpmsignverity.h
|
|
|
45e748 |
@@ -0,0 +1,29 @@
|
|
|
45e748 |
+#ifndef H_RPMSIGNVERITY
|
|
|
45e748 |
+#define H_RPMSIGNVERITY
|
|
|
45e748 |
+
|
|
|
45e748 |
+#include <rpm/rpmtypes.h>
|
|
|
45e748 |
+#include <rpm/rpmutil.h>
|
|
|
45e748 |
+
|
|
|
45e748 |
+#ifdef __cplusplus
|
|
|
45e748 |
+extern "C" {
|
|
|
45e748 |
+#endif
|
|
|
45e748 |
+
|
|
|
45e748 |
+/**
|
|
|
45e748 |
+ * Sign file digests in header into signature header
|
|
|
45e748 |
+ * @param fd file descriptor of RPM
|
|
|
45e748 |
+ * @param sigh package signature header
|
|
|
45e748 |
+ * @param h package header
|
|
|
45e748 |
+ * @param key signing key
|
|
|
45e748 |
+ * @param keypass signing key password
|
|
|
45e748 |
+ * @param cert signing cert
|
|
|
45e748 |
+ * @return RPMRC_OK on success
|
|
|
45e748 |
+ */
|
|
|
45e748 |
+RPM_GNUC_INTERNAL
|
|
|
45e748 |
+rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key,
|
|
|
45e748 |
+ char *keypass, char *cert);
|
|
|
45e748 |
+
|
|
|
45e748 |
+#ifdef _cplusplus
|
|
|
45e748 |
+}
|
|
|
45e748 |
+#endif
|
|
|
45e748 |
+
|
|
|
45e748 |
+#endif /* H_RPMSIGNVERITY */
|
|
|
45e748 |
--
|
|
|
45e748 |
2.27.0
|
|
|
45e748 |
|