lib/deltas: Check signed delta in execute_offline
authorFrédéric Danis <frederic.danis@collabora.com>
Tue, 25 Aug 2020 07:26:09 +0000 (09:26 +0200)
committerFrédéric Danis <frederic.danis@collabora.com>
Mon, 14 Sep 2020 07:27:19 +0000 (09:27 +0200)
Add a new function `ostree_repo_static_delta_execute_offline_with_signature`
which takes a signature engine to verify the delta before applying it.
The `ostree_repo_static_delta_execute_offline` is just a wrapper to this
new function, passing a NULL signature engine.
When this function is called without signature engine, but with a sign
delta, it will only fails if `sign-verify-deltas` is set to true in repo
core options.

This commits move signature existence check and delta signature
verification to share common parts between existing APIs and the new
function.

Signed-off-by: Frédéric Danis <frederic.danis@collabora.com>
apidoc/ostree-sections.txt
src/libostree/libostree-devel.sym
src/libostree/ostree-repo-static-delta-core.c
src/libostree/ostree-repo.h

index 8cafeb1f82e4d6751d731061b6c5e8933c29d8b8..66b42233011e0b2e31538fafdbd984ef0942f4e0 100644 (file)
@@ -412,6 +412,7 @@ ostree_repo_list_commit_objects_starting_with
 ostree_repo_list_static_delta_names
 OstreeStaticDeltaGenerateOpt
 ostree_repo_static_delta_generate
+ostree_repo_static_delta_execute_offline_with_signature
 ostree_repo_static_delta_execute_offline
 ostree_repo_static_delta_verify_signature
 ostree_repo_traverse_new_reachable
index 9a847b924a56a54f074671d9625192b135e5d719..a15654c1382cd0d41d75420e44fdfb391ed46b62 100644 (file)
@@ -22,6 +22,7 @@ global:
   /* Add symbols here, and uncomment the bits in
    * Makefile-libostree.am to enable this too.
    */
+  ostree_repo_static_delta_execute_offline_with_signature;
   ostree_repo_static_delta_verify_signature;
 } LIBOSTREE_2020.4;
 
index 8d0f4e8226b30c036e047688f772712c9ee345c3..b16764ae663e46f285c5bc0cb10cfd20c300903a 100644 (file)
@@ -265,25 +265,68 @@ _ostree_repo_static_delta_is_signed (OstreeRepo       *self,
   return ret;
 }
 
+static gboolean
+_ostree_repo_static_delta_verify_signature (OstreeRepo       *self,
+                                            int               fd,
+                                            OstreeSign       *sign,
+                                            char            **out_success_message,
+                                            GError          **error)
+{
+  g_autoptr(GVariantBuilder) desc_sign_builder = NULL;
+  g_autoptr(GVariant) delta_meta = NULL;
+  g_autoptr(GVariant) delta = NULL;
+
+  if (!ot_variant_read_fd (fd, 0,
+                           (GVariantType*)OSTREE_STATIC_DELTA_SIGNED_FORMAT,
+                           TRUE, &delta, error))
+    return FALSE;
+
+  /* Check if there are signatures for signature engine */
+  const gchar *signature_key = ostree_sign_metadata_key(sign);
+  GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format(sign);
+  delta_meta = g_variant_get_child_value (delta, 2);
+  if (delta_meta == NULL)
+      return glnx_throw (error, "no metadata in static-delta superblock");
+  g_autoptr(GVariant) signatures = g_variant_lookup_value (delta_meta,
+                                                           signature_key,
+                                                           signature_format);
+  if (!signatures)
+      return glnx_throw (error, "no signature for '%s' in static-delta superblock", signature_key);
+
+  /* Get static delta superblock */
+  g_autoptr(GVariant) child = g_variant_get_child_value (delta, 1);
+  if (child == NULL)
+      return glnx_throw (error, "no metadata in static-delta superblock");
+  g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes(child);
+
+  return ostree_sign_data_verify (sign, signed_data, signatures, out_success_message, error);
+}
+
 /**
- * ostree_repo_static_delta_execute_offline:
+ * ostree_repo_static_delta_execute_offline_with_signature:
  * @self: Repo
  * @dir_or_file: Path to a directory containing static delta data, or directly to the superblock
+ * @sign: Signature engine used to check superblock
  * @skip_validation: If %TRUE, assume data integrity
  * @cancellable: Cancellable
  * @error: Error
  *
  * Given a directory representing an already-downloaded static delta
- * on disk, apply it, generating a new commit.  The directory must be
- * named with the form "FROM-TO", where both are checksums, and it
- * must contain a file named "superblock", along with at least one part.
+ * on disk, apply it, generating a new commit.
+ * If sign is passed, the static delta signature is verified.
+ * If sign-verify-deltas configuration option is set and static delta is signed,
+ * signature verification will be mandatory before apply the static delta.
+ * The directory must be named with the form "FROM-TO", where both are
+ * checksums, and it must contain a file named "superblock", along with at least
+ * one part.
  */
 gboolean
-ostree_repo_static_delta_execute_offline (OstreeRepo                    *self,
-                                          GFile                         *dir_or_file,
-                                          gboolean                       skip_validation,
-                                          GCancellable                  *cancellable,
-                                          GError                      **error)
+ostree_repo_static_delta_execute_offline_with_signature (OstreeRepo   *self,
+                                                         GFile        *dir_or_file,
+                                                         OstreeSign   *sign,
+                                                         gboolean     skip_validation,
+                                                         GCancellable *cancellable,
+                                                         GError       **error)
 {
   g_autofree char *basename = NULL;
   g_autoptr(GVariant) delta = NULL;
@@ -316,6 +359,25 @@ ostree_repo_static_delta_execute_offline (OstreeRepo                    *self,
   gboolean is_signed = _ostree_repo_static_delta_is_signed (self, meta_fd, NULL, NULL);
   if (is_signed)
     {
+      gboolean verify_deltas;
+      gboolean verified;
+
+      if (!ot_keyfile_get_boolean_with_default (self->config, "core", "sign-verify-deltas",
+                                                FALSE, &verify_deltas, error))
+        return FALSE;
+
+      if (verify_deltas && !sign)
+        return glnx_throw (error, "Key is mandatory to check delta signature");
+
+      if (sign)
+        {
+          verified = _ostree_repo_static_delta_verify_signature (self, meta_fd, sign, NULL, error);
+          if (*error)
+            return FALSE;
+          if (!verified)
+            return glnx_throw (error, "Delta signature verification failed");
+        }
+
       if (!ot_variant_read_fd (meta_fd, 0, (GVariantType*)OSTREE_STATIC_DELTA_SIGNED_FORMAT,
                                TRUE, &delta, error))
         return FALSE;
@@ -479,6 +541,32 @@ ostree_repo_static_delta_execute_offline (OstreeRepo                    *self,
   return TRUE;
 }
 
+/**
+ * ostree_repo_static_delta_execute_offline:
+ * @self: Repo
+ * @dir_or_file: Path to a directory containing static delta data, or directly to the superblock
+ * @skip_validation: If %TRUE, assume data integrity
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Given a directory representing an already-downloaded static delta
+ * on disk, apply it, generating a new commit.  The directory must be
+ * named with the form "FROM-TO", where both are checksums, and it
+ * must contain a file named "superblock", along with at least one part.
+ */
+gboolean
+ostree_repo_static_delta_execute_offline (OstreeRepo                    *self,
+                                          GFile                         *dir_or_file,
+                                          gboolean                       skip_validation,
+                                          GCancellable                  *cancellable,
+                                          GError                      **error)
+{
+  return ostree_repo_static_delta_execute_offline_with_signature(self, dir_or_file, NULL,
+                                                                 skip_validation,
+                                                                 cancellable,
+                                                                 error);
+}
+
 gboolean
 _ostree_static_delta_part_open (GInputStream   *part_in,
                                 GBytes         *inline_part_bytes,
@@ -1030,29 +1118,5 @@ ostree_repo_static_delta_verify_signature (OstreeRepo       *self,
   if (!_ostree_repo_static_delta_is_signed (self, delta_fd, NULL, error))
     return FALSE;
 
-  g_autoptr(GVariant) delta = NULL;
-  if (!ot_variant_read_fd (delta_fd, 0,
-                           (GVariantType*)OSTREE_STATIC_DELTA_SIGNED_FORMAT,
-                           TRUE, &delta, error))
-    return FALSE;
-
-  /* Check if there are signatures for signature engine */
-  const gchar *signature_key = ostree_sign_metadata_key(sign);
-  GVariantType *signature_format = (GVariantType *) ostree_sign_metadata_format(sign);
-  delta_meta = g_variant_get_child_value (delta, 2);
-  if (delta_meta == NULL)
-      return glnx_throw (error, "no metadata in static-delta superblock");
-  g_autoptr(GVariant) signatures = g_variant_lookup_value (delta_meta,
-                                                           signature_key,
-                                                           signature_format);
-  if (!signatures)
-      return glnx_throw (error, "no signature for '%s' in static-delta superblock", signature_key);
-
-  /* Get static delta superblock */
-  g_autoptr(GVariant) child = g_variant_get_child_value (delta, 1);
-  if (child == NULL)
-      return glnx_throw (error, "no metadata in static-delta superblock");
-  g_autoptr(GBytes) signed_data = g_variant_get_data_as_bytes(child);
-
-  return ostree_sign_data_verify (sign, signed_data, signatures, out_success_message, error);
+  return _ostree_repo_static_delta_verify_signature (self, delta_fd, sign, out_success_message, error);
 }
index 552c1e6188cfaf4dedfc2832e24d1f0e756e3393..d52fc9c3a98014f8d3e2f0bf7405a017b0bcc5e6 100644 (file)
@@ -1068,6 +1068,14 @@ gboolean ostree_repo_static_delta_generate (OstreeRepo                   *self,
                                             GCancellable                 *cancellable,
                                             GError                      **error);
 
+_OSTREE_PUBLIC
+gboolean ostree_repo_static_delta_execute_offline_with_signature (OstreeRepo   *self,
+                                                                  GFile        *dir_or_file,
+                                                                  OstreeSign   *sign,
+                                                                  gboolean     skip_validation,
+                                                                  GCancellable *cancellable,
+                                                                  GError       **error);
+
 _OSTREE_PUBLIC
 gboolean ostree_repo_static_delta_execute_offline (OstreeRepo                    *self,
                                                    GFile                         *dir_or_file,