diff --git a/configure.ac b/configure.ac index 11a040a..00a24ee 100644 --- a/configure.ac +++ b/configure.ac @@ -17,10 +17,11 @@ AC_PROG_CC AC_PROG_CPP AM_PROG_CC_C_O -dnl Checks for libraries. +AC_CHECK_FUNCS(mlock) -dnl **************************** -dnl *** Checks for intltool +# -------------------------------------------------------------------- +# intltool +# IT_PROG_INTLTOOL([0.35.0]) GETTEXT_PACKAGE=gsecret @@ -29,22 +30,55 @@ AC_SUBST([GETTEXT_PACKAGE]) AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE],["$GETTEXT_PACKAGE"],[The gettext domain name]) AM_GLIB_GNU_GETTEXT -dnl ***************************** -dnl *** Check GLib +# -------------------------------------------------------------------- +# GLib +# -PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16.0 gio-2.0 >= 2.16.0 gthread-2.0 >= 2.16.0) +PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28.0 gio-2.0 >= 2.28.0 gthread-2.0 >= 2.16.0) LIBS="$LIBS $GLIB_LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" -AC_CHECK_FUNCS(mlock) +# -------------------------------------------------------------------- +# libgcrypt +# + +GCRYPT_VERSION=1.2.2 +GCRYPT_LIBVER=1 + +AC_ARG_ENABLE(gcrypt, + [AC_HELP_STRING([--disable-gcrypt], + [without gcrypt and transport encryption]) + ]) + +if test "$enable_gcrypt" != "no"; then + AM_PATH_LIBGCRYPT($GCRYPT_LIBVER:$GCRYPT_VERSION,, + AC_MSG_ERROR([[ +*** +*** libgcrypt was not found. You may want to get it from +*** ftp://ftp.gnupg.org/gcrypt/libgcrypt/ +*** + ]])) + + AC_DEFINE(WITH_GCRYPT, 1, [Build with libgcypt and transport encryption]) + AC_DEFINE_UNQUOTED(LIBGCRYPT_VERSION, "$GCRYPT_VERSION", + [Version of GCRYPT we expect]) + + AC_SUBST([LIBGCRYPT_CFLAGS]) + AC_SUBST([LIBGCRYPT_LIBS]) + enable_gcrypt="yes" + +fi + +AM_CONDITIONAL(WITH_GCRYPT, test "$enable_gcrypt" = "yes") + dnl ************************************* dnl *** Warnings to show if using GCC *** dnl ************************************* AC_ARG_ENABLE(more-warnings, - AS_HELP_STRING([--disable-more-warnings], [Inhibit compiler warnings]), - set_more_warnings=no) + AS_HELP_STRING([--disable-more-warnings], [Inhibit compiler warnings]), + set_more_warnings=no) if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then CFLAGS="$CFLAGS \ @@ -67,6 +101,17 @@ if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then done fi +AC_ARG_ENABLE(strict, [ + AS_HELP_STRING([--enable-strict], [Strict code compilation]) + ]) + +if test "$enable_strict" = "yes"; then + CFLAGS="$CFLAGS -Werror \ + -DGTK_DISABLE_DEPRECATED \ + -DGDK_DISABLE_DEPRECATED \ + -DG_DISABLE_DEPRECATED" +fi + dnl ***************************** dnl *** done *** dnl ***************************** @@ -79,3 +124,14 @@ AC_CONFIG_FILES([ library/tests/Makefile ]) AC_OUTPUT + +# ------------------------------------------------------------------------------ +# Summary +# + +echo +echo "CFLAGS: $CFLAGS" +echo +echo "OPTIONS:" +echo " libgcrypt: $enable_gcrypt" +echo diff --git a/egg/Makefile.am b/egg/Makefile.am index b70bf52..d499fea 100644 --- a/egg/Makefile.am +++ b/egg/Makefile.am @@ -5,8 +5,15 @@ noinst_LTLIBRARIES = \ INCLUDES = \ -I$(top_srcdir) +if WITH_GCRYPT +ENCRYPTION_SRCS = egg-dh.c egg-dh.h +ENCRYPTION_SRCS += egg-hkdf.c egg-hkdf.h +ENCRYPTION_SRCS += egg-libgcrypt.c egg-libgcrypt.h +else +ENCRYPTION_SRCS = +endif + libegg_la_SOURCES = \ - egg-dh.c egg-dh.h \ - egg-hkdf.c egg-hkdf.h \ egg-secure-memory.c egg-secure-memory.h \ - $(BUILT_SOURCES) + $(ENCRYPTION_SRCS) \ + $(BUILT_SOURCES) \ No newline at end of file diff --git a/egg/egg-libgcrypt.c b/egg/egg-libgcrypt.c new file mode 100644 index 0000000..e5b3f55 --- /dev/null +++ b/egg/egg-libgcrypt.c @@ -0,0 +1,120 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program 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.1 of + * the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "config.h" + +#include "egg-libgcrypt.h" +#include "egg-secure-memory.h" + +#include + +#include + +EGG_SECURE_DECLARE (libgcrypt); + +static void +log_handler (gpointer unused, int unknown, const gchar *msg, va_list va) +{ + /* TODO: Figure out additional arguments */ + g_logv ("gcrypt", G_LOG_LEVEL_MESSAGE, msg, va); +} + +static int +no_mem_handler (gpointer unused, size_t sz, unsigned int unknown) +{ + /* TODO: Figure out additional arguments */ + g_error ("couldn't allocate %lu bytes of memory", + (unsigned long int)sz); + return 0; +} + +static void +fatal_handler (gpointer unused, int unknown, const gchar *msg) +{ + /* TODO: Figure out additional arguments */ + g_log ("gcrypt", G_LOG_LEVEL_ERROR, "%s", msg); +} + +static int +glib_thread_mutex_init (void **lock) +{ + *lock = g_mutex_new (); + return 0; +} + +static int +glib_thread_mutex_destroy (void **lock) +{ + g_mutex_free (*lock); + return 0; +} + +static int +glib_thread_mutex_lock (void **lock) +{ + g_mutex_lock (*lock); + return 0; +} + +static int +glib_thread_mutex_unlock (void **lock) +{ + g_mutex_unlock (*lock); + return 0; +} + +static struct gcry_thread_cbs glib_thread_cbs = { + GCRY_THREAD_OPTION_USER, NULL, + glib_thread_mutex_init, glib_thread_mutex_destroy, + glib_thread_mutex_lock, glib_thread_mutex_unlock, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +void +egg_libgcrypt_initialize (void) +{ + static volatile gsize gcrypt_initialized = 0; + unsigned seed; + + if (g_once_init_enter (&gcrypt_initialized)) { + + /* Only initialize libgcrypt if it hasn't already been initialized */ + if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) { + if (g_thread_supported()) + gcry_control (GCRYCTL_SET_THREAD_CBS, &glib_thread_cbs); + gcry_check_version (LIBGCRYPT_VERSION); + gcry_set_log_handler (log_handler, NULL); + gcry_set_outofcore_handler (no_mem_handler, NULL); + gcry_set_fatalerror_handler (fatal_handler, NULL); + gcry_set_allocation_handler ((gcry_handler_alloc_t)g_malloc, + (gcry_handler_alloc_t)egg_secure_alloc, + egg_secure_check, + (gcry_handler_realloc_t)egg_secure_realloc, + egg_secure_free); + gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); + } + + gcry_create_nonce (&seed, sizeof (seed)); + srand (seed); + + g_once_init_leave (&gcrypt_initialized, 1); + } +} diff --git a/egg/egg-libgcrypt.h b/egg/egg-libgcrypt.h new file mode 100644 index 0000000..1aee422 --- /dev/null +++ b/egg/egg-libgcrypt.h @@ -0,0 +1,28 @@ +/* + * gnome-keyring + * + * Copyright (C) 2008 Stefan Walter + * + * This program 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.1 of + * the License, or (at your option) any later version. + * + * This program 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 program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#ifndef EGG_LIBGCRYPT_H_ +#define EGG_LIBGCRYPT_H_ + +/* Initializes libgcrypt for use in a glib program */ +void egg_libgcrypt_initialize (void); + +#endif /* EGG_LIBGCRYPT_H_ */ diff --git a/library/Makefile.am b/library/Makefile.am index c7c79a4..5ce70d8 100644 --- a/library/Makefile.am +++ b/library/Makefile.am @@ -18,6 +18,10 @@ libgsecret_la_SOURCES = \ gsecret-util.c \ $(NULL) +libgsecret_la_CFLAGS = \ + $(LIBGCRYPT_CFLAGS) + libgsecret_la_LIBADD = \ $(top_builddir)/egg/libegg.la \ + $(LIBGCRYPT_LIBS) \ $(LIBS) \ No newline at end of file diff --git a/library/gsecret-service.c b/library/gsecret-service.c index 3c4beda..6267065 100644 --- a/library/gsecret-service.c +++ b/library/gsecret-service.c @@ -17,24 +17,30 @@ #include "gsecret-types.h" #include "gsecret-value.h" +#ifdef WITH_GCRYPT +#include "egg/egg-dh.h" +#include "egg/egg-hkdf.h" +#include "egg/egg-libgcrypt.h" +#endif + +#include "egg/egg-secure-memory.h" + #include #include #include -#include "egg/egg-dh.h" -#include "egg/egg-hkdf.h" -#include "egg/egg-secure-memory.h" - EGG_SECURE_GLIB_DEFINITIONS (); EGG_SECURE_DECLARE (secret_service); typedef struct { gchar *path; +#ifdef WITH_GCRYPT gcry_mpi_t prime; gcry_mpi_t privat; gcry_mpi_t publi; +#endif gpointer key; gsize n_key; } GSecretSession; @@ -52,13 +58,17 @@ gsecret_session_free (gpointer data) return; g_free (session->path); +#ifdef WITH_GCRYPT gcry_mpi_release (session->publi); gcry_mpi_release (session->privat); gcry_mpi_release (session->prime); +#endif egg_secure_free (session->key); g_free (session); } +#ifdef WITH_GCRYPT + static GVariant * request_open_session_aes (GSecretSession *session) { @@ -136,6 +146,8 @@ response_open_session_aes (GSecretSession *session, return TRUE; } +#endif /* WITH_GCRYPT */ + static GVariant * request_open_session_plain (GSecretSession *session) { @@ -218,6 +230,8 @@ on_service_open_session_plain (GObject *source, g_object_unref (res); } +#ifdef WITH_GCRYPT + static void on_service_open_session_aes (GObject *source, GAsyncResult *result, @@ -268,6 +282,10 @@ on_service_open_session_aes (GObject *source, g_object_unref (res); } + + +#endif /* WITH_GCRYPT */ + void gsecret_service_ensure_session (GSecretService *self, GCancellable *cancellable, @@ -292,9 +310,15 @@ gsecret_service_ensure_session (GSecretService *self, g_simple_async_result_set_op_res_gpointer (res, closure, open_session_closure_free); g_dbus_proxy_call (G_DBUS_PROXY (self), "OpenSession", +#ifdef WITH_GCRYPT request_open_session_aes (closure->session), G_DBUS_CALL_FLAGS_NONE, -1, cancellable, on_service_open_session_aes, +#else + request_open_session_plain (closure->session), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, on_service_open_session_plain, +#endif g_object_ref (res)); /* Already have a session */ @@ -347,6 +371,7 @@ gsecret_service_ensure_session_sync (GSecretService *self, return session->path; session = g_new0 (GSecretSession, 1); +#ifdef WITH_GCRYPT response = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "OpenSession", request_open_session_aes (session), G_DBUS_CALL_FLAGS_NONE, -1, @@ -359,7 +384,7 @@ gsecret_service_ensure_session_sync (GSecretService *self, /* AES session not supported, request a plain session */ } else if (g_error_matches (lerror, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED)) { g_clear_error (&lerror); - +#endif /* WITH_GCRYPT */ response = g_dbus_proxy_call_sync (G_DBUS_PROXY (self), "OpenSession", request_open_session_plain (session), G_DBUS_CALL_FLAGS_NONE, -1, @@ -369,7 +394,9 @@ gsecret_service_ensure_session_sync (GSecretService *self, complete = response_open_session_plain (session, response); g_variant_unref (response); } +#ifdef WITH_GCRYPT } +#endif if (lerror == NULL && !complete) { g_set_error (&lerror, GSECRET_ERROR, GSECRET_ERROR_PROTOCOL, @@ -393,6 +420,8 @@ gsecret_service_ensure_session_sync (GSecretService *self, return session->path; } +#ifdef WITH_GCRYPT + static gboolean pkcs7_unpad_bytes_in_place (guchar *padded, gsize *n_padded) @@ -483,6 +512,8 @@ service_decode_aes_secret (GSecretSession *session, return gsecret_value_new_full ((gchar *)padded, n_padded, content_type, egg_secure_free); } +#endif /* WITH_GCRYPT */ + static GSecretValue * service_decode_plain_secret (GSecretSession *session, gconstpointer param, @@ -537,13 +568,14 @@ _gsecret_service_decode_secret (GSecretService *self, value = g_variant_get_fixed_array (vvalue, &n_value, sizeof (guchar)); g_variant_get_child (encoded, 3, "s", &content_type); - if (session->key != NULL) { +#ifdef WITH_GCRYPT + if (session->key != NULL) result = service_decode_aes_secret (session, param, n_param, value, n_value, content_type); - } else { + else +#endif result = service_decode_plain_secret (session, param, n_param, value, n_value, content_type); - } g_variant_unref (vparam); g_variant_unref (vvalue); @@ -553,6 +585,8 @@ _gsecret_service_decode_secret (GSecretService *self, return result; } +#ifdef WITH_GCRYPT + static guchar* pkcs7_pad_bytes_in_secure_memory (gconstpointer secret, gsize length, @@ -632,6 +666,8 @@ service_encode_aes_secret (GSecretSession *session, return TRUE; } +#endif /* WITH_GCRYPT */ + static gboolean service_encode_plain_secret (GSecretSession *session, GSecretValue *value, @@ -678,9 +714,11 @@ _gsecret_service_encode_secret (GSecretService *self, type = g_variant_type_new ("(oayays)"); builder = g_variant_builder_new (type); +#ifdef WITH_GCRYPT if (session->key) ret = service_encode_aes_secret (session, value, builder); else +#endif ret = service_encode_plain_secret (session, value, builder); if (ret) result = g_variant_builder_end (builder);