[ostree] pull: Verify commits with gpg signatures from detached metadata



commit 7f9eefb62d2b5a977289fa5a5a1d34755f597679
Author: Jeremy Whiting <jeremy whiting collabora com>
Date:   Thu Sep 5 12:50:36 2013 -0600

    pull: Verify commits with gpg signatures from detached metadata
    
    This uses gpgv for verification against DATADIR/ostree/pubring.gpg by
    default.  The keyring can be overridden by specifying OSTREE_GPG_HOME.
    
    Add a unit test for commit signing with gpg key and verifying on pull;
    to implement this we ship a test GPG key generated with no password
    for Ostree Tester <test test com>.
    
    Change all of the existing tests to disable GPG verification.

 Makefile-libostree.am                 |    5 +
 Makefile-tests.am                     |    1 +
 src/libgsystem                        |    2 +-
 src/libostree/README-gpg              |    2 +
 src/libostree/ostree-gpg-verifier.c   |  307 +++++++++++++++++++++++++++++++++
 src/libostree/ostree-gpg-verifier.h   |   64 +++++++
 src/libostree/ostree-repo-pull.c      |   23 +++
 src/libostree/ostree-repo.c           |  133 ++++++++++++++
 src/libostree/ostree-repo.h           |    7 +
 src/libostree/ostree-sysroot.c        |    3 +-
 src/ostree/ot-admin-builtin-upgrade.c |    3 +-
 tests/libtest.sh                      |    1 +
 tests/pull-test.sh                    |    2 +-
 tests/test-admin-deploy-1.sh          |    2 +-
 tests/test-admin-deploy-2.sh          |    4 +-
 tests/test-archivez.sh                |    2 +-
 tests/test-commit-sign.sh             |  102 +++++++++++
 tests/test-pull-corruption.sh         |    2 +-
 tests/test-pull-resume.sh             |    2 +-
 19 files changed, 657 insertions(+), 10 deletions(-)
---
diff --git a/Makefile-libostree.am b/Makefile-libostree.am
index badbb92..35d0ec0 100644
--- a/Makefile-libostree.am
+++ b/Makefile-libostree.am
@@ -57,6 +57,8 @@ libostree_1_la_SOURCES = \
        src/libostree/ostree-bootloader-uboot.c \
        src/libostree/ostree-ordered-hash.h \
        src/libostree/ostree-ordered-hash.c \
+       src/libostree/ostree-gpg-verifier.c \
+       src/libostree/ostree-gpg-verifier.h \
        $(NULL)
 if USE_LIBARCHIVE
 libostree_1_la_SOURCES += src/libostree/ostree-libarchive-input-stream.h \
@@ -102,5 +104,8 @@ pkgconfig_DATA += src/libostree/ostree-1.pc
 
 if USE_GPGME
 libostree_1_la_LIBADD += $(GPGME_LIBS)
+
+gpgreadme_DATA = src/libostree/README-gpg
+gpgreadmedir = $(pkgdatadir)
 endif
 
diff --git a/Makefile-tests.am b/Makefile-tests.am
index d6b3e44..c012141 100644
--- a/Makefile-tests.am
+++ b/Makefile-tests.am
@@ -23,6 +23,7 @@ insttestdir=$(pkglibexecdir)/installed-tests
 testfiles = test-basic \
        test-archivez \
        test-remote-add \
+        test-commit-sign \
        test-corruption \
        test-libarchive \
        test-pull-archive-z \
diff --git a/src/libgsystem b/src/libgsystem
index e0b2fef..020fa7d 160000
--- a/src/libgsystem
+++ b/src/libgsystem
@@ -1 +1 @@
-Subproject commit e0b2fefbb69d03f7aa1390f723e4dfc46f301e71
+Subproject commit 020fa7de344d9f10136ae1a3cb9bf6baa868218d
diff --git a/src/libostree/README-gpg b/src/libostree/README-gpg
new file mode 100644
index 0000000..9c1d479
--- /dev/null
+++ b/src/libostree/README-gpg
@@ -0,0 +1,2 @@
+Any GPG keyring files ending in ".gpg" placed in this directory will
+be automatically trusted by OSTree.
diff --git a/src/libostree/ostree-gpg-verifier.c b/src/libostree/ostree-gpg-verifier.c
new file mode 100644
index 0000000..bb02b94
--- /dev/null
+++ b/src/libostree/ostree-gpg-verifier.c
@@ -0,0 +1,307 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters verbum org>
+ * Copyright (C) 2013 Sjoerd Simons <sjoerd simons collabora co uk>
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Sjoerd Simons <sjoerd simons collabora co uk>
+ */
+
+#include "ostree-gpg-verifier.h"
+#include "otutil.h"
+
+#define GPGVGOODPREFIX "[GNUPG:] GOODSIG "
+
+typedef struct {
+  GObjectClass parent_class;
+} OstreeGpgVerifierClass;
+
+struct OstreeGpgVerifier {
+  GObject parent;
+
+  GList *keyrings;
+  gchar *homedir;
+};
+
+static void _ostree_gpg_verifier_initable_iface_init (GInitableIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (OstreeGpgVerifier, _ostree_gpg_verifier, G_TYPE_OBJECT,
+                         G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, _ostree_gpg_verifier_initable_iface_init))
+
+static void
+ostree_gpg_verifier_finalize (GObject *object)
+{
+  OstreeGpgVerifier *self = OSTREE_GPG_VERIFIER (object);
+
+  g_list_free_full (self->keyrings, g_object_unref);
+  g_free (self->homedir);
+
+  G_OBJECT_CLASS (_ostree_gpg_verifier_parent_class)->finalize (object);
+}
+
+static void
+_ostree_gpg_verifier_class_init (OstreeGpgVerifierClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = ostree_gpg_verifier_finalize;
+}
+
+static void
+_ostree_gpg_verifier_init (OstreeGpgVerifier *self)
+{
+}
+
+static gboolean
+ostree_gpg_verifier_initable_init (GInitable        *initable,
+                                   GCancellable     *cancellable,
+                                   GError          **error)
+{
+  gboolean ret = FALSE;
+  OstreeGpgVerifier *self = (OstreeGpgVerifier*)initable;
+  const char *default_keyring_path = g_getenv ("OSTREE_GPG_HOME");
+  gs_unref_object GFile *default_keyring_dir = NULL;
+  gs_unref_object GFile *default_pubring_file = NULL;
+  gs_unref_object GFile *default_pubring = NULL;
+
+  if (!default_keyring_path)
+    default_keyring_path = DATADIR "/ostree/trusted.gpg.d/";
+
+  default_keyring_dir = g_file_new_for_path (default_keyring_path);
+  default_pubring_file = g_file_get_child (default_keyring_dir, "pubring.gpg");
+
+  if (!_ostree_gpg_verifier_add_keyring (self, default_pubring_file,
+                                         cancellable, error))
+    goto out;
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+static void
+_ostree_gpg_verifier_initable_iface_init (GInitableIface *iface)
+{
+  iface->init = ostree_gpg_verifier_initable_init;
+}
+
+typedef struct {
+  OstreeGpgVerifier *self;
+  GCancellable *cancellable;
+  gboolean gpgv_done;
+  gboolean status_done;
+
+  gint goodsigs;
+  gint exitcode;
+  GError *error;
+  GMainLoop *loop;
+} VerifyRun;
+
+static void
+_gpgv_parse_line (VerifyRun *v, const gchar *line)
+{
+  if (g_str_has_prefix (line, GPGVGOODPREFIX))
+    v->goodsigs++;
+}
+
+static void
+on_process_done (GObject *s, GAsyncResult *res, gpointer user_data)
+{
+  VerifyRun *v = user_data;
+  gs_subprocess_wait_finish (GS_SUBPROCESS (s), res,
+                             &v->exitcode, &v->error);
+
+  v->gpgv_done = TRUE;
+
+  g_main_loop_quit (v->loop);
+}
+
+static void
+on_read_line (GObject *s, GAsyncResult *res, gpointer user_data)
+{
+  VerifyRun *v = user_data;
+  gchar *line;
+
+  /* Ignore errors when reading from the data input */
+  line = g_data_input_stream_read_line_finish (G_DATA_INPUT_STREAM (s),
+                                               res, NULL, NULL);
+
+  if (line == NULL)
+    {
+      v->status_done = TRUE;
+      g_main_loop_quit (v->loop);
+    }
+  else
+    {
+      _gpgv_parse_line (v, line);
+      g_free (line);
+      g_data_input_stream_read_line_async (G_DATA_INPUT_STREAM (s),
+                                           G_PRIORITY_DEFAULT, v->cancellable,
+                                           on_read_line, v);
+    }
+}
+
+
+gboolean
+_ostree_gpg_verifier_check_signature (OstreeGpgVerifier   *self,
+                                      GFile               *file,
+                                      GFile               *signature,
+                                      gboolean            *out_had_valid_sig,
+                                      GCancellable        *cancellable,
+                                      GError             **error)
+{
+  gboolean ret = FALSE;
+  gboolean ret_had_valid_sig = FALSE;
+  gs_unref_object GSSubprocessContext *context = NULL;
+  gs_unref_object GSSubprocess *proc = NULL;
+  gs_unref_object GDataInputStream *data = NULL;
+  gs_free gchar *status_fd_str = NULL;
+  GInputStream *output;
+  gint fd;
+  VerifyRun v = { 0, };
+  GList *item;
+  GMainContext *maincontext = NULL;
+  GMainLoop *loop = NULL;
+  
+  g_return_val_if_fail (out_had_valid_sig != NULL, FALSE);
+
+  maincontext = g_main_context_new ();
+  loop = g_main_loop_new (maincontext, FALSE);
+
+  g_main_context_push_thread_default (maincontext);
+
+  context = gs_subprocess_context_newv ("gpgv", NULL);
+  gs_subprocess_context_set_stdin_disposition (context,
+                                               GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
+  gs_subprocess_context_set_stdout_disposition (context,
+                                                GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
+  gs_subprocess_context_set_stderr_disposition (context,
+                                                GS_SUBPROCESS_STREAM_DISPOSITION_NULL);
+  
+  if (!gs_subprocess_context_open_pipe_read (context, &output, &fd, error))
+    goto out;
+
+  status_fd_str = g_strdup_printf ("%d", fd);
+  gs_subprocess_context_argv_append (context, "--status-fd");
+  gs_subprocess_context_argv_append (context, status_fd_str);
+
+  for (item = self->keyrings ; item != NULL; item = g_list_next (item))
+    {
+      GFile *keyring = item->data;
+      gs_subprocess_context_argv_append (context, "--keyring");
+      gs_subprocess_context_argv_append (context, gs_file_get_path_cached (keyring));
+    }
+
+  gs_subprocess_context_argv_append (context, gs_file_get_path_cached (signature));
+  gs_subprocess_context_argv_append (context, gs_file_get_path_cached (file));
+
+  proc = gs_subprocess_new (context, cancellable, error);
+  if (proc == NULL)
+    goto out;
+
+  data = g_data_input_stream_new (output);
+
+  v.self = self;
+  v.cancellable = cancellable;
+  v.loop = loop;
+
+  gs_subprocess_wait (proc, cancellable, on_process_done, &v);
+  g_data_input_stream_read_line_async (data, G_PRIORITY_DEFAULT, cancellable,
+                                       on_read_line, &v);
+
+  while (!v.gpgv_done || !v.status_done)
+    g_main_loop_run (loop);
+
+  if (v.goodsigs > 0)
+    ret_had_valid_sig = TRUE;
+  
+  ret = TRUE;
+  *out_had_valid_sig = ret_had_valid_sig;
+ out:
+  if (maincontext)
+    {
+      g_main_context_pop_thread_default (maincontext);
+      g_main_context_unref (maincontext);
+    }
+  if (loop)
+    g_main_loop_unref (loop);
+
+  return ret;
+}
+
+void
+_ostree_gpg_verifier_set_homedir (OstreeGpgVerifier    *self,
+                                  const gchar          *path)
+{
+  g_free (self->homedir);
+  self->homedir = g_strdup (path);
+}
+
+gboolean
+_ostree_gpg_verifier_add_keyring (OstreeGpgVerifier  *self,
+                                  GFile              *path,
+                                  GCancellable       *cancellable,
+                                  GError            **error)
+{
+  g_return_val_if_fail (path != NULL, FALSE);
+
+  self->keyrings = g_list_append (self->keyrings, g_object_ref (path));
+  return TRUE;
+}
+
+gboolean
+_ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier   *self,
+                                      GFile               *path,
+                                      GCancellable        *cancellable,
+                                      GError             **error)
+{
+  gboolean ret = FALSE;
+  gs_unref_object GFileEnumerator *enumerator = NULL;
+  
+  enumerator = g_file_enumerate_children (path, OSTREE_GIO_FAST_QUERYINFO,
+                                          G_FILE_QUERY_INFO_NONE,
+                                          cancellable, error);
+  if (!enumerator)
+    goto out;
+
+  while (TRUE)
+    {
+      GFileInfo *file_info;
+      GFile *path;
+
+      if (!gs_file_enumerator_iterate (enumerator, &file_info, &path,
+                                       cancellable, error))
+        goto out;
+      if (file_info == NULL)
+        break;
+
+      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_REGULAR &&
+          g_str_has_suffix (g_file_info_get_name (file_info), ".gpg"))
+        self->keyrings = g_list_append (self->keyrings, g_object_ref (path));
+    }
+
+  ret = TRUE;
+ out:
+  return ret;
+}
+
+OstreeGpgVerifier*
+_ostree_gpg_verifier_new (GCancellable   *cancellable,
+                          GError        **error)
+{
+  return g_initable_new (OSTREE_TYPE_GPG_VERIFIER, cancellable, error, NULL);
+}
diff --git a/src/libostree/ostree-gpg-verifier.h b/src/libostree/ostree-gpg-verifier.h
new file mode 100644
index 0000000..f69af06
--- /dev/null
+++ b/src/libostree/ostree-gpg-verifier.h
@@ -0,0 +1,64 @@
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
+ *
+ * Copyright (C) 2011 Colin Walters <walters verbum org>
+ * Copyright (C) 2013 Sjoerd Simons <sjoerd simons collabora co uk>
+ *
+ * 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Sjoerd Simons <sjoerd simons collabora co uk>
+ */
+
+//#pragma once
+
+#include "config.h"
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define OSTREE_TYPE_GPG_VERIFIER _ostree_gpg_verifier_get_type()
+#define OSTREE_GPG_VERIFIER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), OSTREE_TYPE_GPG_VERIFIER, OstreeGpgVerifier))
+#define OSTREE_IS_GPG_VERIFIER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OSTREE_TYPE_GPG_VERIFIER))
+
+typedef struct OstreeGpgVerifier OstreeGpgVerifier;
+
+GType _ostree_gpg_verifier_get_type (void);
+
+OstreeGpgVerifier *_ostree_gpg_verifier_new (GCancellable   *cancellable,
+                                             GError        **error);
+
+gboolean      _ostree_gpg_verifier_check_signature (OstreeGpgVerifier *self,
+                                                    GFile             *file,
+                                                    GFile             *signature,
+                                                    gboolean          *had_valid_signature,
+                                                    GCancellable      *cancellable,
+                                                    GError           **error);
+
+void _ostree_gpg_verifier_set_homedir (OstreeGpgVerifier *self,
+                                       const gchar *path);
+
+gboolean      _ostree_gpg_verifier_add_keyring_dir (OstreeGpgVerifier   *self,
+                                                    GFile               *path,
+                                                    GCancellable        *cancellable,
+                                                    GError             **error);
+
+gboolean      _ostree_gpg_verifier_add_keyring (OstreeGpgVerifier   *self,
+                                                GFile               *path,
+                                                GCancellable        *cancellable,
+                                                GError             **error);
+G_END_DECLS
diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c
index 416e3b1..763ab5b 100644
--- a/src/libostree/ostree-repo-pull.c
+++ b/src/libostree/ostree-repo-pull.c
@@ -91,6 +91,8 @@ typedef struct {
   gboolean      transaction_resuming;
   volatile gint n_scanned_metadata;
   SoupURI       *fetching_sync_uri;
+  
+  gboolean          gpg_verify;
 
   GThread          *metadata_thread;
   GMainContext     *metadata_thread_context;
@@ -747,6 +749,19 @@ scan_commit_object (OtPullData         *pull_data,
       goto out;
     }
 
+#ifdef HAVE_GPGME
+  if (pull_data->gpg_verify)
+    {
+      if (!ostree_repo_verify_commit (pull_data->repo,
+                                      checksum,
+                                      NULL,
+                                      NULL,
+                                      cancellable,
+                                      error))
+        goto out;
+    }
+#endif
+
   if (!ostree_repo_load_variant (pull_data->repo, OSTREE_OBJECT_TYPE_COMMIT, checksum,
                                  &commit, error))
     goto out;
@@ -1234,6 +1249,14 @@ ostree_repo_pull (OstreeRepo               *self,
     goto out;
   pull_data->base_uri = soup_uri_new (baseurl);
 
+#ifdef HAVE_GPGME
+  if (!ot_keyfile_get_boolean_with_default (config, remote_key, "gpg-verify",
+                                            TRUE, &pull_data->gpg_verify, error))
+    goto out;
+#else
+  pull_data->gpg_verify = FALSE;
+#endif
+
   if (!ot_keyfile_get_boolean_with_default (config, remote_key, "tls-permissive",
                                             FALSE, &tls_permissive, error))
     goto out;
diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c
index 189740f..f8738a8 100644
--- a/src/libostree/ostree-repo.c
+++ b/src/libostree/ostree-repo.c
@@ -31,6 +31,8 @@
 #include "ostree-core-private.h"
 #include "ostree-repo-private.h"
 #include "ostree-repo-file.h"
+#include "ostree-repo-file-enumerator.h"
+#include "ostree-gpg-verifier.h"
 
 #ifdef HAVE_GPGME
 #include <locale.h>
@@ -403,6 +405,7 @@ ostree_repo_create (OstreeRepo     *self,
 
   config_data = g_string_new (DEFAULT_CONFIG_CONTENTS);
   g_string_append_printf (config_data, "mode=%s\n", mode_str);
+
   if (!g_file_replace_contents (self->config_file,
                                 config_data->str,
                                 config_data->len,
@@ -1646,4 +1649,134 @@ out:
   return ret;
 }
 
+/**
+ * ostree_repo_verify_commit:
+ * @self: Repository
+ * @commit_checksum: ASCII SHA256 checksum
+ * @keyringdir: (allow-none): Path to directory GPG keyrings; overrides built-in default if given
+ * @extra_keyring: (allow-none): Path to additional keyring file (not a directory)
+ * @cancellable: Cancellable
+ * @error: Error
+ *
+ * Check for a valid GPG signature on commit named by the ASCII
+ * checksum @commit_checksum.
+ */
+gboolean
+ostree_repo_verify_commit (OstreeRepo   *self,
+                           const gchar  *commit_checksum,
+                           GFile        *keyringdir,
+                           GFile        *extra_keyring,
+                           GCancellable *cancellable,
+                           GError      **error)
+{
+  gboolean ret = FALSE;
+  gs_unref_object OstreeGpgVerifier *verifier = NULL;
+  gs_unref_variant GVariant *commit_variant = NULL;
+  gs_unref_object GFile *commit_tmp_path = NULL;
+  gs_unref_object GFile *keyringdir_ref = NULL;
+  gs_unref_variant GVariant *metadata = NULL;
+  gs_unref_variant GVariant *signaturedata = NULL;
+  gs_free gchar *commit_filename = NULL;
+  gint i, n;
+  gboolean had_valid_signataure = FALSE;
+
+  if (!ostree_repo_load_variant (self, OSTREE_OBJECT_TYPE_COMMIT,
+                                 commit_checksum, &commit_variant,
+                                 error))
+    goto out;
+
+  verifier = _ostree_gpg_verifier_new (cancellable, error);
+  if (!verifier)
+    goto out;
+
+  if (keyringdir)
+    {
+      if (!_ostree_gpg_verifier_add_keyring_dir (verifier, keyringdir,
+                                                 cancellable, error))
+        goto out;
+    }
+  if (extra_keyring != NULL)
+    {
+      if (!_ostree_gpg_verifier_add_keyring (verifier, extra_keyring,
+                                             cancellable, error))
+        goto out;
+    }
+
+  if (!ostree_repo_read_commit_detached_metadata (self,
+                                                  commit_checksum,
+                                                  &metadata,
+                                                  cancellable,
+                                                  error))
+    {
+      g_prefix_error (error, "Failed to read detached metadata: ");
+      goto out;
+    }
+  
+  if (metadata)
+    signaturedata = g_variant_lookup_value (metadata, "ostree.gpgsigs", G_VARIANT_TYPE ("aay"));
+  if (!signaturedata)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
+                   "No signatures found");
+      goto out;
+    }
+
+  if (!gs_file_open_in_tmpdir (self->tmp_dir, 0644,
+                               &commit_tmp_path, NULL,
+                               cancellable, error))
+    goto out;
+  
+  if (!g_file_replace_contents (commit_tmp_path,
+                                (char*)g_variant_get_data (commit_variant),
+                                g_variant_get_size (commit_variant),
+                                NULL, FALSE, 0, NULL,
+                                cancellable, error))
+    goto out;
+
+  n = g_variant_n_children (signaturedata);
+  for (i = 0; i < n; i++)
+    {
+      GVariant *signature_variant = g_variant_get_child_value (signaturedata, i);
+      gs_unref_object GFile *temp_sig_path = NULL;
+
+      if (!gs_file_open_in_tmpdir (self->tmp_dir, 0644,
+                                   &temp_sig_path, NULL,
+                                   cancellable, error))
+        goto out;
+
+      if (!g_file_replace_contents (temp_sig_path,
+                                    (char*)g_variant_get_data (signature_variant),
+                                    g_variant_get_size (signature_variant),
+                                    NULL, FALSE, 0, NULL,
+                                    cancellable, error))
+        goto out;
+
+      if (!_ostree_gpg_verifier_check_signature (verifier,
+                                                 commit_tmp_path,
+                                                 temp_sig_path,
+                                                 &had_valid_signataure,
+                                                 cancellable, error))
+        {
+          (void) gs_file_unlink (temp_sig_path, NULL, NULL);
+          goto out;
+        }
+      (void) gs_file_unlink (temp_sig_path, NULL, NULL);
+      if (had_valid_signataure)
+        break;
+    }
+  
+  if (!had_valid_signataure)
+    {
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+                   "GPG signatures found, but none are in trusted keyring");
+      goto out;
+    }
+  
+  ret = TRUE;
+out:
+  if (commit_tmp_path)
+    (void) gs_file_unlink (commit_tmp_path, NULL, NULL);
+  return ret;
+}
+
 #endif
diff --git a/src/libostree/ostree-repo.h b/src/libostree/ostree-repo.h
index 4f40b9f..147893d 100644
--- a/src/libostree/ostree-repo.h
+++ b/src/libostree/ostree-repo.h
@@ -470,6 +470,13 @@ gboolean ostree_repo_sign_commit (OstreeRepo     *self,
                                   const gchar    *homedir,
                                   GCancellable   *cancellable,
                                   GError        **error);
+
+gboolean ostree_repo_verify_commit (OstreeRepo   *self,
+                                    const gchar  *commit_checksum,
+                                    GFile        *keyringdir,
+                                    GFile        *extra_keyring,
+                                    GCancellable *cancellable,
+                                    GError      **error);
 #endif
 
 G_END_DECLS
diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c
index df38106..bf064d5 100644
--- a/src/libostree/ostree-sysroot.c
+++ b/src/libostree/ostree-sysroot.c
@@ -232,7 +232,8 @@ ostree_sysroot_ensure_initialized (OstreeSysroot  *self,
   if (!g_file_query_exists (dir, NULL))
     {
       gs_unref_object OstreeRepo *repo = ostree_repo_new (repo_dir);
-      if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE, cancellable, error))
+      if (!ostree_repo_create (repo, OSTREE_REPO_MODE_BARE,
+                               cancellable, error))
         goto out;
     }
 
diff --git a/src/ostree/ot-admin-builtin-upgrade.c b/src/ostree/ot-admin-builtin-upgrade.c
index 27925c5..73b1bf5 100644
--- a/src/ostree/ot-admin-builtin-upgrade.c
+++ b/src/ostree/ot-admin-builtin-upgrade.c
@@ -104,11 +104,12 @@ ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancel
 
   if (origin_remote)
     {
+      OstreeRepoPullFlags pullflags = 0;
       char *refs_to_fetch[] = { origin_ref, NULL };
 
       g_print ("Fetching remote %s ref %s\n", origin_remote, origin_ref);
 
-      if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, OSTREE_REPO_PULL_FLAGS_NONE,
+      if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, pullflags,
                              cancellable, error))
         goto out;
     }
diff --git a/tests/libtest.sh b/tests/libtest.sh
index 84fd88f..a365058 100644
--- a/tests/libtest.sh
+++ b/tests/libtest.sh
@@ -24,6 +24,7 @@ export G_DEBUG=fatal-warnings
 
 export TEST_GPG_KEYID="472CDAFA"
 export TEST_GPG_HOME=${SRCDIR}/gpghome
+export OSTREE_GPG_HOME=${TEST_GPG_HOME}
 
 if test -n "${OT_TESTS_DEBUG}"; then
     set -x
diff --git a/tests/pull-test.sh b/tests/pull-test.sh
index dd93b88..5a96b08 100755
--- a/tests/pull-test.sh
+++ b/tests/pull-test.sh
@@ -20,7 +20,7 @@
 cd ${test_tmpdir}
 mkdir repo
 ${CMD_PREFIX} ostree --repo=repo init
-${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat 
httpd-address)/ostree/gnomerepo
 ${CMD_PREFIX} ostree --repo=repo pull origin main
 ${CMD_PREFIX} ostree --repo=repo fsck
 echo "ok pull"
diff --git a/tests/test-admin-deploy-1.sh b/tests/test-admin-deploy-1.sh
index d02752d..66139d5 100755
--- a/tests/test-admin-deploy-1.sh
+++ b/tests/test-admin-deploy-1.sh
@@ -132,7 +132,7 @@ ostree admin --sysroot=sysroot status
 echo "ok upgrade bare"
 
 os_repository_new_commit
-ostree --repo=sysroot/ostree/repo remote add testos file://$(pwd)/testos-repo 
testos/buildmaster/x86_64-runtime
+ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo 
testos/buildmaster/x86_64-runtime
 ostree admin --sysroot=sysroot upgrade --os=testos
 origrev=${rev}
 rev=${newrev}
diff --git a/tests/test-admin-deploy-2.sh b/tests/test-admin-deploy-2.sh
index 2e6e248..0667ed5 100755
--- a/tests/test-admin-deploy-2.sh
+++ b/tests/test-admin-deploy-2.sh
@@ -41,12 +41,12 @@ echo "ok deploy command"
 # Commit + upgrade twice, so that we'll rotate out the original deployment
 bootcsum1=${bootcsum}
 os_repository_new_commit
-ostree --repo=sysroot/ostree/repo remote add testos file://$(pwd)/testos-repo 
testos/buildmaster/x86_64-runtime
+ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo 
testos/buildmaster/x86_64-runtime
 ostree admin --sysroot=sysroot upgrade --os=testos
 bootcsum2=${bootcsum}
 os_repository_new_commit "1"
 bootcsum3=${bootcsum}
-ostree --repo=sysroot/ostree/repo remote add testos file://$(pwd)/testos-repo 
testos/buildmaster/x86_64-runtime
+ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo 
testos/buildmaster/x86_64-runtime
 ostree admin --sysroot=sysroot upgrade --os=testos
 
 rev=${newrev}
diff --git a/tests/test-archivez.sh b/tests/test-archivez.sh
index 34ba7bc..c228a66 100755
--- a/tests/test-archivez.sh
+++ b/tests/test-archivez.sh
@@ -31,7 +31,7 @@ echo "ok setup"
 cd ${test_tmpdir}
 mkdir repo2
 ${CMD_PREFIX} ostree --repo=repo2 init
-${CMD_PREFIX} ostree --repo=repo2 remote add aremote file://$(pwd)/repo test2
+${CMD_PREFIX} ostree --repo=repo2 remote add --set=gpg-verify=false aremote file://$(pwd)/repo test2
 ostree --repo=repo2 pull aremote
 ostree --repo=repo2 rev-parse aremote/test2
 ostree --repo=repo2 fsck
diff --git a/tests/test-commit-sign.sh b/tests/test-commit-sign.sh
new file mode 100755
index 0000000..516d655
--- /dev/null
+++ b/tests/test-commit-sign.sh
@@ -0,0 +1,102 @@
+#!/bin/bash
+#
+# Copyright (C) 2013 Jeremy Whiting <jeremy whiting collabora com>
+#
+# 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, write to the
+# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+# Boston, MA 02111-1307, USA.
+
+set -e
+
+if ! ostree --version | grep -q -e '\+gpgme'; then
+    exit 77
+fi
+
+. $(dirname $0)/libtest.sh
+
+keyid="472CDAFA"
+oldpwd=`pwd`
+mkdir ostree-srv
+cd ostree-srv
+mkdir gnomerepo
+${CMD_PREFIX} ostree --repo=gnomerepo init --mode="archive-z2"
+mkdir gnomerepo-files
+cd gnomerepo-files 
+echo first > firstfile
+mkdir baz
+echo moo > baz/cow
+echo alien > baz/saucer
+${CMD_PREFIX} ostree  --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "A remote commit" -m 
"Some Commit body" --gpg-sign=$keyid --gpg-homedir=${SRCDIR}/gpghome
+mkdir baz/deeper
+${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "Add deeper" 
--gpg-sign=$keyid --gpg-homedir=${SRCDIR}/gpghome
+echo hi > baz/deeper/ohyeah
+mkdir baz/another/
+echo x > baz/another/y
+${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit -b main -s "The rest" 
--gpg-sign=$keyid --gpg-homedir=${SRCDIR}/gpghome
+cd ..
+rm -rf gnomerepo-files
+
+cd ${test_tmpdir}
+mkdir ${test_tmpdir}/httpd
+cd httpd
+ln -s ${test_tmpdir}/ostree-srv ostree
+ostree trivial-httpd --daemonize -p ${test_tmpdir}/httpd-port
+port=$(cat ${test_tmpdir}/httpd-port)
+echo "http://127.0.0.1:${port}"; > ${test_tmpdir}/httpd-address
+cd ${oldpwd} 
+
+export OSTREE="ostree --repo=repo"
+
+repopath=${test_tmpdir}/ostree-srv/gnomerepo
+cp -a ${repopath} ${repopath}.orig
+
+# Set OSTREE_GPG_HOME to a place with no keyrings, we shouldn't trust the signature
+cd ${test_tmpdir}
+mkdir repo
+${CMD_PREFIX} ostree --repo=repo init
+${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+if env OSTREE_GPG_HOME=${test_tmpdir} ${CMD_PREFIX} ostree --repo=repo pull origin main; then
+    assert_not_reached "pull with no trusted GPG keys unexpectedly succeeded!"
+fi
+rm repo -rf
+
+# And a test case with valid signature
+cd ${test_tmpdir}
+mkdir repo
+${CMD_PREFIX} ostree --repo=repo init
+${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+${CMD_PREFIX} ostree --repo=repo pull origin main
+rm repo -rf
+
+# A test with corrupted detached signature
+cd ${test_tmpdir}
+find ${test_tmpdir}/ostree-srv/gnomerepo -name '*.commitmeta' | while read fname; do
+    echo borkborkbork > ${fname};
+done
+mkdir repo
+${CMD_PREFIX} ostree --repo=repo init
+${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+if ${CMD_PREFIX} ostree --repo=repo pull origin main; then
+    assert_not_reached "pull with corrupted signature unexpectedly succeeded!"
+fi
+rm repo -rf
+
+# And now attempt to pull the same corrupted commit, but with GPG
+# verification off
+cd ${test_tmpdir}
+mkdir repo
+${CMD_PREFIX} ostree --repo=repo init
+${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat 
httpd-address)/ostree/gnomerepo
+${CMD_PREFIX} ostree --repo=repo pull origin main
+rm repo -rf
diff --git a/tests/test-pull-corruption.sh b/tests/test-pull-corruption.sh
index 70efa88..394a9e8 100755
--- a/tests/test-pull-corruption.sh
+++ b/tests/test-pull-corruption.sh
@@ -33,7 +33,7 @@ do_corrupt_pull_test() {
     rm repo -rf
     mkdir repo
     ${CMD_PREFIX} ostree --repo=repo init
-    ${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+    ${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat 
httpd-address)/ostree/gnomerepo
     if ${CMD_PREFIX} ostree --repo=repo pull origin main; then
         assert_not_reached "pull unexpectedly succeeded!"
     fi
diff --git a/tests/test-pull-resume.sh b/tests/test-pull-resume.sh
index 4770c0b..fcca839 100755
--- a/tests/test-pull-resume.sh
+++ b/tests/test-pull-resume.sh
@@ -32,7 +32,7 @@ cd ${test_tmpdir}
 rm repo -rf
 mkdir repo
 ${CMD_PREFIX} ostree --repo=repo init
-${CMD_PREFIX} ostree --repo=repo remote add origin $(cat httpd-address)/ostree/gnomerepo
+${CMD_PREFIX} ostree --repo=repo remote add --set=gpg-verify=false origin $(cat 
httpd-address)/ostree/gnomerepo
 
 maxtries=`find ${repopath}/objects | wc -l`
 maxtries=`expr $maxtries \* 2`


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]