From 45e748cc34b44b2b09800eca32443dbf49509647 Mon Sep 17 00:00:00 2001 From: Matthew Almond Date: Mar 01 2022 07:52:31 +0000 Subject: Add fsverity backport to SIG These patches have been in production at Facebook for a while. This was blocked on the absence of `fsverity-utils-devel`. This is now in EPEL, and EPEL itself is enabled in `centos-stream-8-x86_64` mock config. --- diff --git a/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch b/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch new file mode 100644 index 0000000..e6dae81 --- /dev/null +++ b/0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch @@ -0,0 +1,28 @@ +From 7784da14fe57df919df9dfdad30e436ffe6d3e28 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 20 Apr 2020 11:22:15 -0400 +Subject: [PATCH 15/33] rpmsign: RPMSIGN_FLAG_IMA is already set + +There is no need to set RPMSIGN_FLAG_IMA since it was already set to +get here. + +Signed-off-by: Jes Sorensen +--- + rpmsign.c | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/rpmsign.c b/rpmsign.c +index a74948ba8..e1d207da5 100644 +--- a/rpmsign.c ++++ b/rpmsign.c +@@ -130,7 +130,6 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) + free(fileSigningKeyPassword); + } + +- sargs->signflags |= RPMSIGN_FLAG_IMA; + free(key); + } + #endif +-- +2.27.0 + diff --git a/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch b/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch new file mode 100644 index 0000000..89845cb --- /dev/null +++ b/0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch @@ -0,0 +1,136 @@ +From f525681b4f66026578bc728b864bfea3d814c29e Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Fri, 27 Mar 2020 18:31:36 -0400 +Subject: [PATCH 16/33] Add basic autoconf and framework for fsverity support + +Use the same signing key argument as is used for IMA file signing. + +Signed-off-by: Jes Sorensen +--- + configure.ac | 19 +++++++++++++++++++ + rpmsign.c | 20 ++++++++++++++------ + sign/Makefile.am | 5 +++++ + sign/rpmsign.h | 1 + + 4 files changed, 39 insertions(+), 6 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 3c102d5eb..cc7144440 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -919,6 +919,25 @@ fi + AM_CONDITIONAL(WITH_IMAEVM,[test "$with_imaevm" = yes]) + AC_SUBST(WITH_IMAEVM_LIB) + ++# fsverity ++AC_ARG_WITH([fsverity], [AS_HELP_STRING([--with-fsverity],[build with fsverity support])],[],[with_fsverity=no]) ++if test "$with_fsverity" = yes ; then ++ AC_MSG_CHECKING([libfsverity]) ++ AC_COMPILE_IFELSE( ++ [AC_LANG_PROGRAM( ++ [[#include ]], ++ [[return libfsverity_sign_digest(NULL, NULL, NULL, NULL);]] ++ )], ++ [AC_MSG_RESULT(yes) ++ AC_DEFINE(WITH_FSVERITY, 1, [Build with fsverity support?]) ++ WITH_FSVERITY_LIB="-lfsverity" ++ ], ++ [AC_MSG_ERROR([--with-fsverity given, libfsverity or libfsverity.h missing])] ++ ) ++fi ++AM_CONDITIONAL(WITH_FSVERITY,[test "$with_fsverity" = yes]) ++AC_SUBST(WITH_FSVERITY_LIB) ++ + # libcap + WITH_CAP_LIB= + AC_ARG_WITH(cap, [AS_HELP_STRING([--with-cap],[build with capability support])], +diff --git a/rpmsign.c b/rpmsign.c +index e1d207da5..8861c2c59 100644 +--- a/rpmsign.c ++++ b/rpmsign.c +@@ -18,7 +18,7 @@ enum modes { + + static int mode = MODE_NONE; + +-#ifdef WITH_IMAEVM ++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) + static int fskpass = 0; + static char * fileSigningKey = NULL; + #endif +@@ -39,6 +39,13 @@ static struct poptOption signOptsTable[] = { + { "signfiles", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), + &sargs.signflags, RPMSIGN_FLAG_IMA, + N_("sign package(s) files"), NULL}, ++#endif ++#ifdef WITH_FSVERITY ++ { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), ++ &sargs.signflags, RPMSIGN_FLAG_FSVERITY, ++ N_("generate fsverity signatures for package(s) files"), NULL}, ++#endif ++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) + { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0, + N_("use file signing key "), + N_("") }, +@@ -59,7 +66,7 @@ static struct poptOption optionsTable[] = { + POPT_TABLEEND + }; + +-#ifdef WITH_IMAEVM ++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) + static char *get_fskpass(void) + { + struct termios flags, tmp_flags; +@@ -106,12 +113,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) + goto exit; + } + +-#ifdef WITH_IMAEVM ++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) + if (fileSigningKey) { + rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL); + } + +- if (sargs->signflags & RPMSIGN_FLAG_IMA) { ++ if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) { + char *fileSigningKeyPassword = NULL; + char *key = rpmExpand("%{?_file_signing_key}", NULL); + if (rstreq(key, "")) { +@@ -165,8 +172,9 @@ int main(int argc, char *argv[]) + argerror(_("no arguments given")); + } + +-#ifdef WITH_IMAEVM +- if (fileSigningKey && !(sargs.signflags & RPMSIGN_FLAG_IMA)) { ++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) ++ if (fileSigningKey && ++ !(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) { + argerror(_("--fskpath may only be specified when signing files")); + } + #endif +diff --git a/sign/Makefile.am b/sign/Makefile.am +index db774de0e..8d372915a 100644 +--- a/sign/Makefile.am ++++ b/sign/Makefile.am +@@ -24,3 +24,8 @@ if WITH_IMAEVM + librpmsign_la_SOURCES += rpmsignfiles.c rpmsignfiles.h + librpmsign_la_LIBADD += @WITH_IMAEVM_LIB@ + endif ++ ++if WITH_FSVERITY ++librpmsign_la_SOURCES += rpmsignverity.c rpmsignverity.h ++librpmsign_la_LIBADD += @WITH_FSVERITY_LIB@ ++endif +diff --git a/sign/rpmsign.h b/sign/rpmsign.h +index 7a770d879..2b8a10a1a 100644 +--- a/sign/rpmsign.h ++++ b/sign/rpmsign.h +@@ -17,6 +17,7 @@ enum rpmSignFlags_e { + RPMSIGN_FLAG_NONE = 0, + RPMSIGN_FLAG_IMA = (1 << 0), + RPMSIGN_FLAG_RPMV3 = (1 << 1), ++ RPMSIGN_FLAG_FSVERITY = (1 << 2), + }; + typedef rpmFlags rpmSignFlags; + +-- +2.27.0 + diff --git a/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch b/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch new file mode 100644 index 0000000..ae64146 --- /dev/null +++ b/0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch @@ -0,0 +1,51 @@ +From dbb4f464d177e2c3bfa13b1b2bb511fa6fde40d9 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Wed, 27 May 2020 16:49:03 -0400 +Subject: [PATCH 17/33] rpmsign: Add helper to indicate file signing enabled + +Helper function returning true if either IMA or VERITY signatures are +to be applied. This simplifies the code and makes it easier to read. + +Signed-off-by: Jes Sorensen +--- + rpmsign.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/rpmsign.c b/rpmsign.c +index 8861c2c59..94cbf1d1a 100644 +--- a/rpmsign.c ++++ b/rpmsign.c +@@ -67,6 +67,11 @@ static struct poptOption optionsTable[] = { + }; + + #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) ++static int flags_sign_files(int flags) ++{ ++ return (flags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY) ? 1 : 0); ++} ++ + static char *get_fskpass(void) + { + struct termios flags, tmp_flags; +@@ -118,7 +123,7 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) + rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL); + } + +- if (sargs->signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY)) { ++ if (flags_sign_files(sargs->signflags)) { + char *fileSigningKeyPassword = NULL; + char *key = rpmExpand("%{?_file_signing_key}", NULL); + if (rstreq(key, "")) { +@@ -173,8 +178,7 @@ int main(int argc, char *argv[]) + } + + #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) +- if (fileSigningKey && +- !(sargs.signflags & (RPMSIGN_FLAG_IMA | RPMSIGN_FLAG_FSVERITY))) { ++ if (fileSigningKey && !(flags_sign_files(sargs.signflags))) { + argerror(_("--fskpath may only be specified when signing files")); + } + #endif +-- +2.27.0 + diff --git a/0018-rpmsign-Handle-certpath-for-signing-certificate.patch b/0018-rpmsign-Handle-certpath-for-signing-certificate.patch new file mode 100644 index 0000000..77a8b31 --- /dev/null +++ b/0018-rpmsign-Handle-certpath-for-signing-certificate.patch @@ -0,0 +1,52 @@ +From 5e74846046e06f5a3401c4d2eb4ccfadacd4ab53 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Fri, 3 Apr 2020 16:26:06 -0400 +Subject: [PATCH 18/33] rpmsign: Handle --certpath for signing certificate + +fsverirty needs a certificate for signing, in addition to the signing key. + +Signed-off-by: Jes Sorensen +--- + rpmsign.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/rpmsign.c b/rpmsign.c +index 94cbf1d1a..074dd8b13 100644 +--- a/rpmsign.c ++++ b/rpmsign.c +@@ -22,6 +22,9 @@ static int mode = MODE_NONE; + static int fskpass = 0; + static char * fileSigningKey = NULL; + #endif ++#ifdef WITH_FSVERITY ++static char * fileSigningCert = NULL; ++#endif + + static struct rpmSignArgs sargs = {NULL, 0, 0}; + +@@ -44,6 +47,9 @@ static struct poptOption signOptsTable[] = { + { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), + &sargs.signflags, RPMSIGN_FLAG_FSVERITY, + N_("generate fsverity signatures for package(s) files"), NULL}, ++ { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0, ++ N_("use file signing cert "), ++ N_("") }, + #endif + #if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) + { "fskpath", '\0', POPT_ARG_STRING, &fileSigningKey, 0, +@@ -123,6 +129,12 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) + rpmPushMacro(NULL, "_file_signing_key", NULL, fileSigningKey, RMIL_GLOBAL); + } + ++#ifdef WITH_FSVERITY ++ if (fileSigningCert) { ++ rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL); ++ } ++#endif ++ + if (flags_sign_files(sargs->signflags)) { + char *fileSigningKeyPassword = NULL; + char *key = rpmExpand("%{?_file_signing_key}", NULL); +-- +2.27.0 + diff --git a/0019-Implement-rpmSignVerity.patch b/0019-Implement-rpmSignVerity.patch new file mode 100644 index 0000000..70e873a --- /dev/null +++ b/0019-Implement-rpmSignVerity.patch @@ -0,0 +1,243 @@ +From d447376aa2bf66a5d5b6a928fb0c6e65189910ba Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Fri, 3 Apr 2020 16:38:08 -0400 +Subject: [PATCH 19/33] Implement rpmSignVerity() + +This generates the root Merkle tree hash and signs it using the +specified key and certificate. + +Signed-off-by: Jes Sorensen +--- + sign/rpmgensig.c | 36 +++++++++++++ + sign/rpmsignverity.c | 121 +++++++++++++++++++++++++++++++++++++++++++ + sign/rpmsignverity.h | 29 +++++++++++ + 3 files changed, 186 insertions(+) + create mode 100644 sign/rpmsignverity.c + create mode 100644 sign/rpmsignverity.h + +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index a6e37e71b..8d5c5858f 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -22,6 +22,7 @@ + #include "lib/signature.h" + #include "lib/rpmvs.h" + #include "sign/rpmsignfiles.h" ++#include "sign/rpmsignverity.h" + + #include "debug.h" + +@@ -446,6 +447,36 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp) + #endif + } + ++static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp) ++{ ++#ifdef WITH_FSVERITY ++ rpmRC rc; ++ char *key = rpmExpand("%{?_file_signing_key}", NULL); ++ char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL); ++ char *cert = rpmExpand("%{?_file_signing_cert}", NULL); ++ ++ if (rstreq(keypass, "")) { ++ free(keypass); ++ keypass = NULL; ++ } ++ ++ if (key && cert) { ++ rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert); ++ } else { ++ rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n")); ++ rc = RPMRC_FAIL; ++ } ++ ++ free(keypass); ++ free(key); ++ free(cert); ++ return rc; ++#else ++ rpmlog(RPMLOG_ERR, _("fsverity signing support not built in\n")); ++ return RPMRC_FAIL; ++#endif ++} ++ + static int msgCb(struct rpmsinfo_s *sinfo, void *cbdata) + { + char **msg = cbdata; +@@ -544,6 +575,11 @@ static int rpmSign(const char *rpm, int deleting, int flags) + goto exit; + } + ++ if (flags & RPMSIGN_FLAG_FSVERITY) { ++ if (includeVeritySignatures(fd, &sigh, &h)) ++ goto exit; ++ } ++ + if (deleting) { /* Nuke all the signature tags. */ + deleteSigs(sigh); + } else { +diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c +new file mode 100644 +index 000000000..5346c3bc8 +--- /dev/null ++++ b/sign/rpmsignverity.c +@@ -0,0 +1,121 @@ ++/** ++ * Copyright (C) 2020 Facebook ++ * ++ * Author: Jes Sorensen ++ */ ++ ++#include "system.h" ++ ++#include /* RPMSIGTAG & related */ ++#include /* rpmlog */ ++#include ++#include /* rpmDigestLength */ ++#include "lib/header.h" /* HEADERGET_MINMEM */ ++#include "lib/header_internal.h" ++#include "lib/rpmtypes.h" /* rpmRC */ ++#include ++#include "rpmio/rpmio_internal.h" ++#include "lib/rpmvs.h" ++ ++#include "sign/rpmsignverity.h" ++ ++#define MAX_SIGNATURE_LENGTH 1024 ++ ++static int rpmVerityRead(void *opaque, void *buf, size_t size) ++{ ++ int retval; ++ rpmfi fi = (rpmfi)opaque; ++ ++ retval = rpmfiArchiveRead(fi, buf, size); ++ ++ if (retval > 0) ++ retval = 0; ++ return retval; ++} ++ ++rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, ++ char *keypass, char *cert) ++{ ++ int rc, status; ++ 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; ++ rpm_loff_t file_size; ++ off_t offset = Ftell(fd); ++ const char *compr; ++ char *rpmio_flags = NULL; ++ char *digest_hex; ++ uint8_t *sig; ++ size_t sig_size; ++ ++ 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"), ++ __func__, rc); ++ goto out; ++ } ++ ++ rpmlog(RPMLOG_DEBUG, _("key: %s\n"), key); ++ rpmlog(RPMLOG_DEBUG, _("cert: %s\n"), cert); ++ ++ compr = headerGetString(h, RPMTAG_PAYLOADCOMPRESSOR); ++ rpmio_flags = rstrscat(NULL, "r.", compr ? compr : "gzip", NULL); ++ ++ gzdi = Fdopen(fdDup(Fileno(fd)), rpmio_flags); ++ free(rpmio_flags); ++ ++ files = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY); ++ fi = rpmfiNewArchiveReader(gzdi, files, ++ RPMFI_ITER_READ_ARCHIVE_OMIT_HARDLINKS); ++ ++ 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(¶ms, 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, ++ ¶ms, &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")); ++ rc = RPMRC_FAIL; ++ goto out; ++ } ++ rpmlog(RPMLOG_DEBUG, _("digest signing success\n")); ++ ++ free(digest); ++ free(sig); ++ } ++ ++out: ++ Fseek(fd, offset, SEEK_SET); ++ ++ rpmfilesFree(files); ++ rpmfiFree(fi); ++ rpmtsFree(ts); ++ return rc; ++} +diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h +new file mode 100644 +index 000000000..f3ad3bb18 +--- /dev/null ++++ b/sign/rpmsignverity.h +@@ -0,0 +1,29 @@ ++#ifndef H_RPMSIGNVERITY ++#define H_RPMSIGNVERITY ++ ++#include ++#include ++ ++#ifdef __cplusplus ++extern "C" { ++#endif ++ ++/** ++ * Sign file digests in header into signature header ++ * @param fd file descriptor of RPM ++ * @param sigh package signature header ++ * @param h package header ++ * @param key signing key ++ * @param keypass signing key password ++ * @param cert signing cert ++ * @return RPMRC_OK on success ++ */ ++RPM_GNUC_INTERNAL ++rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, ++ char *keypass, char *cert); ++ ++#ifdef _cplusplus ++} ++#endif ++ ++#endif /* H_RPMSIGNVERITY */ +-- +2.27.0 + diff --git a/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch b/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch new file mode 100644 index 0000000..b099eaf --- /dev/null +++ b/0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch @@ -0,0 +1,95 @@ +From a7e81a1b18c9e9d124a4ea917c8015af62584abb Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Thu, 28 May 2020 17:48:23 -0400 +Subject: [PATCH 20/33] Introduce base2bin() - a helper to convert tag array of + base64 strings + +This will convert a tag of base64 strings to a binary array, similar +to how hex2bin() works. It supports variable sized strings, and will +determine the maximum string length and build the output array based +on that. + +Signed-off-by: Jes Sorensen +--- + lib/rpmfi.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 58 insertions(+) + +diff --git a/lib/rpmfi.c b/lib/rpmfi.c +index 689ead2c5..8c69d3e40 100644 +--- a/lib/rpmfi.c ++++ b/lib/rpmfi.c +@@ -19,6 +19,7 @@ + #include "lib/fsm.h" /* rpmpsm stuff for now */ + #include "lib/rpmug.h" + #include "rpmio/rpmio_internal.h" /* fdInit/FiniDigest */ ++#include "rpmio/rpmbase64.h" + + #include "debug.h" + +@@ -1520,6 +1521,63 @@ static uint8_t *hex2bin(Header h, rpmTagVal tag, rpm_count_t num, size_t len) + return bin; + } + ++/* ++ * Convert a tag of base64 strings to binary presentation. ++ * This handles variable length strings by finding the longest string ++ * before building the output array. Dummy strings in the tag should be ++ * added as '\0' ++ */ ++static uint8_t *base2bin(Header h, rpmTagVal tag, rpm_count_t num, int *len) ++{ ++ struct rpmtd_s td; ++ uint8_t *bin = NULL, *t = NULL; ++ size_t maxlen = 0; ++ int status, i= 0; ++ void **arr = xmalloc(num * sizeof(void *)); ++ size_t *lengths = xcalloc(num, sizeof(size_t)); ++ const char *s; ++ ++ if (headerGet(h, tag, &td, HEADERGET_MINMEM) && rpmtdCount(&td) != num) ++ goto out; ++ ++ while ((s = rpmtdNextString(&td))) { ++ /* Insert a dummy entry for empty strings */ ++ if (*s == '\0') { ++ arr[i++] = NULL; ++ continue; ++ } ++ status = rpmBase64Decode(s, &arr[i], &lengths[i]); ++ if (lengths[i] > maxlen) ++ maxlen = lengths[i]; ++ if (status) { ++ rpmlog(RPMLOG_DEBUG, _("%s: base64 decode failed, len %li\n"), ++ __func__, lengths[i]); ++ goto out; ++ } ++ i++; ++ } ++ ++ if (maxlen) { ++ rpmlog(RPMLOG_DEBUG, _("%s: base64 decode success, len %li\n"), ++ __func__, maxlen); ++ ++ t = bin = xcalloc(num, maxlen); ++ ++ for (i = 0; i < num; i++) { ++ memcpy(t, arr[i], lengths[i]); ++ free(arr[i]); ++ t += maxlen; ++ } ++ *len = maxlen; ++ } ++ out: ++ free(arr); ++ free(lengths); ++ rpmtdFreeData(&td); ++ ++ return bin; ++} ++ + static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags) + { + headerGetFlags scareFlags = (flags & RPMFI_KEEPHEADER) ? +-- +2.27.0 + diff --git a/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch b/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch new file mode 100644 index 0000000..051c0bc --- /dev/null +++ b/0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch @@ -0,0 +1,206 @@ +From ef819fecfed22cab2ccbd128e5ede33db8f2d3e9 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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,6 +428,7 @@ typedef enum rpmSigTag_e { + RPMSIGTAG_SHA256 = RPMTAG_SHA256HEADER, + 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(¶ms, 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, ¶ms, &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(¶ms, 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, +- ¶ms, &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 + diff --git a/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch b/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch new file mode 100644 index 0000000..dba0ca6 --- /dev/null +++ b/0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch @@ -0,0 +1,162 @@ +From 22420d9ee652a25357727b00585dc3cfe78b2a80 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +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 +--- + 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 + diff --git a/0023-Process-verity-tag-on-package-read.patch b/0023-Process-verity-tag-on-package-read.patch new file mode 100644 index 0000000..c0b6b74 --- /dev/null +++ b/0023-Process-verity-tag-on-package-read.patch @@ -0,0 +1,189 @@ +From 34e751ccee43f799dd32f6b9c64020106dba9fac Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 13 Apr 2020 18:21:36 -0400 +Subject: [PATCH 23/33] Process verity tag on package read + +This processes verity signature tags on package read, and provides +accessor functions to access them. + +Signed-off-by: Jes Sorensen +--- + lib/rpmfi.c | 27 +++++++++++++++++++++++++++ + lib/rpmfi.h | 8 ++++++++ + lib/rpmfiles.h | 10 ++++++++++ + sign/rpmsignverity.c | 20 ++++++++++++++++---- + 4 files changed, 61 insertions(+), 4 deletions(-) + +diff --git a/lib/rpmfi.c b/lib/rpmfi.c +index 8c69d3e40..5fdbe02a2 100644 +--- a/lib/rpmfi.c ++++ b/lib/rpmfi.c +@@ -116,8 +116,10 @@ struct rpmfiles_s { + + int digestalgo; /*!< File digest algorithm */ + uint32_t *signatureoffs; /*!< File signature offsets */ ++ int veritysiglength; /*!< Verity signature length */ + unsigned char * digests; /*!< File digests in binary. */ + unsigned char * signatures; /*!< File signatures in binary. */ ++ unsigned char * veritysigs; /*!< Verity signatures in binary. */ + + struct nlinkHash_s * nlinks;/*!< Files connected by hardlinks */ + rpm_off_t * replacedSizes; /*!< (TR_ADDED) */ +@@ -582,6 +584,19 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len) + return signature; + } + ++const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len) ++{ ++ const unsigned char *vsignature = NULL; ++ ++ if (fi != NULL && ix >= 0 && ix < rpmfilesFC(fi)) { ++ if (fi->veritysigs != NULL) ++ vsignature = fi->veritysigs + (fi->veritysiglength * ix); ++ if (len) ++ *len = fi->veritysiglength; ++ } ++ return vsignature; ++} ++ + const char * rpmfilesFLink(rpmfiles fi, int ix) + { + const char * flink = NULL; +@@ -1268,6 +1283,7 @@ rpmfiles rpmfilesFree(rpmfiles fi) + fi->digests = _free(fi->digests); + fi->signatures = _free(fi->signatures); + fi->signatureoffs = _free(fi->signatureoffs); ++ fi->veritysigs = _free(fi->veritysigs); + fi->fcaps = _free(fi->fcaps); + + fi->cdict = _free(fi->cdict); +@@ -1649,6 +1665,12 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags) + totalfc, &fi->signatureoffs); + } + ++ fi->veritysigs = NULL; ++ if (!(flags & RPMFI_NOVERITYSIGNATURES)) { ++ fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES, ++ totalfc, &fi->veritysiglength); ++ } ++ + /* XXX TR_REMOVED doesn;t need fmtimes, frdevs, finodes */ + if (!(flags & RPMFI_NOFILEMTIMES)) + _hgfi(h, RPMTAG_FILEMTIMES, &td, scareFlags, fi->fmtimes); +@@ -1939,6 +1961,11 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len) + return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len); + } + ++const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len) ++{ ++ return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len); ++} ++ + uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp) + { + return rpmfilesFDepends(fi->files, fi ? fi->i : -1, fddictp); +diff --git a/lib/rpmfi.h b/lib/rpmfi.h +index 6ef70cd28..fcb9d3acd 100644 +--- a/lib/rpmfi.h ++++ b/lib/rpmfi.h +@@ -190,6 +190,14 @@ char * rpmfiFDigestHex(rpmfi fi, int *algo); + */ + const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen); + ++/** \ingroup rpmfi ++ * Return current verity (binary) signature of file info set iterator. ++ * @param fi file info set iterator ++ * @retval siglen signature length (pass NULL to ignore) ++ * @return current verity signature, NULL on invalid ++ */ ++const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen); ++ + /** \ingroup rpmfi + * Return current file linkto (i.e. symlink(2) target) from file info set iterator. + * @param fi file info set iterator +diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h +index daf572cf4..81b3d01a1 100644 +--- a/lib/rpmfiles.h ++++ b/lib/rpmfiles.h +@@ -119,6 +119,7 @@ enum rpmfiFlags_e { + RPMFI_NOFILEVERIFYFLAGS = (1 << 16), + RPMFI_NOFILEFLAGS = (1 << 17), + RPMFI_NOFILESIGNATURES = (1 << 18), ++ RPMFI_NOVERITYSIGNATURES = (1 << 19), + }; + + typedef rpmFlags rpmfiFlags; +@@ -442,6 +443,15 @@ const unsigned char * rpmfilesFDigest(rpmfiles fi, int ix, int *algo, size_t *le + */ + const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len); + ++/** \ingroup rpmfiles ++ * Return file verity signature (binary) ++ * @param fi file info set ++ * @param ix file index ++ * @retval len signature length (pass NULL to ignore) ++ * @return verity signature, NULL on invalid ++ */ ++const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len); ++ + /** \ingroup rpmfiles + * Return file rdev from file info set. + * @param fi file info set +diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c +index 3bb23a18d..177561957 100644 +--- a/sign/rpmsignverity.c ++++ b/sign/rpmsignverity.c +@@ -15,6 +15,7 @@ + #include "lib/rpmtypes.h" /* rpmRC */ + #include + #include "rpmio/rpmio_internal.h" ++#include "rpmio/rpmbase64.h" + #include "lib/rpmvs.h" + + #include "sign/rpmsignverity.h" +@@ -40,7 +41,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, + struct libfsverity_signature_params sig_params; + struct libfsverity_digest *digest = NULL; + rpm_loff_t file_size; +- char *digest_hex, *sig_hex = NULL; ++ char *digest_hex, *digest_base64, *sig_base64 = NULL, *sig_hex = NULL; + uint8_t *sig = NULL; + int status; + +@@ -60,8 +61,14 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, + } + + digest_hex = pgpHexStr(digest->digest, digest->digest_size); +- rpmlog(RPMLOG_DEBUG, _("digest(%i): %s\n"), +- digest->digest_size, digest_hex); ++ digest_base64 = rpmBase64Encode(digest->digest, digest->digest_size, -1); ++ rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest(%i): %s, idx %i\n"), ++ file_size, rpmfiFN(fi), digest->digest_size, digest_hex, ++ rpmfiFX(fi)); ++ rpmlog(RPMLOG_DEBUG, _("file(size %li): %s: digest sz (%i): base64 sz (%li), %s, idx %i\n"), ++ file_size, rpmfiFN(fi), digest->digest_size, strlen(digest_base64), ++ digest_base64, rpmfiFX(fi)); ++ + free(digest_hex); + + memset(&sig_params, 0, sizeof(struct libfsverity_signature_params)); +@@ -73,10 +80,15 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, + } + + sig_hex = pgpHexStr(sig, *sig_size); ++ sig_base64 = rpmBase64Encode(sig, *sig_size, -1); ++ rpmlog(RPMLOG_DEBUG, _("%s: sig_size(%li), base64_size(%li), idx %i: signature:\n%s\n"), ++ rpmfiFN(fi), *sig_size, strlen(sig_base64), rpmfiFX(fi), sig_hex); + out: ++ free(sig_hex); ++ + free(digest); + free(sig); +- return sig_hex; ++ return sig_base64; + } + + rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, +-- +2.27.0 + diff --git a/0024-Generate-a-zero-length-signature-for-symlinks.patch b/0024-Generate-a-zero-length-signature-for-symlinks.patch new file mode 100644 index 0000000..2fc3f5a --- /dev/null +++ b/0024-Generate-a-zero-length-signature-for-symlinks.patch @@ -0,0 +1,33 @@ +From 202359dc598f2162175e3a8552c9b338d27b8989 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Tue, 14 Apr 2020 10:33:32 -0400 +Subject: [PATCH 24/33] Generate a zero-length signature for symlinks + +The fsverity utility follows the symlink when generating a signature. +Since we don't want to sign the same file twice, we need to skip these +links, and instead just generate a dummy zero-length signature here. + +Signed-off-by: Jes Sorensen +--- + sign/rpmsignverity.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c +index 177561957..2c7d21620 100644 +--- a/sign/rpmsignverity.c ++++ b/sign/rpmsignverity.c +@@ -45,7 +45,10 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, + uint8_t *sig = NULL; + int status; + +- file_size = rpmfiFSize(fi); ++ if (S_ISLNK(rpmfiFMode(fi))) ++ file_size = 0; ++ else ++ file_size = rpmfiFSize(fi); + + memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); + params.version = 1; +-- +2.27.0 + diff --git a/0025-rpmsignverity.c-Clean-up-debug-logging.patch b/0025-rpmsignverity.c-Clean-up-debug-logging.patch new file mode 100644 index 0000000..bb6e4f3 --- /dev/null +++ b/0025-rpmsignverity.c-Clean-up-debug-logging.patch @@ -0,0 +1,40 @@ +From 7e50b3f4b2ebb963d1080a0a1469517ef81f780c Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Tue, 14 Apr 2020 12:08:09 -0400 +Subject: [PATCH 25/33] rpmsignverity.c: Clean up debug logging + +Put most logging in one place and avoid printing the same info twice. + +Signed-off-by: Jes Sorensen +--- + sign/rpmsignverity.c | 5 ----- + 1 file changed, 5 deletions(-) + +diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c +index 2c7d21620..445e1197c 100644 +--- a/sign/rpmsignverity.c ++++ b/sign/rpmsignverity.c +@@ -104,7 +104,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, + rpmfi hfi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_FLAGS_QUERY); + rpmts ts = rpmtsCreate(); + struct rpmtd_s td; +- rpm_loff_t file_size; + off_t offset = Ftell(fd); + const char *compr; + char *rpmio_flags = NULL; +@@ -158,12 +157,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, + 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)); +- + signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert); + } + +-- +2.27.0 + diff --git a/0026-fsverity-add-tag-for-fsverity-algorithm.patch b/0026-fsverity-add-tag-for-fsverity-algorithm.patch new file mode 100644 index 0000000..74b2fc1 --- /dev/null +++ b/0026-fsverity-add-tag-for-fsverity-algorithm.patch @@ -0,0 +1,161 @@ +From e339fdbbd0b81dc1fcdc2032e861b8a5fa6e062d Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 20 Apr 2020 13:40:26 -0400 +Subject: [PATCH 26/33] fsverity - add tag for fsverity algorithm + +The default algorith is SHA256, but fsverity allows for other +algorithms, so add a tag to handle this. + +Signed-off-by: Jes Sorensen +--- + lib/package.c | 1 + + lib/rpmfi.c | 2 ++ + lib/rpmtag.h | 2 ++ + sign/rpmsignverity.c | 32 ++++++++++++++++++++++++++++---- + 4 files changed, 33 insertions(+), 4 deletions(-) + +diff --git a/lib/package.c b/lib/package.c +index c6108f686..3c761d365 100644 +--- a/lib/package.c ++++ b/lib/package.c +@@ -46,6 +46,7 @@ struct taglate_s { + { RPMSIGTAG_FILESIGNATURES, RPMTAG_FILESIGNATURES, 0, 1 }, + { RPMSIGTAG_FILESIGNATURELENGTH, RPMTAG_FILESIGNATURELENGTH, 1, 1 }, + { RPMSIGTAG_VERITYSIGNATURES, RPMTAG_VERITYSIGNATURES, 0, 0 }, ++ { RPMSIGTAG_VERITYSIGNATUREALGO, RPMTAG_VERITYSIGNATUREALGO, 1, 0 }, + { RPMSIGTAG_SHA1, RPMTAG_SHA1HEADER, 1, 0 }, + { RPMSIGTAG_SHA256, RPMTAG_SHA256HEADER, 1, 0 }, + { RPMSIGTAG_DSA, RPMTAG_DSAHEADER, 0, 0 }, +diff --git a/lib/rpmfi.c b/lib/rpmfi.c +index 5fdbe02a2..70f05f509 100644 +--- a/lib/rpmfi.c ++++ b/lib/rpmfi.c +@@ -118,6 +118,7 @@ struct rpmfiles_s { + int digestalgo; /*!< File digest algorithm */ + uint32_t *signatureoffs; /*!< File signature offsets */ + int veritysiglength; /*!< Verity signature length */ ++ uint16_t verityalgo; /*!< Verity algorithm */ + unsigned char * digests; /*!< File digests in binary. */ + unsigned char * signatures; /*!< File signatures in binary. */ + unsigned char * veritysigs; /*!< Verity signatures in binary. */ +@@ -1667,6 +1668,7 @@ static int rpmfilesPopulate(rpmfiles fi, Header h, rpmfiFlags flags) + + fi->veritysigs = NULL; + if (!(flags & RPMFI_NOVERITYSIGNATURES)) { ++ fi->verityalgo = headerGetNumber(h, RPMTAG_VERITYSIGNATUREALGO); + fi->veritysigs = base2bin(h, RPMTAG_VERITYSIGNATURES, + totalfc, &fi->veritysiglength); + } +diff --git a/lib/rpmtag.h b/lib/rpmtag.h +index 478457ecb..8d1efcc79 100644 +--- a/lib/rpmtag.h ++++ b/lib/rpmtag.h +@@ -68,6 +68,7 @@ typedef enum rpmTag_e { + /* RPMTAG_SIG_BASE+18 reserved for RPMSIGTAG_FILESIGNATURES */ + /* RPMTAG_SIG_BASE+19 reserved for RPMSIGTAG_FILESIGNATURELENGTH */ + RPMTAG_VERITYSIGNATURES = RPMTAG_SIG_BASE+20, /* s[] */ ++ RPMTAG_VERITYSIGNATUREALGO = RPMTAG_SIG_BASE+21, /* i */ + + RPMTAG_NAME = 1000, /* s */ + #define RPMTAG_N RPMTAG_NAME /* s */ +@@ -431,6 +432,7 @@ typedef enum rpmSigTag_e { + RPMSIGTAG_FILESIGNATURES = RPMTAG_SIG_BASE + 18, + RPMSIGTAG_FILESIGNATURELENGTH = RPMTAG_SIG_BASE + 19, + RPMSIGTAG_VERITYSIGNATURES = RPMTAG_VERITYSIGNATURES, ++ RPMSIGTAG_VERITYSIGNATUREALGO = RPMTAG_VERITYSIGNATUREALGO, + } rpmSigTag; + + +diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c +index 445e1197c..55096e732 100644 +--- a/sign/rpmsignverity.c ++++ b/sign/rpmsignverity.c +@@ -35,7 +35,7 @@ static int rpmVerityRead(void *opaque, void *buf, size_t size) + } + + static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, +- char *keypass, char *cert) ++ char *keypass, char *cert, uint16_t algo) + { + struct libfsverity_merkle_tree_params params; + struct libfsverity_signature_params sig_params; +@@ -52,7 +52,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, + + memset(¶ms, 0, sizeof(struct libfsverity_merkle_tree_params)); + params.version = 1; +- params.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; ++ params.hash_algorithm = algo; + params.block_size = RPM_FSVERITY_BLKSZ; + params.salt_size = 0 /* salt_size */; + params.salt = NULL /* salt */; +@@ -111,6 +111,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, + char **signatures = NULL; + size_t sig_size; + int nr_files, idx; ++ uint16_t algo; ++ uint32_t algo32; + + Fseek(fd, 0, SEEK_SET); + rpmtsSetVSFlags(ts, RPMVSF_MASK_NODIGESTS | RPMVSF_MASK_NOSIGNATURES | +@@ -142,6 +144,7 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, + * Should this be sigh from the cloned fd or the sigh we received? + */ + headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES); ++ headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO); + + /* + * The payload doesn't include special files, like ghost files, and +@@ -153,20 +156,24 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, + nr_files = rpmfiFC(hfi); + signatures = xcalloc(nr_files, sizeof(char *)); + ++ algo = FS_VERITY_HASH_ALG_SHA256; ++ + rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"), + nr_files, rpmfiFC(fi)); + + while (rpmfiNext(fi) >= 0) { + idx = rpmfiFX(fi); + +- signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert); ++ signatures[idx] = rpmVeritySignFile(fi, &sig_size, key, keypass, cert, ++ algo); + } + + while (rpmfiNext(hfi) >= 0) { + idx = rpmfiFX(hfi); + if (signatures[idx]) + continue; +- signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert); ++ signatures[idx] = rpmVeritySignFile(hfi, &sig_size, key, keypass, cert, ++ algo); + } + + rpmtdReset(&td); +@@ -187,6 +194,23 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, + signatures[idx] = NULL; + } + ++ if (sig_size == 0) { ++ rpmlog(RPMLOG_ERR, _("Zero length fsverity signature\n")); ++ rc = RPMRC_FAIL; ++ goto out; ++ } ++ ++ rpmtdReset(&td); ++ ++ /* RPM doesn't like new 16 bit types, so use a 32 bit tag */ ++ algo32 = algo; ++ rpmtdReset(&td); ++ td.tag = RPMSIGTAG_VERITYSIGNATUREALGO; ++ td.type = RPM_INT32_TYPE; ++ td.data = &algo32; ++ td.count = 1; ++ headerPut(sigh, &td, HEADERPUT_DEFAULT); ++ + rpmlog(RPMLOG_DEBUG, _("sigh size: %i\n"), headerSizeof(sigh, 0)); + + rc = RPMRC_OK; +-- +2.27.0 + diff --git a/0027-plugins-fsverity-Install-fsverity-signatures.patch b/0027-plugins-fsverity-Install-fsverity-signatures.patch new file mode 100644 index 0000000..c302c97 --- /dev/null +++ b/0027-plugins-fsverity-Install-fsverity-signatures.patch @@ -0,0 +1,257 @@ +From f1a92e02faa2715777286acd07b8d0f465c5df37 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 20 Apr 2020 11:11:25 -0400 +Subject: [PATCH 27/33] plugins/fsverity: Install fsverity signatures + +This plugin installs fsverity signatures for regular files, when a signature +is found in the RPM. It tries to enable them unconditionally, but fails +gracefully if fsverity isn't supported or enabled. + +Signed-off-by: Jes Sorensen +--- + configure.ac | 29 ++++++++ + macros.in | 4 + + plugins/Makefile.am | 7 ++ + plugins/fsverity.c | 177 ++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 217 insertions(+) + create mode 100644 plugins/fsverity.c + +diff --git a/configure.ac b/configure.ac +index cc7144440..7d3c31831 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1049,6 +1049,11 @@ AS_IF([test "$enable_plugins" != no],[ + ]) + AM_CONDITIONAL(IMA, [test "x$ac_cv_func_lsetxattr" = xyes]) + ++AS_IF([test "$enable_plugins" != no],[ ++AC_CHECK_HEADERS([linux/fsverity.h],[FSVERITY_IOCTL="yes"]) ++]) ++AM_CONDITIONAL(FSVERITY_IOCTL,[test "x$FSVERITY_IOCTL" = xyes]) ++ + #================= + # Check for fapolicyd support + AC_ARG_WITH(fapolicyd, +diff --git a/macros.in b/macros.in +index fe8862903..3c722146b 100644 +--- a/macros.in ++++ b/macros.in +@@ -767,6 +767,9 @@ package or when debugging this package.\ + # a wrong or missing signature. + #%_ima_sign_config_files 0 + ++# Set to 1 to have fsverity signatures written for %config files. ++#%_fsverity_sign_config_files 0 ++ + # + # Default output format string for rpm -qa + # +@@ -1185,6 +1188,7 @@ package or when debugging this package.\ + %__transaction_syslog %{__plugindir}/syslog.so + %__transaction_ima %{__plugindir}/ima.so + %__transaction_fapolicyd %{__plugindir}/fapolicyd.so ++%__transaction_fsverity %{__plugindir}/fsverity.so + %__transaction_prioreset %{__plugindir}/prioreset.so + %__transaction_audit %{__plugindir}/audit.so + +diff --git a/plugins/Makefile.am b/plugins/Makefile.am +index cbfb81e19..e51b71f62 100644 +--- a/plugins/Makefile.am ++++ b/plugins/Makefile.am +@@ -48,3 +48,10 @@ audit_la_sources = audit.c + audit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @WITH_AUDIT_LIB@ + plugins_LTLIBRARIES += audit.la + endif ++ ++if FSVERITY_IOCTL ++fsverity_la_sources = fsverity.c ++fsverity_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la ++plugins_LTLIBRARIES += fsverity.la ++endif ++ +diff --git a/plugins/fsverity.c b/plugins/fsverity.c +new file mode 100644 +index 000000000..15ddcf33e +--- /dev/null ++++ b/plugins/fsverity.c +@@ -0,0 +1,177 @@ ++/** ++ * Copyright (C) 2020 Facebook ++ * ++ * Author: Jes Sorensen ++ */ ++ ++#include "system.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "lib/rpmfs.h" ++#include "lib/rpmplugin.h" ++#include "lib/rpmte_internal.h" ++ ++#include "sign/rpmsignverity.h" ++ ++static int sign_config_files = 0; ++ ++/* ++ * This unconditionally tries to apply the fsverity signature to a file, ++ * but fails gracefully if the file system doesn't support it or the ++ * verity feature flag isn't enabled in the file system (ext4). ++ */ ++static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, ++ const char *path, const char *dest, ++ mode_t file_mode, rpmFsmOp op) ++{ ++ struct fsverity_enable_arg arg; ++ const unsigned char * signature = NULL; ++ size_t len; ++ int rc = RPMRC_OK; ++ int fd; ++ rpmFileAction action = XFO_ACTION(op); ++ char *buffer; ++ ++ /* Ignore skipped files and unowned directories */ ++ if (XFA_SKIPPING(action) || (op & FAF_UNOWNED)) { ++ rpmlog(RPMLOG_DEBUG, "fsverity skipping early: path %s dest %s\n", ++ path, dest); ++ goto exit; ++ } ++ ++ /* ++ * Do not install signatures for config files unless the ++ * user explicitly asks for it. ++ */ ++ if (rpmfiFFlags(fi) & RPMFILE_CONFIG) { ++ if (!(rpmfiFMode(fi) & (S_IXUSR|S_IXGRP|S_IXOTH)) && ++ !sign_config_files) { ++ rpmlog(RPMLOG_DEBUG, "fsverity skipping: path %s dest %s\n", ++ path, dest); ++ ++ goto exit; ++ } ++ } ++ ++ /* ++ * Right now fsverity doesn't deal with symlinks or directories, so do ++ * not try to install signatures for non regular files. ++ */ ++ if (!S_ISREG(rpmfiFMode(fi))) { ++ rpmlog(RPMLOG_DEBUG, "fsverity skipping non regular: path %s dest %s\n", ++ path, dest); ++ goto exit; ++ } ++ ++ signature = rpmfiVSignature(fi, &len); ++ if (!signature || !len) { ++ rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n", ++ path, dest); ++ goto exit; ++ } ++ ++ memset(&arg, 0, sizeof(arg)); ++ arg.version = 1; ++ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; ++ arg.block_size = RPM_FSVERITY_BLKSZ; ++ arg.sig_ptr = (uintptr_t)signature; ++ arg.sig_size = len; ++ ++ buffer = pgpHexStr(signature, arg.sig_size); ++ rpmlog(RPMLOG_DEBUG, "applying signature: %s\n", buffer); ++ free(buffer); ++ ++ fd = open(path, O_RDONLY); ++ if (fd < 0) { ++ rpmlog(RPMLOG_ERR, "failed to open path %s\n", path); ++ goto exit; ++ } ++ ++ /* ++ * Enable fsverity on the file. ++ * fsverity not supported by file system (ENOTTY) and fsverity not ++ * enabled on file system are expected and not considered ++ * errors. Every other non-zero error code will result in the ++ * installation failing. ++ */ ++ if (ioctl(fd, FS_IOC_ENABLE_VERITY, &arg) != 0) { ++ switch(errno) { ++ case EBADMSG: ++ rpmlog(RPMLOG_DEBUG, "invalid or malformed fsverity signature for %s\n", path); ++ rc = RPMRC_FAIL; ++ break; ++ case EEXIST: ++ rpmlog(RPMLOG_DEBUG, "fsverity signature already enabled %s\n", ++ path); ++ rc = RPMRC_FAIL; ++ break; ++ case EINVAL: ++ rpmlog(RPMLOG_DEBUG, "invalid arguments for ioctl %s\n", path); ++ rc = RPMRC_FAIL; ++ break; ++ case EKEYREJECTED: ++ rpmlog(RPMLOG_DEBUG, "signature doesn't match file %s\n", path); ++ rc = RPMRC_FAIL; ++ break; ++ case EMSGSIZE: ++ rpmlog(RPMLOG_DEBUG, "invalid signature size for %s\n", path); ++ rc = RPMRC_FAIL; ++ break; ++ case ENOPKG: ++ rpmlog(RPMLOG_DEBUG, "unsupported signature algoritm (%i) for %s\n", ++ arg.hash_algorithm, path); ++ rc = RPMRC_FAIL; ++ break; ++ case ETXTBSY: ++ rpmlog(RPMLOG_DEBUG, "file is open by other process %s\n", ++ path); ++ rc = RPMRC_FAIL; ++ break; ++ case ENOTTY: ++ rpmlog(RPMLOG_DEBUG, "fsverity not supported by file system for %s\n", ++ path); ++ break; ++ case EOPNOTSUPP: ++ rpmlog(RPMLOG_DEBUG, "fsverity not enabled on file system for %s\n", ++ path); ++ break; ++ default: ++ rpmlog(RPMLOG_DEBUG, "failed to enable verity (errno %i) for %s\n", ++ errno, path); ++ rc = RPMRC_FAIL; ++ break; ++ } ++ } ++ ++ rpmlog(RPMLOG_DEBUG, "fsverity enabled signature for: path %s dest %s\n", ++ path, dest); ++ close(fd); ++exit: ++ return rc; ++} ++ ++static rpmRC fsverity_init(rpmPlugin plugin, rpmts ts) ++{ ++ sign_config_files = rpmExpandNumeric("%{?_fsverity_sign_config_files}"); ++ ++ rpmlog(RPMLOG_DEBUG, "fsverity_init\n"); ++ ++ return RPMRC_OK; ++} ++ ++struct rpmPluginHooks_s fsverity_hooks = { ++ .init = fsverity_init, ++ .fsm_file_prepare = fsverity_fsm_file_prepare, ++}; +-- +2.27.0 + diff --git a/0028-fsverity-plugin-Use-tag-for-algorithm.patch b/0028-fsverity-plugin-Use-tag-for-algorithm.patch new file mode 100644 index 0000000..0b9bb41 --- /dev/null +++ b/0028-fsverity-plugin-Use-tag-for-algorithm.patch @@ -0,0 +1,116 @@ +From 5a5286ac37cd58779cc0e5b69088d9acc8f40c4e Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 20 Apr 2020 14:13:51 -0400 +Subject: [PATCH 28/33] fsverity plugin: Use tag for algorithm + +This uses the algorithm from the tag, if available. Fallback is SHA256. + +Signed-off-by: Jes Sorensen +--- + lib/rpmfi.c | 9 ++++++--- + lib/rpmfi.h | 3 ++- + lib/rpmfiles.h | 3 ++- + plugins/fsverity.c | 8 ++++++-- + 4 files changed, 16 insertions(+), 7 deletions(-) + +diff --git a/lib/rpmfi.c b/lib/rpmfi.c +index 70f05f509..3e2b4e676 100644 +--- a/lib/rpmfi.c ++++ b/lib/rpmfi.c +@@ -585,7 +585,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len) + return signature; + } + +-const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len) ++const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len, ++ uint16_t *algo) + { + const unsigned char *vsignature = NULL; + +@@ -594,6 +595,8 @@ const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len) + vsignature = fi->veritysigs + (fi->veritysiglength * ix); + if (len) + *len = fi->veritysiglength; ++ if (algo) ++ *algo = fi->verityalgo; + } + return vsignature; + } +@@ -1963,9 +1966,9 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *len) + return rpmfilesFSignature(fi->files, fi ? fi->i : -1, len); + } + +-const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len) ++const unsigned char * rpmfiVSignature(rpmfi fi, size_t *len, uint16_t *algo) + { +- return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len); ++ return rpmfilesVSignature(fi->files, fi ? fi->i : -1, len, algo); + } + + uint32_t rpmfiFDepends(rpmfi fi, const uint32_t ** fddictp) +diff --git a/lib/rpmfi.h b/lib/rpmfi.h +index fcb9d3acd..6fd2747d6 100644 +--- a/lib/rpmfi.h ++++ b/lib/rpmfi.h +@@ -194,9 +194,10 @@ const unsigned char * rpmfiFSignature(rpmfi fi, size_t *siglen); + * Return current verity (binary) signature of file info set iterator. + * @param fi file info set iterator + * @retval siglen signature length (pass NULL to ignore) ++ * @retval algo fsverity algorithm + * @return current verity signature, NULL on invalid + */ +-const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen); ++const unsigned char * rpmfiVSignature(rpmfi fi, size_t *siglen, uint16_t *algo); + + /** \ingroup rpmfi + * Return current file linkto (i.e. symlink(2) target) from file info set iterator. +diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h +index 81b3d01a1..64b33281a 100644 +--- a/lib/rpmfiles.h ++++ b/lib/rpmfiles.h +@@ -450,7 +450,8 @@ const unsigned char * rpmfilesFSignature(rpmfiles fi, int ix, size_t *len); + * @retval len signature length (pass NULL to ignore) + * @return verity signature, NULL on invalid + */ +-const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len); ++const unsigned char * rpmfilesVSignature(rpmfiles fi, int ix, size_t *len, ++ uint16_t *algo); + + /** \ingroup rpmfiles + * Return file rdev from file info set. +diff --git a/plugins/fsverity.c b/plugins/fsverity.c +index 15ddcf33e..1e7f38b38 100644 +--- a/plugins/fsverity.c ++++ b/plugins/fsverity.c +@@ -39,6 +39,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + struct fsverity_enable_arg arg; + const unsigned char * signature = NULL; + size_t len; ++ uint16_t algo = 0; + int rc = RPMRC_OK; + int fd; + rpmFileAction action = XFO_ACTION(op); +@@ -75,7 +76,7 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + goto exit; + } + +- signature = rpmfiVSignature(fi, &len); ++ signature = rpmfiVSignature(fi, &len, &algo); + if (!signature || !len) { + rpmlog(RPMLOG_DEBUG, "fsverity no signature for: path %s dest %s\n", + path, dest); +@@ -84,7 +85,10 @@ static rpmRC fsverity_fsm_file_prepare(rpmPlugin plugin, rpmfi fi, + + memset(&arg, 0, sizeof(arg)); + arg.version = 1; +- arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; ++ if (algo) ++ arg.hash_algorithm = algo; ++ else ++ arg.hash_algorithm = FS_VERITY_HASH_ALG_SHA256; + arg.block_size = RPM_FSVERITY_BLKSZ; + arg.sig_ptr = (uintptr_t)signature; + arg.sig_size = len; +-- +2.27.0 + diff --git a/0029-Add-fsverity-tags-to-rpmgeneral.at.patch b/0029-Add-fsverity-tags-to-rpmgeneral.at.patch new file mode 100644 index 0000000..6575b99 --- /dev/null +++ b/0029-Add-fsverity-tags-to-rpmgeneral.at.patch @@ -0,0 +1,28 @@ +From 3132053a066b3dc8aa38b358ecd316ee60fd0f7c Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 20 Apr 2020 18:52:08 -0400 +Subject: [PATCH 29/33] Add fsverity tags to rpmgeneral.at + +Make sure we pass the checks with the new tags in place. + +Signed-off-by: Jes Sorensen +--- + tests/rpmgeneral.at | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/tests/rpmgeneral.at b/tests/rpmgeneral.at +index 45d38698b..8a7dc827f 100644 +--- a/tests/rpmgeneral.at ++++ b/tests/rpmgeneral.at +@@ -291,6 +291,8 @@ VERBOSE + VERIFYSCRIPT + VERIFYSCRIPTFLAGS + VERIFYSCRIPTPROG ++VERITYSIGNATUREALGO ++VERITYSIGNATURES + VERSION + XPM + ]) +-- +2.27.0 + diff --git a/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch b/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch new file mode 100644 index 0000000..d872d5e --- /dev/null +++ b/0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch @@ -0,0 +1,117 @@ +From 46db4f6827840e828f42424454410b930895d9a7 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Mon, 13 Apr 2020 18:24:31 -0400 +Subject: [PATCH 30/33] Add --delfilesign flag to delete IMA and fsverity file + signatures + +This allows a user to remove both types of file signatures from the +package. Previously there was no way to delete IMA signatures, only +replace them by first removing the package signature and then +resigning the package and the files. + +Signed-off-by: Jes Sorensen +--- + rpmsign.c | 12 ++++++++++++ + sign/rpmgensig.c | 17 ++++++++++++++++- + sign/rpmsign.h | 9 +++++++++ + 3 files changed, 37 insertions(+), 1 deletion(-) + +diff --git a/rpmsign.c b/rpmsign.c +index 074dd8b13..e43811e9f 100644 +--- a/rpmsign.c ++++ b/rpmsign.c +@@ -14,6 +14,7 @@ enum modes { + MODE_ADDSIGN = (1 << 0), + MODE_RESIGN = (1 << 1), + MODE_DELSIGN = (1 << 2), ++ MODE_DELFILESIGN = (1 << 3), + }; + + static int mode = MODE_NONE; +@@ -35,6 +36,10 @@ static struct poptOption signOptsTable[] = { + N_("sign package(s) (identical to --addsign)"), NULL }, + { "delsign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, MODE_DELSIGN, + N_("delete package signatures"), NULL }, ++#if defined(WITH_IMAEVM) || defined(WITH_FSVERITY) ++ { "delfilesign", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), &mode, ++ MODE_DELFILESIGN, N_("delete IMA and fsverity file signatures"), NULL }, ++#endif + { "rpmv3", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), + &sargs.signflags, RPMSIGN_FLAG_RPMV3, + N_("create rpm v3 header+payload signatures") }, +@@ -207,6 +212,13 @@ int main(int argc, char *argv[]) + ec++; + } + break; ++ case MODE_DELFILESIGN: ++ ec = 0; ++ while ((arg = poptGetArg(optCon)) != NULL) { ++ if (rpmPkgDelFileSign(arg, &sargs) < 0) ++ ec++; ++ } ++ break; + case MODE_NONE: + printUsage(optCon, stderr, 0); + break; +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index 8d5c5858f..02cf0bc62 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -336,6 +336,14 @@ static void deleteSigs(Header sigh) + headerDel(sigh, RPMSIGTAG_PGP5); + } + ++static void deleteFileSigs(Header sigh) ++{ ++ headerDel(sigh, RPMSIGTAG_FILESIGNATURELENGTH); ++ headerDel(sigh, RPMSIGTAG_FILESIGNATURES); ++ headerDel(sigh, RPMSIGTAG_VERITYSIGNATURES); ++ headerDel(sigh, RPMSIGTAG_VERITYSIGNATUREALGO); ++} ++ + static int haveSignature(rpmtd sigtd, Header h) + { + pgpDigParams sig1 = NULL; +@@ -580,7 +588,9 @@ static int rpmSign(const char *rpm, int deleting, int flags) + goto exit; + } + +- if (deleting) { /* Nuke all the signature tags. */ ++ if (deleting == 2) { /* Nuke IMA + fsverity file signature tags. */ ++ deleteFileSigs(sigh); ++ } else if (deleting) { /* Nuke all the signature tags. */ + deleteSigs(sigh); + } else { + /* Signature target containing header + payload */ +@@ -745,3 +755,8 @@ int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args) + { + return rpmSign(path, 1, 0); + } ++ ++int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args) ++{ ++ return rpmSign(path, 2, 0); ++} +diff --git a/sign/rpmsign.h b/sign/rpmsign.h +index 2b8a10a1a..5169741dd 100644 +--- a/sign/rpmsign.h ++++ b/sign/rpmsign.h +@@ -44,6 +44,15 @@ int rpmPkgSign(const char *path, const struct rpmSignArgs * args); + */ + int rpmPkgDelSign(const char *path, const struct rpmSignArgs * args); + ++ ++/** \ingroup rpmsign ++ * Delete file signature(s) from a package ++ * @param path path to package ++ * @param args signing parameters (or NULL for defaults) ++ * @return 0 on success ++ */ ++int rpmPkgDelFileSign(const char *path, const struct rpmSignArgs * args); ++ + #ifdef __cplusplus + } + #endif +-- +2.27.0 + diff --git a/0031-Update-man-page-for-rpmsign.patch b/0031-Update-man-page-for-rpmsign.patch new file mode 100644 index 0000000..938e0f1 --- /dev/null +++ b/0031-Update-man-page-for-rpmsign.patch @@ -0,0 +1,72 @@ +From 4d243b7e692e3803a764343dfed23feb1c656f0b Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Tue, 12 May 2020 13:42:34 -0400 +Subject: [PATCH 31/33] Update man page for rpmsign + +This documents the new arguments --signverity and --certpath required +to sign a package with fsverity signatures. + +Signed-off-by: Jes Sorensen +--- + doc/rpmsign.8 | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/doc/rpmsign.8 b/doc/rpmsign.8 +index f7ceae89b..a212746fe 100644 +--- a/doc/rpmsign.8 ++++ b/doc/rpmsign.8 +@@ -9,6 +9,8 @@ rpmsign \- RPM Package Signing + + \fBrpm\fR \fB--delsign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR + ++\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR ++ + .SS "rpmsign-options" + .PP + [\fb--rpmv3\fR] +@@ -30,6 +32,12 @@ packages with a MD5/SHA1 checksums cannot be signed in FIPS mode. + .PP + Delete all signatures from each package \fIPACKAGE_FILE\fR given. + ++\fBrpm\fR \fB--delfilesign\fR \fB\fIPACKAGE_FILE\fB\fR\fI ...\fR ++ ++.PP ++Delete all IMA and fsverity file signatures from each package ++\fIPACKAGE_FILE\fR given. ++ + .SS "SIGN OPTIONS" + .PP + .TP +@@ -44,12 +52,23 @@ signature verifiable with rpm < 4.14 or other interoperability reasons. + \fB--fskpath \fIKEY\fB\fR + Used with \fB--signfiles\fR, use file signing key \fIKey\fR. + .TP ++\fB--certpath \fICERT\fB\fR ++Used with \fB--signverity\fR, use file signing certificate \fICert\fR. ++.TP + \fB--signfiles\fR + Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must + be set to a supported algorithm before building the package. The + supported algorithms are SHA1, SHA256, SHA384, and SHA512, which are + represented as 2, 8, 9, and 10 respectively. The file signing key (RSA + private key) must be set before signing the package, it can be configured on the command line with \fB--fskpath\fR or the macro %_file_signing_key. ++.TP ++\fB--signverity\fR ++Sign package files with fsverity signatures. The file signing key (RSA ++private key) and the signing certificate must be set before signing ++the package. The key can be configured on the command line with ++\fB--fskpath\fR or the macro %_file_signing_key, and the cert can be ++configured on the command line with \fB--certpath\fR or the macro ++%_file_signing_cert. + + .SS "USING GPG TO SIGN PACKAGES" + .PP +@@ -110,4 +129,5 @@ Jeff Johnson + Erik Troan + Panu Matilainen + Fionnuala Gunter ++Jes Sorensen + .fi +-- +2.27.0 + diff --git a/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch b/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch new file mode 100644 index 0000000..6a20363 --- /dev/null +++ b/0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch @@ -0,0 +1,168 @@ +From 3669fecaba2858aeca44d1bfc265760611ea8834 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Wed, 10 Jun 2020 12:30:54 -0400 +Subject: [PATCH 32/33] rpmsign: Add argument to specify algorithm for fsverity + signatures + +The argument --verity-algo can be used to specify the algorithm for +the fsverity signatures. If nothing is specified, this will default to +sha256. The available algorithms depend on libfsverity, currently +sha256 and sha512 are supported. + +Signed-off-by: Jes Sorensen +--- + doc/rpmsign.8 | 3 +++ + rpmsign.c | 7 +++++++ + sign/rpmgensig.c | 22 ++++++++++++++++++++-- + sign/rpmsignverity.c | 6 +++--- + sign/rpmsignverity.h | 2 +- + 5 files changed, 34 insertions(+), 6 deletions(-) + +diff --git a/doc/rpmsign.8 b/doc/rpmsign.8 +index a212746fe..5165e39f9 100644 +--- a/doc/rpmsign.8 ++++ b/doc/rpmsign.8 +@@ -55,6 +55,9 @@ Used with \fB--signfiles\fR, use file signing key \fIKey\fR. + \fB--certpath \fICERT\fB\fR + Used with \fB--signverity\fR, use file signing certificate \fICert\fR. + .TP ++\fB--verityalgo \fIALG\fB\fR ++Used with \fB--signverity\fR, to specify the signing algorithm. sha256 and sha512 are supported, with sha256 being the default if this argument is not specified. This can also be specified with the macro %_verity_algorithm ++.TP + \fB--signfiles\fR + Sign package files. The macro \fB%_binary_filedigest_algorithm\fR must + be set to a supported algorithm before building the package. The +diff --git a/rpmsign.c b/rpmsign.c +index e43811e9f..12299379c 100644 +--- a/rpmsign.c ++++ b/rpmsign.c +@@ -25,6 +25,7 @@ static char * fileSigningKey = NULL; + #endif + #ifdef WITH_FSVERITY + static char * fileSigningCert = NULL; ++static char * verityAlgorithm = NULL; + #endif + + static struct rpmSignArgs sargs = {NULL, 0, 0}; +@@ -52,6 +53,9 @@ static struct poptOption signOptsTable[] = { + { "signverity", '\0', (POPT_ARG_VAL|POPT_ARGFLAG_OR), + &sargs.signflags, RPMSIGN_FLAG_FSVERITY, + N_("generate fsverity signatures for package(s) files"), NULL}, ++ { "verityalgo", '\0', POPT_ARG_STRING, &verityAlgorithm, 0, ++ N_("algorithm to use for verity signatures, default sha256"), ++ N_("") }, + { "certpath", '\0', POPT_ARG_STRING, &fileSigningCert, 0, + N_("use file signing cert "), + N_("") }, +@@ -138,6 +142,9 @@ static int doSign(poptContext optCon, struct rpmSignArgs *sargs) + if (fileSigningCert) { + rpmPushMacro(NULL, "_file_signing_cert", NULL, fileSigningCert, RMIL_GLOBAL); + } ++ if (verityAlgorithm) { ++ rpmPushMacro(NULL, "_verity_algorithm", NULL, verityAlgorithm, RMIL_GLOBAL); ++ } + #endif + + if (flags_sign_files(sargs->signflags)) { +diff --git a/sign/rpmgensig.c b/sign/rpmgensig.c +index 02cf0bc62..b3b02828a 100644 +--- a/sign/rpmgensig.c ++++ b/sign/rpmgensig.c +@@ -8,6 +8,10 @@ + #include + #include + #include ++#include ++#ifdef WITH_FSVERITY ++#include ++#endif + + #include /* RPMSIGTAG & related */ + #include +@@ -458,23 +462,37 @@ static rpmRC includeFileSignatures(Header *sigp, Header *hdrp) + static rpmRC includeVeritySignatures(FD_t fd, Header *sigp, Header *hdrp) + { + #ifdef WITH_FSVERITY +- rpmRC rc; ++ rpmRC rc = RPMRC_OK; + char *key = rpmExpand("%{?_file_signing_key}", NULL); + char *keypass = rpmExpand("%{?_file_signing_key_password}", NULL); + char *cert = rpmExpand("%{?_file_signing_cert}", NULL); ++ char *algorithm = rpmExpand("%{?_verity_algorithm}", NULL); ++ uint16_t algo = 0; + + if (rstreq(keypass, "")) { + free(keypass); + keypass = NULL; + } + ++ if (algorithm && strlen(algorithm) > 0) { ++ algo = libfsverity_find_hash_alg_by_name(algorithm); ++ rpmlog(RPMLOG_DEBUG, _("Searching for algorithm %s got %i\n"), ++ algorithm, algo); ++ if (!algo) { ++ rpmlog(RPMLOG_ERR, _("Unsupported fsverity algorithm %s\n"), ++ algorithm); ++ rc = RPMRC_FAIL; ++ goto out; ++ } ++ } + if (key && cert) { +- rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert); ++ rc = rpmSignVerity(fd, *sigp, *hdrp, key, keypass, cert, algo); + } else { + rpmlog(RPMLOG_ERR, _("fsverity signatures requires a key and a cert\n")); + rc = RPMRC_FAIL; + } + ++ out: + free(keypass); + free(key); + free(cert); +diff --git a/sign/rpmsignverity.c b/sign/rpmsignverity.c +index 55096e732..e6c830cdc 100644 +--- a/sign/rpmsignverity.c ++++ b/sign/rpmsignverity.c +@@ -95,7 +95,7 @@ static char *rpmVeritySignFile(rpmfi fi, size_t *sig_size, char *key, + } + + rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, +- char *keypass, char *cert) ++ char *keypass, char *cert, uint16_t algo) + { + int rc; + FD_t gzdi; +@@ -111,7 +111,6 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, + char **signatures = NULL; + size_t sig_size; + int nr_files, idx; +- uint16_t algo; + uint32_t algo32; + + Fseek(fd, 0, SEEK_SET); +@@ -156,7 +155,8 @@ rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, + nr_files = rpmfiFC(hfi); + signatures = xcalloc(nr_files, sizeof(char *)); + +- algo = FS_VERITY_HASH_ALG_SHA256; ++ if (!algo) ++ algo = FS_VERITY_HASH_ALG_SHA256; + + rpmlog(RPMLOG_DEBUG, _("file count - header: %i, payload %i\n"), + nr_files, rpmfiFC(fi)); +diff --git a/sign/rpmsignverity.h b/sign/rpmsignverity.h +index 69bbaf7f7..d869e8d8e 100644 +--- a/sign/rpmsignverity.h ++++ b/sign/rpmsignverity.h +@@ -27,7 +27,7 @@ extern "C" { + */ + RPM_GNUC_INTERNAL + rpmRC rpmSignVerity(FD_t fd, Header sigh, Header h, char *key, +- char *keypass, char *cert); ++ char *keypass, char *cert, uint16_t algo); + + #ifdef _cplusplus + } +-- +2.27.0 + diff --git a/0033-Enable-fsverity-in-CI.patch b/0033-Enable-fsverity-in-CI.patch new file mode 100644 index 0000000..0fc6fde --- /dev/null +++ b/0033-Enable-fsverity-in-CI.patch @@ -0,0 +1,27 @@ +From 84ee9dc61b14056fec489bb099f1f212b3b169a9 Mon Sep 17 00:00:00 2001 +From: Jes Sorensen +Date: Fri, 28 Aug 2020 11:10:41 -0400 +Subject: [PATCH 33/33] Enable fsverity in CI + +Add fsverity-utils and fsverity-utils-devel as dependencies. + +Signed-off-by: Jes Sorensen +--- + Makefile.am | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/Makefile.am b/Makefile.am +index 8e92f0cde..3c1451049 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -17,6 +17,7 @@ DISTCHECK_CONFIGURE_FLAGS = \ + --with-selinux \ + --with-imaevm \ + --with-fapolicyd \ ++ --with-fsverity \ + --disable-dependency-tracking + + include $(top_srcdir)/rpm.am +-- +2.27.0 + diff --git a/rpm.spec b/rpm.spec index bcd8a8d..3193d41 100644 --- a/rpm.spec +++ b/rpm.spec @@ -15,6 +15,16 @@ %bcond_without libarchive # build with libimaevm.so %bcond_without libimaevm +%ifarch aarch64 ppc64le +# no fsverity on RHEL based aarch64 or ppc64le +# due to PAGESIZE == 64k +# https://pagure.io/centos-sig-hyperscale/package-bugs/issue/8 +# build without libfsverity.so +%bcond_with libfsverity +%else +# build with libfsverity.so +%bcond_without libfsverity +%endif # build with zstd support? %bcond_without zstd # build with ndb backend? @@ -32,7 +42,7 @@ %global rpmver 4.16.1.3 #global snapver rc1 -%global rel 11 +%global rel 11.1 %global sover 9 %global srcver %{rpmver}%{?snapver:-%{snapver}} @@ -100,6 +110,29 @@ Patch916: 0006-debugedit-Handle-DWARF-5-debug_line-and-debug_line_s.patch # Downstream-only patches Patch1000: rpm-4.16.1.3-hashtab-use-after-free-fix.patch +# fsverity support +%if %{with libfsverity} +Patch1964: 0015-rpmsign-RPMSIGN_FLAG_IMA-is-already-set.patch +Patch1965: 0016-Add-basic-autoconf-and-framework-for-fsverity-suppor.patch +Patch1966: 0017-rpmsign-Add-helper-to-indicate-file-signing-enabled.patch +Patch1967: 0018-rpmsign-Handle-certpath-for-signing-certificate.patch +Patch1968: 0019-Implement-rpmSignVerity.patch +Patch1969: 0020-Introduce-base2bin-a-helper-to-convert-tag-array-of-.patch +Patch1970: 0021-rpmsignverity-Add-verity-signature-headers-to-the-pa.patch +Patch1971: 0022-rpmSignVerity-Generate-signatures-for-files-not-pres.patch +Patch1972: 0023-Process-verity-tag-on-package-read.patch +Patch1973: 0024-Generate-a-zero-length-signature-for-symlinks.patch +Patch1974: 0025-rpmsignverity.c-Clean-up-debug-logging.patch +Patch1975: 0026-fsverity-add-tag-for-fsverity-algorithm.patch +Patch1976: 0027-plugins-fsverity-Install-fsverity-signatures.patch +Patch1977: 0028-fsverity-plugin-Use-tag-for-algorithm.patch +Patch1978: 0029-Add-fsverity-tags-to-rpmgeneral.at.patch +Patch1979: 0030-Add-delfilesign-flag-to-delete-IMA-and-fsverity-file.patch +Patch1980: 0031-Update-man-page-for-rpmsign.patch +Patch1981: 0032-rpmsign-Add-argument-to-specify-algorithm-for-fsveri.patch +Patch1982: 0033-Enable-fsverity-in-CI.patch +%endif + # Partially GPL/LGPL dual-licensed and some bits with BSD # SourceLicense: (GPLv2+ and LGPLv2+ with exceptions) and BSD License: GPLv2+ @@ -161,6 +194,10 @@ BuildRequires: audit-libs-devel BuildRequires: ima-evm-utils-devel >= 1.0 %endif +%if %{with libfsverity} +BuildRequires: fsverity-utils-devel >= 1.1 +%endif + %description The RPM Package Manager (RPM) is a powerful command line driven package management system capable of installing, uninstalling, @@ -308,6 +345,17 @@ Requires: rpm-libs%{_isa} = %{version}-%{release} %description plugin-ima %{summary}. +%if %{with libfsverity} +%package plugin-fsverity +Summary: Rpm plugin fsverity file signatures +Group: System Environment/Base +Requires: rpm-libs%{_isa} = %{version}-%{release} + +%description plugin-fsverity +%{summary} + +%endif + %package plugin-fapolicyd Summary: Rpm plugin for fapolicyd functionality Requires: rpm-libs%{_isa} = %{version}-%{release} @@ -380,6 +428,7 @@ done; %{?with_ndb: --enable-ndb} \ %{!?with_libarchive: --without-archive} \ %{?with_libimaevm: --with-imaevm} \ + %{?with_libfsverity: --with-fsverity} \ %{?with_zstd: --enable-zstd} \ %{?with_sqlite: --enable-sqlite} \ %{?with_bdb_ro: --enable-bdb-ro} \ @@ -525,6 +574,11 @@ fi %if %{with plugins} %dir %{_libdir}/rpm-plugins +%if %{with libfsverity} +%files plugin-fsverity +%{_libdir}/rpm-plugins/fsverity.so +%endif + %files plugin-syslog %{_libdir}/rpm-plugins/syslog.so %{_mandir}/man8/rpm-plugin-syslog.8* @@ -611,6 +665,9 @@ fi %doc doc/librpm/html/* %changelog +* Fri Feb 25 2022 Manu Bretelle - 4.16.1.3-11.1 +- Added fsverity backport + * Mon Feb 14 2022 Michal Domonkos - 4.16.1.3-11 - Fix IMA signature lengths assumed constant, take III (#2018937) - Fix regression reading rpm v3 and other rare packages (#2037186)