Commit: Add composefs digest and sig to the commit metadata
authorAlexander Larsson <alexl@redhat.com>
Mon, 15 May 2023 13:18:16 +0000 (15:18 +0200)
committerAlexander Larsson <alexl@redhat.com>
Wed, 31 May 2023 08:55:14 +0000 (10:55 +0200)
If `composefs-apply-sig` is enabled (default no) we add an
ostree.composefs digest to the commit metadata. This can be verified
on deploy.

This is a separate option from the generic `composefs` option which
controls whether composefs is used during deploy. It is separate
because we want to not have to force use of fs-verity, etc during the
build.

If the `composefs-certfile` and `composefs-keyfile` keys in the
ex-integrity group are set, then the commit metadata also gets a
ostree.composefs-sig containing the signature of the composefs file.

src/libostree/ostree-repo-commit.c
src/libostree/ostree-repo-composefs.c
src/libostree/ostree-repo-private.h

index 0900205fee924e8d41edc35b139234f77010b1f4..fe9248619929439d27a13e242525ef92928085fa 100644 (file)
@@ -398,14 +398,9 @@ compare_ascii_checksums_for_sorting (gconstpointer a_pp, gconstpointer b_pp)
 /*
  * Create sizes metadata GVariant and add it to the metadata variant given.
  */
-static GVariant *
-add_size_index_to_metadata (OstreeRepo *self, GVariant *original_metadata)
+static void
+add_size_index_to_metadata (OstreeRepo *self, GVariantBuilder *builder)
 {
-  g_autoptr (GVariantBuilder) builder = NULL;
-
-  /* original_metadata may be NULL */
-  builder = ot_util_variant_builder_from_variant (original_metadata, G_VARIANT_TYPE ("a{sv}"));
-
   if (self->object_sizes && g_hash_table_size (self->object_sizes) > 0)
     {
       GVariantBuilder index_builder;
@@ -443,8 +438,6 @@ add_size_index_to_metadata (OstreeRepo *self, GVariant *original_metadata)
       /* Clear the object sizes hash table for a subsequent commit. */
       g_hash_table_remove_all (self->object_sizes);
     }
-
-  return g_variant_ref_sink (g_variant_builder_end (builder));
 }
 
 static gboolean
@@ -2912,6 +2905,23 @@ ostree_repo_write_commit (OstreeRepo *self, const char *parent, const char *subj
                                              out_commit, cancellable, error);
 }
 
+static GVariant *
+add_auto_metadata (OstreeRepo *self, GVariant *original_metadata, OstreeRepoFile *repo_root,
+                   GCancellable *cancellable, GError **error)
+{
+  g_autoptr (GVariantBuilder) builder = NULL;
+
+  /* original_metadata may be NULL */
+  builder = ot_util_variant_builder_from_variant (original_metadata, G_VARIANT_TYPE ("a{sv}"));
+
+  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));
+}
+
 /**
  * ostree_repo_write_commit_with_time:
  * @self: Repo
@@ -2938,7 +2948,10 @@ ostree_repo_write_commit_with_time (OstreeRepo *self, const char *parent, const
   OstreeRepoFile *repo_root = OSTREE_REPO_FILE (root);
 
   /* Add sizes information to our metadata object */
-  g_autoptr (GVariant) new_metadata = add_size_index_to_metadata (self, metadata);
+  g_autoptr (GVariant) new_metadata
+      = add_auto_metadata (self, metadata, repo_root, cancellable, error);
+  if (new_metadata == NULL)
+    return FALSE;
 
   g_autoptr (GVariant) commit = g_variant_new (
       "(@a{sv}@ay@a(say)sst@ay@ay)", new_metadata ? new_metadata : create_empty_gvariant_dict (),
index 3df1cf9835c624789f2b423510376a755dd0613a..f33f5d3055c8414ec23b9ffef0c191b417d55eb2 100644 (file)
@@ -558,3 +558,74 @@ ostree_repo_checkout_composefs (OstreeRepo *self, OstreeComposefsTarget *target,
   return FALSE;
 #endif
 }
+
+#ifdef HAVE_COMPOSEFS
+static gboolean
+ostree_repo_commit_add_composefs_sig (OstreeRepo *self, GVariantBuilder *builder,
+                                      guchar *fsverity_digest, GCancellable *cancellable,
+                                      GError **error)
+{
+  g_autofree char *certfile = NULL;
+  g_autofree char *keyfile = NULL;
+  g_autoptr (GBytes) sig = NULL;
+
+  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");
+
+  if (!_ostree_fsverity_sign (certfile, keyfile, fsverity_digest, &sig, 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))
+    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_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;
+#else
+      return glnx_throw (error, "composefs required, but libostree compiled without support");
+#endif
+    }
+
+  return TRUE;
+}
index 15121372527727d354bf50e93532b442611ba029..76f3152bcbe5de919fed126bb8d9e2248257d147 100644 (file)
@@ -465,6 +465,10 @@ 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