lib: Rework composefs metadata, drop custom signatures
authorColin Walters <walters@verbum.org>
Fri, 16 Jun 2023 19:35:50 +0000 (15:35 -0400)
committerColin Walters <walters@verbum.org>
Sat, 17 Jun 2023 21:08:46 +0000 (17:08 -0400)
We will be switching to handling signature verification of
the target ostree commit.

13 files changed:
Makefile-libostree.am
Makefile-tests.am
apidoc/ostree-sections.txt
src/libostree/libostree-devel.sym
src/libostree/ostree-repo-commit.c
src/libostree/ostree-repo-composefs.c
src/libostree/ostree-repo-private.h
src/libostree/ostree-repo-verity.c
src/libostree/ostree-repo.h
src/libostree/ostree-sysroot-deploy.c
src/ostree/ot-builtin-commit.c
src/switchroot/ostree-prepare-root.c
tests/test-composefs.sh [new file with mode: 0755]

index 8edd7f4de17d922f5e16d3359be1bf5ba75d52a9..438741de7a33de9c3cd56270d53fcbbefdb0fcd1 100644 (file)
@@ -174,9 +174,9 @@ endif # USE_GPGME
 symbol_files = $(top_srcdir)/src/libostree/libostree-released.sym
 
 # Uncomment this include when adding new development symbols.
-#if BUILDOPT_IS_DEVEL_BUILD
-#symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
-#endif
+if BUILDOPT_IS_DEVEL_BUILD
+symbol_files += $(top_srcdir)/src/libostree/libostree-devel.sym
+endif
 
 # http://blog.jgc.org/2007/06/escaping-comma-and-space-in-gnu-make.html
 wl_versionscript_arg = -Wl,--version-script=
index 32817704fedc49b5d1fac4ea77d2ee8e3100f18d..dfed9c18bcdf976e462298f3b084ca8c5626ce86 100644 (file)
@@ -72,6 +72,7 @@ _installed_or_uninstalled_test_scripts = \
        tests/test-remote-add.sh \
        tests/test-remote-headers.sh \
        tests/test-remote-refs.sh \
+       tests/test-composefs.sh \
        tests/test-commit-sign.sh \
        tests/test-commit-timestamp.sh \
        tests/test-export.sh \
index a0db55c76b39907c718206e42f197fe5cfccb990..af57d7c9d14c65b6f0fc571577c2ca55d5137cb3 100644 (file)
@@ -426,6 +426,7 @@ ostree_repo_write_commit
 ostree_repo_write_commit_with_time
 ostree_repo_read_commit_detached_metadata
 ostree_repo_write_commit_detached_metadata
+ostree_repo_commit_add_composefs_metadata
 OstreeRepoCheckoutAtOptions
 ostree_repo_checkout_at_options_set_devino
 OstreeRepoCheckoutMode
index 9168db734a10e79204fc82ab96d895028d79b717..ec416c815a7828af7a05499f304e84639e9e8835 100644 (file)
    - uncomment the include in Makefile-libostree.am
 */
 
+LIBOSTREE_2023.4 {
+global:
+  ostree_repo_commit_add_composefs_metadata;
+} LIBOSTREE_2023.1;
+
 /* Stub section for the stable release *after* this development one; don't
  * edit this other than to update the year.  This is just a copy/paste
  * source.  Replace $LASTSTABLE with the last stable version, and $NEWVERSION
index d9ea29018d26910a40eadb0fcdd5790282bd556c..1bc3394bddbde99428f9cf02e50a1850f648dc0b 100644 (file)
@@ -2916,9 +2916,6 @@ add_auto_metadata (OstreeRepo *self, GVariant *original_metadata, OstreeRepoFile
 
   add_size_index_to_metadata (self, builder);
 
-  if (!ostree_repo_commit_add_composefs_metadata (self, builder, repo_root, cancellable, error))
-    return NULL;
-
   return g_variant_ref_sink (g_variant_builder_end (builder));
 }
 
index 330b0cf4958f51ece3035c75bfae3c5e3fc762e5..623a3fc955506979649717131792bee5f7a67288 100644 (file)
@@ -566,89 +566,46 @@ ostree_repo_checkout_composefs (OstreeRepo *self, OstreeComposefsTarget *target,
 #endif
 }
 
-#ifdef HAVE_COMPOSEFS
-static gboolean
-ostree_repo_commit_add_composefs_sig (OstreeRepo *self, GVariantBuilder *builder,
-                                      guchar *fsverity_digest, GCancellable *cancellable,
-                                      GError **error)
+/**
+ * ostree_repo_commit_add_composefs_metadata:
+ * @self: Repo
+ * @format_version: Must be zero
+ * @dict: A GVariant builder of type a{sv}
+ * @repo_root: the target filesystem tree
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Compute the composefs digest for a filesystem tree
+ * and insert it into metadata for a commit object.  The composefs
+ * digest covers the entire filesystem tree and can be verified by
+ * the composefs mount tooling.
+ */
+_OSTREE_PUBLIC
+gboolean
+ostree_repo_commit_add_composefs_metadata (OstreeRepo *self, guint format_version,
+                                           GVariantDict *dict, OstreeRepoFile *repo_root,
+                                           GCancellable *cancellable, GError **error)
 {
-  g_autofree char *certfile = NULL;
-  g_autofree char *keyfile = NULL;
-  g_autoptr (GBytes) sig = NULL;
-  guchar digest_digest[LCFS_DIGEST_SIZE];
-
-  certfile
-      = g_key_file_get_string (self->config, _OSTREE_INTEGRITY_SECTION, "composefs-certfile", NULL);
-  keyfile
-      = g_key_file_get_string (self->config, _OSTREE_INTEGRITY_SECTION, "composefs-keyfile", NULL);
-
-  if (certfile == NULL && keyfile == NULL)
-    return TRUE;
-
-  if (certfile == NULL)
-    return glnx_throw (error, "Error signing compoosefs: keyfile specified but certfile is not");
-
-  if (keyfile == NULL)
-    return glnx_throw (error, "Error signing compoosefs: certfile specified but keyfile is not");
-
-  /* We sign not the fs-verity of the image file itself, but rather we sign a file containing
-   * the fs-verity digest. This may seem weird, but disconnecting the signature from the
-   * actual image itself has two major advantages:
-   *  * We can read/mount the image (non-verified) even  without the public  key in
-   *    the keyring.
-   *  * We can apply fs-verity to the image during deploy without the public key in
-   *    the keyring.
-   *
-   * This is important because during an update we don't have the public key loaded until
-   * we boot into the new initrd.
-   */
+#ifdef HAVE_COMPOSEFS
+  /* For now */
+  g_assert (format_version == 0);
 
-  if (lcfs_compute_fsverity_from_data (digest_digest, fsverity_digest, LCFS_DIGEST_SIZE) < 0)
-    return glnx_throw_errno (error);
+  /* Create a composefs image and put in deploy dir as .ostree.cfs */
+  g_autoptr (OstreeComposefsTarget) target = ostree_composefs_target_new ();
 
-  if (!_ostree_fsverity_sign (certfile, keyfile, digest_digest, &sig, cancellable, error))
+  if (!ostree_repo_checkout_composefs (self, target, repo_root, cancellable, error))
     return FALSE;
 
-  g_variant_builder_add (builder, "{sv}", "ostree.composefs-sig", ot_gvariant_new_ay_bytes (sig));
-
-  return TRUE;
-}
-#endif
-
-gboolean
-ostree_repo_commit_add_composefs_metadata (OstreeRepo *self, GVariantBuilder *builder,
-                                           OstreeRepoFile *repo_root, GCancellable *cancellable,
-                                           GError **error)
-{
-  gboolean add_metadata;
-
-  if (!ot_keyfile_get_boolean_with_default (self->config, _OSTREE_INTEGRITY_SECTION,
-                                            "composefs-add-metadata", FALSE, &add_metadata, error))
+  g_autofree guchar *fsverity_digest = NULL;
+  if (!ostree_composefs_target_write (target, -1, &fsverity_digest, cancellable, error))
     return FALSE;
 
-  if (add_metadata)
-    {
-#ifdef HAVE_COMPOSEFS
-      /* Create a composefs image and put in deploy dir as .ostree.cfs */
-      g_autoptr (OstreeComposefsTarget) target = ostree_composefs_target_new ();
-
-      if (!ostree_repo_checkout_composefs (self, target, repo_root, cancellable, error))
-        return FALSE;
+  g_variant_dict_insert_value (
+      dict, OSTREE_COMPOSEFS_DIGEST_KEY_V0,
+      ot_gvariant_new_bytearray (fsverity_digest, OSTREE_SHA256_DIGEST_LEN));
 
-      g_autofree guchar *fsverity_digest = NULL;
-      if (!ostree_composefs_target_write (target, -1, &fsverity_digest, cancellable, error))
-        return FALSE;
-
-      g_variant_builder_add (builder, "{sv}", "ostree.composefs",
-                             ot_gvariant_new_bytearray (fsverity_digest, OSTREE_SHA256_DIGEST_LEN));
-
-      if (!ostree_repo_commit_add_composefs_sig (self, builder, fsverity_digest, cancellable,
-                                                 error))
-        return FALSE;
+  return TRUE;
 #else
-      return composefs_not_supported (error);
+  return composefs_not_supported (error);
 #endif
-    }
-
-  return TRUE;
 }
index 76f3152bcbe5de919fed126bb8d9e2248257d147..6d3f21e61fe51aa224c2f33cead9da66eeb1999c 100644 (file)
@@ -65,6 +65,11 @@ G_BEGIN_DECLS
 #define OSTREE_COMMIT_TIMESTAMP "ostree.commit.timestamp"
 #define OSTREE_COMMIT_VERSION "ostree.commit.version"
 
+// The metadata key for composefs
+#define OSTREE_COMPOSEFS_META_PREFIX "ostree.composefs"
+// The fs-verity digest of the composefs, version 0
+#define OSTREE_COMPOSEFS_DIGEST_KEY_V0 OSTREE_COMPOSEFS_META_PREFIX ".digest.v0"
+
 #define _OSTREE_INTEGRITY_SECTION "ex-integrity"
 
 typedef enum
@@ -399,9 +404,6 @@ gboolean _ostree_tmpf_fsverity_core (GLnxTmpfile *tmpf, _OstreeFeatureSupport fs
 
 gboolean _ostree_tmpf_fsverity (OstreeRepo *self, GLnxTmpfile *tmpf, GBytes *signature,
                                 GError **error);
-gboolean _ostree_fsverity_sign (const char *certfile, const char *keyfile,
-                                const guchar *fsverity_digest, GBytes **data_out,
-                                GCancellable *cancellable, GError **error);
 
 gboolean _ostree_repo_verify_bindings (const char *collection_id, const char *ref_name,
                                        GVariant *commit, GError **error);
@@ -465,10 +467,6 @@ gboolean ostree_repo_checkout_composefs (OstreeRepo *self, OstreeComposefsTarget
                                          OstreeRepoFile *source, GCancellable *cancellable,
                                          GError **error);
 
-gboolean ostree_repo_commit_add_composefs_metadata (OstreeRepo *self, GVariantBuilder *builder,
-                                                    OstreeRepoFile *repo_root,
-                                                    GCancellable *cancellable, GError **error);
-
 G_DEFINE_AUTOPTR_CLEANUP_FUNC (OstreeComposefsTarget, ostree_composefs_target_unref)
 
 G_END_DECLS
index 512386a96f5212eb0358399cc9633d8f4afc8d8f..6a7130c8a29b6ca076c4208cf54b8af5e09ba17a 100644 (file)
@@ -206,131 +206,3 @@ _ostree_tmpf_fsverity (OstreeRepo *self, GLnxTmpfile *tmpf, GBytes *signature, G
 #endif
   return TRUE;
 }
-
-#if defined(HAVE_OPENSSL)
-static gboolean
-read_pem_x509_certificate (const char *certfile, X509 **cert_ret, GError **error)
-{
-  g_autoptr (BIO) bio = NULL;
-  X509 *cert;
-
-  errno = 0;
-  bio = BIO_new_file (certfile, "r");
-  if (!bio)
-    return glnx_throw_errno_prefix (error, "Error loading composefs certfile '%s'", certfile);
-
-  cert = PEM_read_bio_X509 (bio, NULL, NULL, NULL);
-  if (!cert)
-    return glnx_throw (error, "Error parsing composefs certfile '%s'", certfile);
-
-  *cert_ret = cert;
-  return TRUE;
-}
-
-static gboolean
-read_pem_pkcs8_private_key (const char *keyfile, EVP_PKEY **pkey_ret, GError **error)
-{
-  g_autoptr (BIO) bio;
-  EVP_PKEY *pkey;
-
-  errno = 0;
-  bio = BIO_new_file (keyfile, "r");
-  if (!bio)
-    return glnx_throw_errno_prefix (error, "Error loading composefs keyfile '%s'", keyfile);
-
-  pkey = PEM_read_bio_PrivateKey (bio, NULL, NULL, NULL);
-  if (!pkey)
-    return glnx_throw (error, "Error parsing composefs keyfile '%s'", keyfile);
-
-  *pkey_ret = pkey;
-  return TRUE;
-}
-
-static gboolean
-sign_pkcs7 (const void *data_to_sign, size_t data_size, EVP_PKEY *pkey, X509 *cert,
-            const EVP_MD *md, BIO **res, GError **error)
-{
-  int pkcs7_flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR | PKCS7_NOCERTS | PKCS7_PARTIAL;
-  g_autoptr (BIO) bio = NULL;
-  g_autoptr (BIO) bio_res = NULL;
-  g_autoptr (PKCS7) p7 = NULL;
-
-  bio = BIO_new_mem_buf ((void *)data_to_sign, data_size);
-  if (!bio)
-    return glnx_throw (error, "Can't allocate buffer");
-
-  p7 = PKCS7_sign (NULL, NULL, NULL, bio, pkcs7_flags);
-  if (!p7)
-    return glnx_throw (error, "Can't initialize PKCS#7");
-
-  if (!PKCS7_sign_add_signer (p7, cert, pkey, md, pkcs7_flags))
-    return glnx_throw (error, "Can't add signer to PKCS#7");
-
-  if (PKCS7_final (p7, bio, pkcs7_flags) != 1)
-    return glnx_throw (error, "Can't finalize PKCS#7");
-
-  bio_res = BIO_new (BIO_s_mem ());
-  if (!bio_res)
-    return glnx_throw (error, "Can't allocate buffer");
-
-  if (i2d_PKCS7_bio (bio_res, p7) != 1)
-    return glnx_throw (error, "Can't DER-encode PKCS#7 signature object");
-
-  *res = g_steal_pointer (&bio_res);
-  return TRUE;
-}
-
-gboolean
-_ostree_fsverity_sign (const char *certfile, const char *keyfile, const guchar *fsverity_digest,
-                       GBytes **data_out, GCancellable *cancellable, GError **error)
-{
-  g_autofree struct fsverity_formatted_digest *d = NULL;
-  gsize d_size;
-  g_autoptr (X509) cert = NULL;
-  g_autoptr (EVP_PKEY) pkey = NULL;
-  g_autoptr (BIO) bio_sig = NULL;
-  const EVP_MD *md;
-  guchar *sig;
-  long sig_size;
-
-  if (certfile == NULL)
-    return glnx_throw (error, "certfile not specified");
-
-  if (keyfile == NULL)
-    return glnx_throw (error, "keyfile not specified");
-
-  if (!read_pem_x509_certificate (certfile, &cert, error))
-    return FALSE;
-
-  if (!read_pem_pkcs8_private_key (keyfile, &pkey, error))
-    return FALSE;
-
-  md = EVP_sha256 ();
-  if (md == NULL)
-    return glnx_throw (error, "No sha256 support in openssl");
-
-  d_size = sizeof (struct fsverity_formatted_digest) + OSTREE_SHA256_DIGEST_LEN;
-  d = g_malloc0 (d_size);
-
-  memcpy (d->magic, "FSVerity", 8);
-  d->digest_algorithm = GUINT16_TO_LE (FS_VERITY_HASH_ALG_SHA256);
-  d->digest_size = GUINT16_TO_LE (OSTREE_SHA256_DIGEST_LEN);
-  memcpy (d->digest, fsverity_digest, OSTREE_SHA256_DIGEST_LEN);
-
-  if (!sign_pkcs7 (d, d_size, pkey, cert, md, &bio_sig, error))
-    return FALSE;
-
-  sig_size = BIO_get_mem_data (bio_sig, &sig);
-
-  *data_out = g_bytes_new (sig, sig_size);
-
-  return TRUE;
-}
-#else
-gboolean
-_ostree_fsverity_sign (const char *certfile, const char *keyfile, const guchar *fsverity_digest,
-                       GBytes **data_out, GCancellable *cancellable, GError **error)
-{
-  return glnx_throw (error, "fsverity signature support not built");
-}
-#endif
index 1e6b320279c0e8739509b6a104c968ccfe709053..2dea9092230a97685e709b7f89c3992ba4920ec5 100644 (file)
@@ -690,6 +690,11 @@ _OSTREE_PUBLIC
 gboolean ostree_repo_write_mtree (OstreeRepo *self, OstreeMutableTree *mtree, GFile **out_file,
                                   GCancellable *cancellable, GError **error);
 
+_OSTREE_PUBLIC
+gboolean ostree_repo_commit_add_composefs_metadata (OstreeRepo *self, guint format_version,
+                                                    GVariantDict *dict, OstreeRepoFile *repo_root,
+                                                    GCancellable *cancellable, GError **error);
+
 _OSTREE_PUBLIC
 gboolean ostree_repo_write_commit (OstreeRepo *self, const char *parent, const char *subject,
                                    const char *body, GVariant *metadata, OstreeRepoFile *root,
index 8920fd704de4506e27a4014d6f68757d3a13e87b..8fcd5e802758a2f9ee8d1298c77ea66fc1b94fe3 100644 (file)
@@ -659,10 +659,8 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy
         return FALSE;
 
       g_autoptr (GVariant) metadata = g_variant_get_child_value (commit_variant, 0);
-      g_autoptr (GVariant) metadata_composefs
-          = g_variant_lookup_value (metadata, "ostree.composefs", G_VARIANT_TYPE_BYTESTRING);
-      g_autoptr (GVariant) metadata_composefs_sig
-          = g_variant_lookup_value (metadata, "ostree.composefs-sig", G_VARIANT_TYPE_BYTESTRING);
+      g_autoptr (GVariant) metadata_composefs = g_variant_lookup_value (
+          metadata, OSTREE_COMPOSEFS_DIGEST_KEY_V0, G_VARIANT_TYPE_BYTESTRING);
 
       /* Create a composefs image and put in deploy dir as .ostree.cfs */
       g_autoptr (OstreeComposefsTarget) target = ostree_composefs_target_new ();
@@ -695,32 +693,6 @@ checkout_deployment_tree (OstreeSysroot *sysroot, OstreeRepo *repo, OstreeDeploy
       if (!_ostree_tmpf_fsverity (repo, &tmpf, NULL, error))
         return FALSE;
 
-      if (metadata_composefs && metadata_composefs_sig)
-        {
-          g_autofree char *composefs_digest_path
-              = g_strdup_printf ("%s/.ostree.cfs.digest", checkout_target_name);
-          g_autofree char *composefs_sig_path
-              = g_strdup_printf ("%s/.ostree.cfs.sig", checkout_target_name);
-          g_autoptr (GBytes) digest = g_variant_get_data_as_bytes (metadata_composefs);
-          g_autoptr (GBytes) sig = g_variant_get_data_as_bytes (metadata_composefs_sig);
-
-          if (!glnx_file_replace_contents_at (osdeploy_dfd, composefs_digest_path,
-                                              g_bytes_get_data (digest, NULL),
-                                              g_bytes_get_size (digest), 0, cancellable, error))
-            return FALSE;
-
-          if (!glnx_file_replace_contents_at (osdeploy_dfd, composefs_sig_path,
-                                              g_bytes_get_data (sig, NULL), g_bytes_get_size (sig),
-                                              0, cancellable, error))
-            return FALSE;
-
-          /* The signature should be applied as a fs-verity signature to the digest file. However
-           * we can't do that until boot, because we can't guarantee that the public key is
-           * loaded into the keyring until we boot the new initrd. So the signature is applied
-           * in ostree-prepare-root on first boot.
-           */
-        }
-
       if (!glnx_link_tmpfile_at (&tmpf, GLNX_LINK_TMPFILE_REPLACE, osdeploy_dfd, composefs_cfs_path,
                                  error))
         return FALSE;
index 8f56779fb244567e80ec8a175ef01eb57576bdf8..760496715afd4c20a8746a1be3b5bd075cda4630 100644 (file)
@@ -70,6 +70,7 @@ static char *opt_gpg_homedir;
 static char **opt_key_ids;
 static char *opt_sign_name;
 static gboolean opt_generate_sizes;
+static gboolean opt_composefs_metadata;
 static gboolean opt_disable_fsync;
 static char *opt_timestamp;
 
@@ -161,6 +162,8 @@ static GOptionEntry options[] = {
     "Signature type to use (defaults to 'ed25519')", "NAME" },
   { "generate-sizes", 0, 0, G_OPTION_ARG_NONE, &opt_generate_sizes,
     "Generate size information along with commit metadata", NULL },
+  { "generate-composefs-metadata", 0, 0, G_OPTION_ARG_NONE, &opt_composefs_metadata,
+    "Generate composefs commit metadata", NULL },
   { "disable-fsync", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_disable_fsync,
     "Do not invoke fsync()", NULL },
   { "fsync", 0, 0, G_OPTION_ARG_CALLBACK, parse_fsync_cb, "Specify how to invoke fsync()",
@@ -872,6 +875,18 @@ ostree_builtin_commit (int argc, char **argv, OstreeCommandInvocation *invocatio
           metadata = g_variant_ref_sink (g_variant_dict_end (&bootmeta));
         }
 
+      if (opt_composefs_metadata)
+        {
+          g_autoptr (GVariant) old_metadata = g_steal_pointer (&metadata);
+          g_auto (GVariantDict) newmeta;
+          g_variant_dict_init (&newmeta, old_metadata);
+          if (!ostree_repo_commit_add_composefs_metadata (
+                  repo, 0, &newmeta, OSTREE_REPO_FILE (root), cancellable, error))
+            goto out;
+
+          metadata = g_variant_ref_sink (g_variant_dict_end (&newmeta));
+        }
+
       if (!opt_timestamp)
         {
           if (!ostree_repo_write_commit (repo, parent, opt_subject, commit_body, metadata,
index ca97244ac95bed792de264ca4f63cc22c3adfc2a..2bfc48f5d882224d96302c4e3ee0324df27572bd 100644 (file)
@@ -181,130 +181,6 @@ resolve_deploy_path (const char *root_mountpoint)
   return deploy_path;
 }
 
-#ifdef HAVE_COMPOSEFS
-static void
-apply_digest_signature (const char *digestfile, const char *sigfile)
-{
-  unsigned char *signature;
-  size_t signature_len;
-  int digest_is_readonly;
-  int digest_fd;
-
-  signature = read_file (sigfile, &signature_len);
-  if (signature == NULL)
-    err (EXIT_FAILURE, "Missing signaure file %s", sigfile);
-
-  /* If we're read-only we temporarily make read-write bind mount to sign */
-  digest_is_readonly = path_is_on_readonly_fs (digestfile);
-  if (digest_is_readonly)
-    {
-      if (mount (digestfile, digestfile, NULL, MS_BIND | MS_SILENT, NULL) < 0)
-        err (EXIT_FAILURE, "failed to bind mount %s (for signing)", digestfile);
-      if (mount (digestfile, digestfile, NULL, MS_REMOUNT | MS_SILENT, NULL) < 0)
-        err (EXIT_FAILURE, "failed to remount %s read-write (for signing)", digestfile);
-    }
-
-  /* Ensure we re-open after any bindmounts */
-  digest_fd = open (digestfile, O_RDONLY | O_CLOEXEC);
-  if (digest_fd < 0)
-    err (EXIT_FAILURE, "failed to open %s", digestfile);
-
-  fsverity_sign (digest_fd, signature, signature_len);
-
-  close (digest_fd);
-
-  if (digest_is_readonly && umount2 (digestfile, MNT_DETACH) < 0)
-    err (EXIT_FAILURE, "failed to unmount %s (after signing)", digestfile);
-
-  free (signature);
-
-#ifdef USE_LIBSYSTEMD
-  sd_journal_send ("MESSAGE=Applied fsverity signature %s to %s", sigfile, digestfile, NULL);
-#endif
-}
-
-static void
-ensure_digest_fd_is_signed (int digest_fd)
-{
-  struct fsverity_read_metadata_arg read_metadata = { 0 };
-  char sig_data[1];
-  int res;
-
-  /* We verify there is a signature by reading one byte of it. */
-
-  read_metadata.metadata_type = FS_VERITY_METADATA_TYPE_SIGNATURE;
-  read_metadata.offset = 0;
-  read_metadata.length = sizeof (sig_data);
-  read_metadata.buf_ptr = (size_t)&sig_data;
-
-  res = ioctl (digest_fd, FS_IOC_READ_VERITY_METADATA, &read_metadata);
-  if (res == -1)
-    {
-      if (errno == ENODATA)
-        err (EXIT_FAILURE, "Digest file is unexpectedly not signed");
-      else
-        err (EXIT_FAILURE, "Failed to get signature from digest file");
-    }
-}
-
-static char *
-read_signed_digest (const char *digestfile, const char *sigfile)
-{
-  unsigned fd_flags;
-  int digest_fd;
-  unsigned char buf[LCFS_DIGEST_SIZE];
-  char *digest;
-  ssize_t bytes_read;
-
-  digest_fd = open (digestfile, O_RDONLY | O_CLOEXEC);
-  if (digest_fd < 0)
-    err (EXIT_FAILURE, "failed to open %s", digestfile);
-
-  /* Check if file is already fsverity */
-  if (ioctl (digest_fd, FS_IOC_GETFLAGS, &fd_flags) < 0)
-    err (EXIT_FAILURE, "failed to get fd flags for %s", digestfile);
-
-  /* If it is not, apply signature */
-  if ((fd_flags & FS_VERITY_FL) == 0)
-    {
-      close (digest_fd);
-
-      apply_digest_signature (digestfile, sigfile);
-
-      /* Reopen */
-      digest_fd = open (digestfile, O_RDONLY | O_CLOEXEC);
-      if (digest_fd < 0)
-        err (EXIT_FAILURE, "failed to reopen %s", digestfile);
-    }
-
-  /* By now we know its fs-verify enabled, also ensure it is signed
-   * with a key in the keyring */
-  ensure_digest_fd_is_signed (digest_fd);
-
-  /* Load the expected digest */
-  do
-    bytes_read = read (digest_fd, buf, LCFS_DIGEST_SIZE);
-  while (bytes_read == -1 && errno == EINTR);
-  if (bytes_read == -1)
-    err (EXIT_FAILURE, "Failed to read digest file");
-
-  if (bytes_read != LCFS_DIGEST_SIZE)
-    err (EXIT_FAILURE, "Digest file has wrong size");
-
-  digest = malloc (LCFS_DIGEST_SIZE * 2 + 1);
-  if (digest == NULL)
-    err (EXIT_FAILURE, "Out of memory");
-
-  bin2hex (digest, buf, LCFS_DIGEST_SIZE);
-
-#ifdef USE_LIBSYSTEMD
-  sd_journal_send ("MESSAGE=Signed digest file found for root", NULL);
-#endif
-
-  return digest;
-}
-#endif
-
 static int
 pivot_root (const char *new_root, const char *put_old)
 {
@@ -439,11 +315,7 @@ main (int argc, char *argv[])
       };
 
       if (composefs_mode == OSTREE_COMPOSEFS_MODE_SIGNED)
-        {
-          composefs_digest
-              = read_signed_digest (OSTREE_COMPOSEFS_NAME ".digest", OSTREE_COMPOSEFS_NAME ".sig");
-          composefs_mode = OSTREE_COMPOSEFS_MODE_DIGEST;
-        }
+        errx (EXIT_FAILURE, "composefs signature not supported");
 
       cfs_options.flags = LCFS_MOUNT_FLAGS_READONLY;
 
diff --git a/tests/test-composefs.sh b/tests/test-composefs.sh
new file mode 100755 (executable)
index 0000000..f76cbf2
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# SPDX-License-Identifier: LGPL-2.0+
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <https://www.gnu.org/licenses/>.
+
+set -euo pipefail
+
+if ! ostree --version | grep -q -e '- composefs'; then
+    echo "1..0 #SKIP no composefs support compiled in"
+    exit 0
+fi
+
+. $(dirname $0)/libtest.sh
+
+setup_test_repository "bare-user"
+
+cd ${test_tmpdir}
+$OSTREE checkout test2 test2-co
+$OSTREE commit ${COMMIT_ARGS} -b test-composefs --generate-composefs-metadata test2-co
+orig_composefs_digest=$($OSTREE show --print-metadata-key ostree.composefs.v0 test-composefs)
+assert_streq "${orig_composefs_digest}" '[byte 0x1f, 0x08, 0xe5, 0x8b, 0x14, 0x3b, 0x75, 0x34, 0x76, 0xb5, 0xef, 0x0c, 0x0c, 0x6e, 0xce, 0xbf, 0xde, 0xbb, 0x6d, 0x40, 0x30, 0x5e, 0x35, 0xbd, 0x6f, 0x8e, 0xc1, 0x9c, 0xd0, 0xd1, 0x5b, 0xae]'
+$OSTREE commit ${COMMIT_ARGS} -b test-composefs2 --generate-composefs-metadata test2-co
+new_composefs_digest=$($OSTREE show --print-metadata-key ostree.composefs.v0 test-composefs)
+assert_streq "${orig_composefs_digest}" "${new_composefs_digest}"
+tap_ok "composefs metadata"
+
+tap_end