From 25ad4a9f65a5dae9348fd38c7f4b8b0df1f9773a Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Thu, 1 May 2014 12:55:13 -0400 Subject: [PATCH] pull: Add tls-client-cert-{path,key} (if we have new enough libsoup) This is an actually working version of client-side certificates. Depends on: See: https://bugzilla.gnome.org/show_bug.cgi?id=334021 We detect whether libsoup is new enough for this. https://bugzilla.gnome.org/show_bug.cgi?id=729356 --- Makefile-libostree.am | 8 ++- configure.ac | 9 +++ doc/ostree.repo-config.xml | 20 +++++- src/libostree/ostree-fetcher.c | 28 +++++++++ src/libostree/ostree-fetcher.h | 3 + src/libostree/ostree-repo-pull.c | 35 +++++++++++ src/libostree/ostree-tls-cert-interaction.c | 69 +++++++++++++++++++++ src/libostree/ostree-tls-cert-interaction.h | 39 ++++++++++++ 8 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 src/libostree/ostree-tls-cert-interaction.c create mode 100644 src/libostree/ostree-tls-cert-interaction.h diff --git a/Makefile-libostree.am b/Makefile-libostree.am index 5fd60006..d2c039cf 100644 --- a/Makefile-libostree.am +++ b/Makefile-libostree.am @@ -1,6 +1,6 @@ # Makefile for C source code # -# Copyright (C) 2011 Colin Walters +# Copyright (C) 2011,2014 Colin Walters # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -88,6 +88,12 @@ libostree_1_la_SOURCES += src/libostree/ostree-libarchive-input-stream.h \ src/libostree/ostree-libarchive-input-stream.c \ $(NULL) endif +if HAVE_LIBSOUP_CLIENT_CERTS +libostree_1_la_SOURCES += \ + src/libostree/ostree-tls-cert-interaction.c \ + src/libostree/ostree-tls-cert-interaction.h \ + $(NULL) +endif libostree_1_la_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/src/libotutil -I$(srcdir)/src/libostree -DLOCALEDIR=\"$(datadir)/locale\" -DGPGVPATH=\"$(GPGVPATH)\" $(OT_INTERNAL_GIO_UNIX_CFLAGS) $(OT_DEP_LZMA_CFLAGS) libostree_1_la_LDFLAGS = -version-number 1:0:0 -Bsymbolic-functions -export-symbols-regex '^ostree_' diff --git a/configure.ac b/configure.ac index 9089ddc6..74094c9c 100644 --- a/configure.ac +++ b/configure.ac @@ -63,12 +63,21 @@ AS_IF([test x$with_soup != xno ], [ PKG_CHECK_MODULES(OT_DEP_SOUP, $SOUP_DEPENDENCY) AC_DEFINE(HAVE_LIBSOUP, 1, [Define if we have libsoup.pc]) with_soup=yes + save_CFLAGS=$CFLAGS + CFLAGS=$OT_DEP_SOUP_CFLAGS + have_libsoup_client_certs=no + AC_CHECK_DECL([SOUP_SESSION_TLS_INTERACTION], [ + AC_DEFINE(HAVE_LIBSOUP_CLIENT_CERTS, 1, [Define if we have libsoup client certs]) + have_libsoup_client_certs=yes + ], [], [#include ]) + CFLAGS=$save_CFLAGS ], [ with_soup=no ]) ], [ with_soup=no ]) if test x$with_soup != xno; then OSTREE_FEATURES="$OSTREE_FEATURES +libsoup"; fi AM_CONDITIONAL(USE_LIBSOUP, test x$with_soup != xno) +AM_CONDITIONAL(HAVE_LIBSOUP_CLIENT_CERTS, test x$have_libsoup_client_certs = xyes) m4_ifdef([GOBJECT_INTROSPECTION_CHECK], [ GOBJECT_INTROSPECTION_CHECK([1.34.0]) diff --git a/doc/ostree.repo-config.xml b/doc/ostree.repo-config.xml index 07244d03..42408143 100644 --- a/doc/ostree.repo-config.xml +++ b/doc/ostree.repo-config.xml @@ -104,12 +104,30 @@ Boston, MA 02111-1307, USA. gpg-verify - A boolean value, defaults to true. + A boolean value, defaults to true. Controls whether or not OSTree will require commits to be signed by a known GPG key. For more information, see the ostree1 manual under GPG. + + + tls-permissive + A boolean value, defaults to false. By + default, server TLS certificates will be checked against the + system certificate store. If this variable is set, any + certificate will be accepted. + + + + tls-client-cert-path + Path to file for client-side certificate, to present when making requests to this repository. + + + + tls-client-key-path + Path to file containing client-side certificate key, to present when making requests to this repository. + diff --git a/src/libostree/ostree-fetcher.c b/src/libostree/ostree-fetcher.c index c8db3a08..06023c6b 100644 --- a/src/libostree/ostree-fetcher.c +++ b/src/libostree/ostree-fetcher.c @@ -25,6 +25,9 @@ #include #include "ostree-fetcher.h" +#ifdef HAVE_LIBSOUP_CLIENT_CERTS +#include "ostree-tls-cert-interaction.h" +#endif #include "ostree.h" #include "otutil.h" #include "libgsystem.h" @@ -79,6 +82,8 @@ struct OstreeFetcher GFile *tmpdir; + GTlsCertificate *client_cert; + SoupSession *session; SoupRequester *requester; @@ -107,6 +112,7 @@ ostree_fetcher_finalize (GObject *object) g_clear_object (&self->session); g_clear_object (&self->tmpdir); + g_clear_object (&self->client_cert); g_hash_table_destroy (self->sending_messages); g_hash_table_destroy (self->message_to_request); @@ -175,6 +181,9 @@ ostree_fetcher_init (OstreeFetcher *self) } } + if (g_getenv ("OSTREE_DEBUG_HTTP")) + soup_session_add_feature (self->session, (SoupSessionFeature*)soup_logger_new (SOUP_LOGGER_LOG_BODY, 500)); + self->requester = (SoupRequester *)soup_session_get_feature (self->session, SOUP_TYPE_REQUESTER); g_object_get (self->session, "max-conns-per-host", &max_conns, NULL); self->max_outstanding = 3 * max_conns; @@ -204,6 +213,24 @@ ostree_fetcher_new (GFile *tmpdir, return self; } +void +ostree_fetcher_set_client_cert (OstreeFetcher *fetcher, + GTlsCertificate *cert) +{ + g_clear_object (&fetcher->client_cert); + fetcher->client_cert = g_object_ref (cert); + if (fetcher->client_cert) + { +#ifdef HAVE_LIBSOUP_CLIENT_CERTS + gs_unref_object GTlsInteraction *interaction = + (GTlsInteraction*)ostree_tls_cert_interaction_new (fetcher->client_cert); + g_object_set (fetcher->session, "tls-interaction", interaction, NULL); +#else + g_warning ("This version of OSTree is compiled without client side certificate support"); +#endif + } +} + static void on_request_sent (GObject *object, GAsyncResult *result, gpointer user_data); @@ -215,6 +242,7 @@ ostree_fetcher_process_pending_queue (OstreeFetcher *self) self->outstanding < self->max_outstanding) { OstreeFetcherPendingURI *next = g_queue_pop_head (&self->pending_queue); + self->outstanding++; soup_request_send_async (next->request, next->cancellable, on_request_sent, next); diff --git a/src/libostree/ostree-fetcher.h b/src/libostree/ostree-fetcher.h index 220bd931..928d2a35 100644 --- a/src/libostree/ostree-fetcher.h +++ b/src/libostree/ostree-fetcher.h @@ -54,6 +54,9 @@ GType ostree_fetcher_get_type (void) G_GNUC_CONST; OstreeFetcher *ostree_fetcher_new (GFile *tmpdir, OstreeFetcherConfigFlags flags); +void ostree_fetcher_set_client_cert (OstreeFetcher *fetcher, + GTlsCertificate *cert); + char * ostree_fetcher_query_state_text (OstreeFetcher *self); guint64 ostree_fetcher_bytes_transferred (OstreeFetcher *self); diff --git a/src/libostree/ostree-repo-pull.c b/src/libostree/ostree-repo-pull.c index 427bd924..e3e5a775 100644 --- a/src/libostree/ostree-repo-pull.c +++ b/src/libostree/ostree-repo-pull.c @@ -1086,6 +1086,41 @@ ostree_repo_pull (OstreeRepo *self, pull_data->fetcher = ostree_fetcher_new (pull_data->repo->tmp_dir, fetcher_flags); + { + gs_free char *tls_client_cert_path = NULL; + gs_free char *tls_client_key_path = NULL; + + if (!ot_keyfile_get_value_with_default (config, remote_key, + "tls-client-cert-path", + NULL, &tls_client_cert_path, error)) + goto out; + if (!ot_keyfile_get_value_with_default (config, remote_key, + "tls-client-key-path", + NULL, &tls_client_key_path, error)) + goto out; + + if ((tls_client_cert_path != NULL) != (tls_client_key_path != NULL)) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + "\"%s\" must specify both \"tls-client-cert-path\" and \"tls-client-key-path\"", remote_key); + goto out; + } + else if (tls_client_cert_path) + { + gs_unref_object GTlsCertificate *client_cert = NULL; + + g_assert (tls_client_key_path); + + client_cert = g_tls_certificate_new_from_files (tls_client_cert_path, + tls_client_key_path, + error); + if (!client_cert) + goto out; + + ostree_fetcher_set_client_cert (pull_data->fetcher, client_cert); + } + } + if (!pull_data->base_uri) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, diff --git a/src/libostree/ostree-tls-cert-interaction.c b/src/libostree/ostree-tls-cert-interaction.c new file mode 100644 index 00000000..63de9173 --- /dev/null +++ b/src/libostree/ostree-tls-cert-interaction.c @@ -0,0 +1,69 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2014 Colin Walters + * + * 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 . + */ + +#include "config.h" + +#include "ostree-tls-cert-interaction.h" + +struct _OstreeTlsCertInteraction +{ + GTlsInteraction parent_instance; + + GTlsCertificate *cert; +}; + +struct _OstreeTlsCertInteractionClass +{ + GTlsInteractionClass parent_class; +}; + +#include + +G_DEFINE_TYPE (OstreeTlsCertInteraction, ostree_tls_cert_interaction, G_TYPE_TLS_INTERACTION); + +static GTlsInteractionResult +request_certificate (GTlsInteraction *interaction, + GTlsConnection *connection, + GTlsCertificateRequestFlags flags, + GCancellable *cancellable, + GError **error) +{ + OstreeTlsCertInteraction *self = (OstreeTlsCertInteraction*)interaction; + g_tls_connection_set_certificate (connection, self->cert); + return G_TLS_INTERACTION_HANDLED; +} + +static void +ostree_tls_cert_interaction_init (OstreeTlsCertInteraction *interaction) +{ +} + +static void +ostree_tls_cert_interaction_class_init (OstreeTlsCertInteractionClass *klass) +{ + GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass); + interaction_class->request_certificate = request_certificate; +} + +OstreeTlsCertInteraction * +ostree_tls_cert_interaction_new (GTlsCertificate *cert) +{ + OstreeTlsCertInteraction *self = g_object_new (OSTREE_TYPE_TLS_CERT_INTERACTION, NULL); + self->cert = g_object_ref (cert); + return self; +} diff --git a/src/libostree/ostree-tls-cert-interaction.h b/src/libostree/ostree-tls-cert-interaction.h new file mode 100644 index 00000000..ca9cd325 --- /dev/null +++ b/src/libostree/ostree-tls-cert-interaction.h @@ -0,0 +1,39 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * + * Copyright (C) 2013 Colin Walters + * + * 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 . + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define OSTREE_TYPE_TLS_CERT_INTERACTION (ostree_tls_cert_interaction_get_type ()) +#define OSTREE_TLS_CERT_INTERACTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), OSTREE_TYPE_TLS_CERT_INTERACTION, OstreeTlsCertInteraction)) +#define OSTREE_TLS_CERT_INTERACTION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), OSTREE_TYPE_TLS_CERT_INTERACTION, OstreeTlsCertInteractionClass)) +#define OSTREE_IS_TLS_CERT_INTERACTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), OSTREE_TYPE_TLS_CERT_INTERACTION)) +#define OSTREE_IS_TLS_CERT_INTERACTION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), OSTREE_TYPE_TLS_CERT_INTERACTION)) +#define OSTREE_TLS_CERT_INTERACTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), OSTREE_TYPE_TLS_CERT_INTERACTION, OstreeTlsCertInteractionClass)) + +typedef struct _OstreeTlsCertInteraction OstreeTlsCertInteraction; +typedef struct _OstreeTlsCertInteractionClass OstreeTlsCertInteractionClass; + +GType ostree_tls_cert_interaction_get_type (void) G_GNUC_CONST; + +OstreeTlsCertInteraction * ostree_tls_cert_interaction_new (GTlsCertificate *cert); + +G_END_DECLS