[gnome-keyring/dbus-api] Implement prompt password return via encryption.
- From: Stefan Walter <stefw src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gnome-keyring/dbus-api] Implement prompt password return via encryption.
- Date: Thu, 5 Nov 2009 05:54:29 +0000 (UTC)
commit 140996d802b7ad338a3377dd6c368169c2c5e056
Author: Stef Walter <stef memberwebs com>
Date: Tue Nov 3 03:06:44 2009 +0000
Implement prompt password return via encryption.
* Prompt password encrypted return via DH key negotiation.
* Factor out some common code between prompt-tool and daemon.
* Add tests for common code.
configure.in | 1 +
daemon/.gitignore | 1 +
daemon/prompt/Makefile.am | 16 ++-
daemon/prompt/gkd-prompt-tool.c | 116 +++++++++-
daemon/prompt/gkd-prompt-util.c | 248 ++++++++++++++++++++
daemon/prompt/gkd-prompt-util.h | 49 ++++
daemon/prompt/gkd-prompt.c | 160 ++------------
daemon/prompt/tests/Makefile.am | 14 ++
.../prompt/{test => tests}/test-data/prompt-empty | 0
.../prompt/{test => tests}/test-data/prompt-full | 0
.../prompt/{test => tests}/test-data/prompt-test | 0
daemon/prompt/tests/unit-test-util.c | 146 ++++++++++++
egg/Makefile.am | 20 ++-
egg/egg-dh.c | 4 +
egg/egg-dh.h | 2 +
15 files changed, 621 insertions(+), 156 deletions(-)
---
diff --git a/configure.in b/configure.in
index bacc953..0c97846 100644
--- a/configure.in
+++ b/configure.in
@@ -533,6 +533,7 @@ daemon/keyrings/Makefile
daemon/keyrings/tests/Makefile
daemon/pkcs11/Makefile
daemon/prompt/Makefile
+daemon/prompt/tests/Makefile
daemon/ui/Makefile
daemon/util/Makefile
daemon/util/tests/Makefile
diff --git a/daemon/.gitignore b/daemon/.gitignore
index 977c5e9..f6d0066 100644
--- a/daemon/.gitignore
+++ b/daemon/.gitignore
@@ -9,4 +9,5 @@ Makefile.in
/gnome-keyring-daemon.desktop.in
*-marshal.[ch]
gnome-keyring-prompt
+run-auto-test*
diff --git a/daemon/prompt/Makefile.am b/daemon/prompt/Makefile.am
index a1a2379..2269fd0 100644
--- a/daemon/prompt/Makefile.am
+++ b/daemon/prompt/Makefile.am
@@ -1,4 +1,12 @@
+if WITH_TESTS
+TESTS_DIR = tests
+else
+TESTS_DIR =
+endif
+
+SUBDIRS = . $(TESTS_DIR)
+
INCLUDES= \
-DPREFIX=\""$(prefix)"\" \
-DBINDIR=\""$(bindir)"\" \
@@ -28,6 +36,7 @@ BUILT_SOURCES = \
libgkd_prompt_la_SOURCES = \
gkd-prompt.c gkd-prompt.h \
+ gkd-prompt-util.c gkd-prompt-util.h \
$(BUILT_SOURCES)
libgkd_prompt_la_LIBADD = \
@@ -51,12 +60,15 @@ libexec_PROGRAMS= \
gnome-keyring-prompt
gnome_keyring_prompt_SOURCES = \
- gkd-prompt-tool.c
+ gkd-prompt-tool.c \
+ gkd-prompt-util.c gkd-prompt-util.h
gnome_keyring_prompt_LDADD = \
- $(top_builddir)/egg/libegg.la \
+ $(top_builddir)/egg/libegg-prompt.la \
+ $(LIBGCRYPT_LIBS) \
$(GTK_LIBS)
gnome_keyring_prompt_CFLAGS = \
-DUIDIR=\""$(uidir)"\" \
+ $(LIBGCRYPT_CFLAGS) \
$(GTK_CFLAGS)
diff --git a/daemon/prompt/gkd-prompt-tool.c b/daemon/prompt/gkd-prompt-tool.c
index d1d0b7e..39ee2bb 100644
--- a/daemon/prompt/gkd-prompt-tool.c
+++ b/daemon/prompt/gkd-prompt-tool.c
@@ -22,23 +22,33 @@
#include "config.h"
+#include "gkd-prompt-util.h"
+
+#include "egg/egg-dh.h"
#include "egg/egg-secure-memory.h"
-#include <gtk/gtk.h>
+#include <gcrypt.h>
+
#include <glib/gi18n.h>
-#include <stdio.h>
-#include <string.h>
+#include <gtk/gtk.h>
+
+#include <errno.h>
#include <locale.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
+#include <string.h>
#include <syslog.h>
+#include <unistd.h>
static GKeyFile *input_data = NULL;
static GKeyFile *output_data = NULL;
static gboolean keyboard_grabbed = FALSE;
+/* An encryption key for returning passwords */
+static gpointer the_key = NULL;
+static gsize n_the_key = 0;
+
#define LOG_ERRORS 1
/* ------------------------------------------------------------------------------ */
@@ -212,11 +222,91 @@ prepare_dialog (GtkBuilder *builder)
return dialog;
}
+static gboolean
+negotiate_transport_crypto (void)
+{
+ gcry_mpi_t base, prime, peer;
+ gcry_mpi_t key, pub, secret;
+ gboolean ret = FALSE;
+
+ g_assert (!the_key);
+ base = prime = peer = NULL;
+ key = pub = secret = NULL;
+
+ /* The DH stuff coming in from our caller */
+ if (gkd_prompt_util_decode_mpi (input_data, "transport", "prime", &prime) &&
+ gkd_prompt_util_decode_mpi (input_data, "transport", "base", &base) &&
+ gkd_prompt_util_decode_mpi (input_data, "transport", "public", &peer)) {
+
+ /* Generate our own public/secret, and then a key, send it back */
+ if (egg_dh_gen_secret (prime, base, &pub, &secret) &&
+ egg_dh_gen_key (peer, secret, prime, &key)) {
+
+ /* Build up a key we can use */
+ gkd_prompt_util_encode_mpi (output_data, "transport", "public", pub);
+ if (gkd_prompt_util_mpi_to_key (key, &the_key, &n_the_key))
+ ret = TRUE;
+ }
+ }
+
+ gcry_mpi_release (base);
+ gcry_mpi_release (prime);
+ gcry_mpi_release (peer);
+ gcry_mpi_release (key);
+ gcry_mpi_release (pub);
+ gcry_mpi_release (secret);
+
+ return ret;
+}
+
+static void
+gather_password (GtkBuilder *builder, const gchar *password_type)
+{
+ GtkEntry *entry;
+ gchar iv[16];
+ gpointer data;
+ gsize n_data;
+
+ entry = GTK_ENTRY (gtk_builder_get_object (builder, "password_entry"));
+ g_return_if_fail (GTK_IS_ENTRY (entry));
+
+ /* A non-encrypted password: just send the value back */
+ if (!g_key_file_has_group (input_data, "transport")) {
+ g_key_file_set_boolean (output_data, password_type, "encrypted", FALSE);
+ g_key_file_set_value (output_data, password_type, "value",
+ gtk_entry_get_text (entry));
+ return;
+ }
+
+ g_key_file_set_boolean (output_data, password_type, "encrypted", TRUE);
+ if (!the_key && !negotiate_transport_crypto ()) {
+ g_warning ("couldn't negotiate transport crypto for password");
+ return;
+ }
+
+ gcry_create_nonce (iv, sizeof (iv));
+ data = gkd_prompt_util_encrypt_text (the_key, n_the_key, iv, sizeof (iv),
+ gtk_entry_get_text (entry), &n_data);
+ g_return_if_fail (data);
+
+ gkd_prompt_util_encode_hex (output_data, password_type, "iv", iv, sizeof (iv));
+ gkd_prompt_util_encode_hex (output_data, password_type, "value", data, n_data);
+
+ g_free (data);
+}
+
+static void
+gather_dialog (GtkBuilder *builder, GtkDialog *dialog)
+{
+ gather_password (builder, "password");
+}
+
static void
run_dialog (void)
{
GtkBuilder *builder;
GtkDialog *dialog;
+ gint res;
builder = gtk_builder_new ();
dialog = prepare_dialog (builder);
@@ -227,11 +317,13 @@ run_dialog (void)
for (;;) {
gtk_widget_show (GTK_WIDGET (dialog));
- switch (gtk_dialog_run (dialog)) {
+ res = gtk_dialog_run (dialog);
+ switch (res) {
case GTK_RESPONSE_OK:
- /* TODO: if (!validate_dialog (builder, dialog, response))
+ case GTK_RESPONSE_APPLY:
+ /* if (!validate_dialog (builder, dialog, res))
continue; */
- /* TODO: output */
+ gather_dialog (builder, dialog);
break;
case GTK_RESPONSE_CANCEL:
case GTK_RESPONSE_DELETE_EVENT:
@@ -477,6 +569,14 @@ main (int argc, char *argv[])
run_dialog ();
+ /* Cleanup after any key */
+ if (the_key) {
+ egg_secure_clear (the_key, n_the_key);
+ egg_secure_free (the_key);
+ the_key = NULL;
+ n_the_key = 0;
+ }
+
g_key_file_free (input_data);
data = g_key_file_to_data (output_data, &length, &err);
g_key_file_free (output_data);
diff --git a/daemon/prompt/gkd-prompt-util.c b/daemon/prompt/gkd-prompt-util.c
new file mode 100644
index 0000000..151940a
--- /dev/null
+++ b/daemon/prompt/gkd-prompt-util.c
@@ -0,0 +1,248 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkd-prompt-tool.c - Handles gui authentication for the keyring daemon.
+
+ Copyright (C) 2009 Stefan Walter
+
+ Gnome keyring is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ Gnome keyring 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gkd-prompt-util.h"
+
+#include "egg/egg-dh.h"
+#include "egg/egg-hex.h"
+#include "egg/egg-secure-memory.h"
+
+void
+gkd_prompt_util_encode_mpi (GKeyFile *key_file, const gchar *section,
+ const gchar *field, gcry_mpi_t mpi)
+{
+ gcry_error_t gcry;
+ guchar *data;
+ gsize n_data;
+
+ g_return_if_fail (key_file);
+ g_return_if_fail (section);
+ g_return_if_fail (field);
+ g_return_if_fail (mpi);
+
+ /* Get the size */
+ gcry = gcry_mpi_print (GCRYMPI_FMT_HEX, NULL, 0, &n_data, mpi);
+ g_return_if_fail (gcry == 0);
+
+ data = g_malloc0 (n_data + 1);
+
+ /* Write into buffer */
+ gcry = gcry_mpi_print (GCRYMPI_FMT_HEX, data, n_data, &n_data, mpi);
+ g_return_if_fail (gcry == 0);
+
+ g_key_file_set_value (key_file, section, field, (gchar*)data);
+ g_free (data);
+}
+
+void
+gkd_prompt_util_encode_hex (GKeyFile *key_file, const gchar *section,
+ const gchar *field, gconstpointer data, gsize n_data)
+{
+ gchar *value;
+
+ g_return_if_fail (key_file);
+ g_return_if_fail (section);
+ g_return_if_fail (field);
+
+ value = egg_hex_encode (data, n_data);
+ g_key_file_set_value (key_file, section, field, value);
+ g_free (value);
+}
+
+gpointer
+gkd_prompt_util_decode_hex (GKeyFile *key_file, const gchar *section,
+ const gchar *field, gsize *n_result)
+{
+ gpointer result = NULL;
+ gchar *data;
+
+ g_return_val_if_fail (key_file, NULL);
+ g_return_val_if_fail (section, NULL);
+ g_return_val_if_fail (field, NULL);
+ g_return_val_if_fail (n_result, NULL);
+
+ data = g_key_file_get_value (key_file, section, field, NULL);
+ if (data != NULL)
+ result = egg_hex_decode (data, -1, n_result);
+ g_free (data);
+ return result;
+}
+
+gboolean
+gkd_prompt_util_decode_mpi (GKeyFile *key_file, const gchar *section,
+ const gchar *field, gcry_mpi_t *mpi)
+{
+ gcry_error_t gcry;
+ gchar *data;
+
+ g_return_val_if_fail (key_file, FALSE);
+ g_return_val_if_fail (section, FALSE);
+ g_return_val_if_fail (field, FALSE);
+ g_return_val_if_fail (mpi, FALSE);
+
+ data = g_key_file_get_value (key_file, section, field, NULL);
+ if (data == NULL)
+ return FALSE;
+
+ gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_HEX, data, 0, NULL);
+ g_free (data);
+
+ return (gcry == 0);
+}
+
+gboolean
+gkd_prompt_util_mpi_to_key (gcry_mpi_t mpi, gpointer *key, gsize *n_key)
+{
+ gcry_error_t gcry;
+ guchar *buffer;
+ gsize n_buffer;
+
+ g_return_val_if_fail (mpi, FALSE);
+ g_return_val_if_fail (key, FALSE);
+ g_return_val_if_fail (n_key, FALSE);
+
+ /* Write the key out to raw data */
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_buffer, mpi);
+ g_return_val_if_fail (gcry == 0, FALSE);
+ buffer = egg_secure_alloc (n_buffer);
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, n_buffer, &n_buffer, mpi);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ /* Allocate memory for hashed key */
+ g_assert (16 == gcry_md_get_algo_dlen (GCRY_MD_MD5));
+ *key = egg_secure_alloc (16);
+ *n_key = 16;
+
+ /* Use that as the input to derive a key for 128-bit AES */
+ gcry_md_hash_buffer (GCRY_MD_MD5, *key, buffer, n_buffer);
+
+ egg_secure_free (buffer);
+ return TRUE;
+}
+
+gpointer
+gkd_prompt_util_encrypt_text (gpointer key, gsize n_key, gpointer iv, gsize n_iv,
+ const gchar *text, gsize *n_result)
+{
+ gcry_cipher_hd_t cih;
+ gcry_error_t gcry;
+ guchar* padded;
+ guchar* result;
+ gsize n_text;
+ gsize pos;
+
+ g_return_val_if_fail (key, NULL);
+ g_return_val_if_fail (n_key == 16, NULL);
+ g_return_val_if_fail (iv, NULL);
+ g_return_val_if_fail (n_iv == 16, NULL);
+
+ gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
+ if (gcry) {
+ g_warning ("couldn't create aes cipher context: %s", gcry_strerror (gcry));
+ return NULL;
+ }
+
+ /* 16 = 128 bits */
+ gcry = gcry_cipher_setkey (cih, key, 16);
+ g_return_val_if_fail (gcry == 0, NULL);
+
+ /* 16 = 128 bits */
+ gcry = gcry_cipher_setiv (cih, iv, 16);
+ g_return_val_if_fail (gcry == 0, NULL);
+
+ /* Allocate memory for the operation */
+ n_text = strlen (text) + 1;
+ *n_result = ((n_text + 15) / 16) * 16;
+ padded = egg_secure_alloc (*n_result);
+ result = g_malloc0 (*n_result);
+
+ /* Setup the padding */
+ memset (padded, 0, *n_result);
+ memcpy (padded, text, n_text);
+
+ for (pos = 0; pos < *n_result; pos += 16) {
+ gcry = gcry_cipher_encrypt (cih, result + pos, 16, padded + pos, 16);
+ g_return_val_if_fail (gcry == 0, NULL);
+ }
+
+ gcry_cipher_close (cih);
+
+ egg_secure_clear (padded, *n_result);
+ egg_secure_free (padded);
+ return result;
+}
+
+gchar*
+gkd_prompt_util_decrypt_text (gpointer key, gsize n_key, gpointer iv, gsize n_iv,
+ gpointer data, gsize n_data)
+{
+ gcry_cipher_hd_t cih;
+ gcry_error_t gcry;
+ gchar *result;
+ gsize pos;
+
+ g_return_val_if_fail (key, NULL);
+ g_return_val_if_fail (n_key == 16, NULL);
+
+ if (n_iv != 16) {
+ g_warning ("prompt response has iv of wrong length");
+ return NULL;
+ }
+
+ if (n_data % 16 != 0) {
+ g_warning ("prompt response encrypted password of wrong length");
+ return NULL;
+ }
+
+ gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
+ if (gcry) {
+ g_warning ("couldn't create aes cipher context: %s", gcry_strerror (gcry));
+ return NULL;
+ }
+
+ /* 16 = 128 bits */
+ gcry = gcry_cipher_setkey (cih, key, 16);
+ g_return_val_if_fail (gcry == 0, NULL);
+
+ /* 16 = 128 bits */
+ gcry = gcry_cipher_setiv (cih, iv, 16);
+ g_return_val_if_fail (gcry == 0, NULL);
+
+ /* Allocate memory for the result */
+ result = egg_secure_alloc (n_data);
+
+ for (pos = 0; pos < n_data; pos += 16) {
+ gcry = gcry_cipher_decrypt (cih, result + pos, 16, (guchar*)data + pos, 16);
+ g_return_val_if_fail (gcry == 0, NULL);
+ }
+
+ gcry_cipher_close (cih);
+
+ if (!g_utf8_validate (result, -1, NULL)) {
+ egg_secure_free (result);
+ return NULL;
+ }
+
+ return result;
+}
diff --git a/daemon/prompt/gkd-prompt-util.h b/daemon/prompt/gkd-prompt-util.h
new file mode 100644
index 0000000..50a8c28
--- /dev/null
+++ b/daemon/prompt/gkd-prompt-util.h
@@ -0,0 +1,49 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 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 __GKD_PROMPT_UTIL_H__
+#define __GKD_PROMPT_UTIL_H__
+
+#include <gcrypt.h>
+
+#include <glib.h>
+
+void gkd_prompt_util_encode_mpi (GKeyFile *key_file, const gchar *section,
+ const gchar *field, gcry_mpi_t mpi);
+
+void gkd_prompt_util_encode_hex (GKeyFile *key_file, const gchar *section,
+ const gchar *field, gconstpointer data, gsize n_data);
+
+gboolean gkd_prompt_util_decode_mpi (GKeyFile *key_file, const gchar *section,
+ const gchar *field, gcry_mpi_t *mpi);
+
+gpointer gkd_prompt_util_decode_hex (GKeyFile *key_file, const gchar *section,
+ const gchar *field, gsize *n_result);
+
+gpointer gkd_prompt_util_encrypt_text (gpointer key, gsize n_key, gpointer iv, gsize n_iv,
+ const gchar *text, gsize *n_result);
+
+gchar* gkd_prompt_util_decrypt_text (gpointer key, gsize n_key, gpointer iv, gsize n_iv,
+ gpointer data, gsize n_data);
+
+gboolean gkd_prompt_util_mpi_to_key (gcry_mpi_t mpi, gpointer *key, gsize *n_key);
+
+#endif /* __GKD_PROMPT_H__ */
diff --git a/daemon/prompt/gkd-prompt.c b/daemon/prompt/gkd-prompt.c
index 199fe51..1777e85 100644
--- a/daemon/prompt/gkd-prompt.c
+++ b/daemon/prompt/gkd-prompt.c
@@ -23,6 +23,7 @@
#include "gkd-prompt.h"
#include "gkd-prompt-marshal.h"
+#include "gkd-prompt-util.h"
#include "egg/egg-cleanup.h"
#include "egg/egg-dh.h"
@@ -52,7 +53,7 @@ struct _GkdPromptPrivate {
/* Transport crypto */
gcry_mpi_t secret;
gcry_mpi_t prime;
- guchar *key;
+ gpointer key;
gsize n_key;
/* Information about child */
@@ -234,32 +235,6 @@ on_child_exited (GPid pid, gint status, gpointer user_data)
g_spawn_close_pid (pid);
}
-static gboolean
-encode_input_mpi (GkdPrompt *self, const gchar *section,
- const gchar *field, gcry_mpi_t mpi)
-{
- gcry_error_t gcry;
- guchar *data;
- gsize n_data;
-
- g_assert (self->pv->input);
-
- /* Get the size */
- gcry = gcry_mpi_print (GCRYMPI_FMT_HEX, NULL, 0, &n_data, mpi);
- g_return_val_if_fail (gcry == 0, FALSE);
-
- data = g_malloc0 (n_data + 1);
-
- /* Write into buffer */
- gcry = gcry_mpi_print (GCRYMPI_FMT_HEX, data, n_data, &n_data, mpi);
- g_return_val_if_fail (gcry == 0, FALSE);
-
- g_key_file_set_value (self->pv->input, section, field, (gchar*)data);
- g_free (data);
-
- return TRUE;
-}
-
static void
prepare_transport_crypto (GkdPrompt *self)
{
@@ -274,64 +249,23 @@ prepare_transport_crypto (GkdPrompt *self)
g_return_if_reached ();
/* Send over the prime, base, and public bits */
- if (!encode_input_mpi (self, "transport", "prime", self->pv->prime) ||
- !encode_input_mpi (self, "transport", "base", base) ||
- !encode_input_mpi (self, "transport", "public", pub))
- g_return_if_reached ();
+ gkd_prompt_util_encode_mpi (self->pv->input, "transport", "prime", self->pv->prime);
+ gkd_prompt_util_encode_mpi (self->pv->input, "transport", "base", base);
+ gkd_prompt_util_encode_mpi (self->pv->input, "transport", "public", pub);
gcry_mpi_release (base);
gcry_mpi_release (pub);
}
static gboolean
-decode_output_mpi (GkdPrompt *self, const gchar *section,
- const gchar *field, gcry_mpi_t *mpi)
-{
- gcry_error_t gcry;
- gchar *data;
-
- g_assert (self->pv->output);
-
- data = g_key_file_get_value (self->pv->output, section, field, NULL);
- if (!data)
- return FALSE;
-
- gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_HEX, data, 0, NULL);
- g_free (data);
-
- return (gcry == 0);
-}
-
-static guchar*
-decode_output_hex (GkdPrompt *self, const gchar *section,
- const gchar *field, gsize *n_result)
-{
- guchar *result;
- gchar *data;
-
- g_assert (self->pv->output);
-
- data = g_key_file_get_value (self->pv->output, section, field, NULL);
- if (!data)
- return NULL;
-
- result = egg_hex_decode (data, -1, n_result);
- g_free (data);
- return result;
-}
-
-static gboolean
receive_transport_crypto (GkdPrompt *self)
{
gcry_mpi_t key, peer;
- gcry_error_t gcry;
- guchar *buffer;
- gsize n_buffer;
gboolean ret;
g_assert (self->pv->output);
- if (!decode_output_mpi (self, "transport", "public", &peer))
+ if (!gkd_prompt_util_decode_mpi (self->pv->output, "transport", "public", &peer))
return FALSE;
ret = egg_dh_gen_key (peer, self->pv->secret, self->pv->prime, &key);
@@ -339,81 +273,19 @@ receive_transport_crypto (GkdPrompt *self)
if (!ret)
return FALSE;
- /* Write the key out to raw data */
- gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_buffer, peer);
- g_return_val_if_fail (gcry == 0, FALSE);
- buffer = egg_secure_alloc (n_buffer);
- gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, n_buffer, &n_buffer, peer);
- g_return_val_if_fail (gcry == 0, FALSE);
-
- /* Allocate memory for hashed key */
egg_secure_free (self->pv->key);
- g_assert (16 == gcry_md_get_algo_dlen (GCRY_MD_MD5));
- self->pv->key = egg_secure_alloc (16);
- self->pv->n_key = 16;
-
- /* Use that as the input to derive a key for 128-bit AES */
- gcry_md_hash_buffer (GCRY_MD_MD5, self->pv->key, buffer, n_buffer);
-
- egg_secure_free (buffer);
- return TRUE;
-}
-
-static gchar*
-decrypt_transport_crypto (GkdPrompt *self, guchar *data, gsize n_data,
- guchar *iv, gsize n_iv)
-{
- gcry_cipher_hd_t cih;
- gcry_error_t gcry;
- gchar *result;
- gsize pos;
-
- g_assert (self->pv->key);
- g_assert (self->pv->n_key == 16);
-
- if (n_iv != 16) {
- g_warning ("prompt response has iv of wrong length");
- return NULL;
- }
-
- if (n_data % 16 != 0) {
- g_warning ("prompt response encrypted password of wrong length");
- return NULL;
- }
-
- gcry = gcry_cipher_open (&cih, GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC, 0);
- if (gcry) {
- g_warning ("couldn't create aes cipher context: %s", gcry_strerror (gcry));
- return NULL;
- }
-
- /* 16 = 128 bits */
- gcry = gcry_cipher_setkey (cih, self->pv->key, 16);
- g_return_val_if_fail (gcry == 0, NULL);
-
- /* 16 = 128 bits */
- gcry = gcry_cipher_setiv (cih, iv, 16);
- g_return_val_if_fail (gcry == 0, NULL);
-
- /* Allocate memory for the result */
- result = egg_secure_alloc (n_data);
-
- for (pos = 0; pos < n_data; pos += 16) {
- gcry = gcry_cipher_decrypt (cih, result + pos, 16, data + pos, 16);
- g_return_val_if_fail (gcry == 0, NULL);
- }
+ ret = gkd_prompt_util_mpi_to_key (key, &self->pv->key, &self->pv->n_key);
+ gcry_mpi_release (key);
- gcry_cipher_close (cih);
-
- if (!g_utf8_validate (result, n_data, NULL)) {
- egg_secure_free (result);
- return NULL;
+ if (!ret) {
+ self->pv->key = NULL;
+ self->pv->n_key = 0;
+ return FALSE;
}
- return result;
+ return TRUE;
}
-
static gboolean
prepare_input_data (GkdPrompt *self)
{
@@ -739,21 +611,21 @@ gkd_prompt_get_password (GkdPrompt *self, const gchar *password_type)
g_return_val_if_reached (NULL);
/* Parse out an IV */
- iv = decode_output_hex (self, password_type, "iv", &n_iv);
+ iv = gkd_prompt_util_decode_hex (self->pv->input, password_type, "iv", &n_iv);
if (iv == NULL) {
g_warning ("prompt response has encrypted password, but no iv set");
return NULL;
}
/* Parse out the password */
- data = decode_output_hex (self, password_type, "value", &n_data);
+ data = gkd_prompt_util_decode_hex (self->pv->input, password_type, "value", &n_data);
if (data == NULL) {
g_warning ("prompt response missing encrypted password value");
g_free (iv);
return NULL;
}
- result = decrypt_transport_crypto (self, data, n_data, iv, n_iv);
+ result = gkd_prompt_util_decrypt_text (self->pv->key, self->pv->n_key, iv, n_iv, data, n_data);
g_free (data);
g_free (iv);
diff --git a/daemon/prompt/tests/Makefile.am b/daemon/prompt/tests/Makefile.am
new file mode 100644
index 0000000..2717a64
--- /dev/null
+++ b/daemon/prompt/tests/Makefile.am
@@ -0,0 +1,14 @@
+# Test files should be listed in order they need to run
+UNIT_AUTO = \
+ unit-test-util.c
+
+UNIT_PROMPT =
+
+UNIT_LIBS = \
+ $(top_builddir)/daemon/prompt/libgkd-prompt.la \
+ $(top_builddir)/egg/libegg-prompt.la
+
+EXTRA_DIST = \
+ test-data
+
+include $(top_srcdir)/tests/gtest.make
diff --git a/daemon/prompt/test/test-data/prompt-empty b/daemon/prompt/tests/test-data/prompt-empty
similarity index 100%
rename from daemon/prompt/test/test-data/prompt-empty
rename to daemon/prompt/tests/test-data/prompt-empty
diff --git a/daemon/prompt/test/test-data/prompt-full b/daemon/prompt/tests/test-data/prompt-full
similarity index 100%
rename from daemon/prompt/test/test-data/prompt-full
rename to daemon/prompt/tests/test-data/prompt-full
diff --git a/daemon/prompt/test/test-data/prompt-test b/daemon/prompt/tests/test-data/prompt-test
similarity index 100%
rename from daemon/prompt/test/test-data/prompt-test
rename to daemon/prompt/tests/test-data/prompt-test
diff --git a/daemon/prompt/tests/unit-test-util.c b/daemon/prompt/tests/unit-test-util.c
new file mode 100644
index 0000000..d3c2bde
--- /dev/null
+++ b/daemon/prompt/tests/unit-test-util.c
@@ -0,0 +1,146 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-util.c: Test gkd-prompt-util.c
+
+ Copyright (C) 2009 Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "run-auto-test.h"
+
+#include "gkd-prompt-util.h"
+
+#include <egg/egg-dh.h>
+#include <egg/egg-libgcrypt.h>
+#include <egg/egg-secure-memory.h>
+
+#include <gcrypt.h>
+
+static GKeyFile *key_file = NULL;
+
+DEFINE_SETUP(prompt_util)
+{
+ egg_libgcrypt_initialize ();
+ key_file = g_key_file_new ();
+}
+
+DEFINE_TEARDOWN(prompt_util)
+{
+ g_key_file_free (key_file);
+ key_file = NULL;
+}
+
+DEFINE_TEST(encode_decode_mpi)
+{
+ gcry_mpi_t mpi, check;
+
+ mpi = gcry_mpi_new (512);
+ gcry_mpi_randomize (mpi, 512, GCRY_WEAK_RANDOM);
+
+ gkd_prompt_util_encode_mpi (key_file, "section", "field", mpi);
+ if (!gkd_prompt_util_decode_mpi (key_file, "section", "field", &check))
+ g_assert_not_reached ();
+
+ g_assert (gcry_mpi_cmp (mpi, check) == 0);
+ gcry_mpi_release (mpi);
+ gcry_mpi_release (check);
+}
+
+DEFINE_TEST(decode_nonexistant_mpi)
+{
+ gcry_mpi_t mpi;
+
+ if (gkd_prompt_util_decode_mpi (key_file, "nonexist", "nope", &mpi))
+ g_assert_not_reached ();
+}
+
+DEFINE_TEST(encode_decode_hex)
+{
+ gchar buffer[32];
+ gpointer check;
+ gsize n_check;
+
+ gcry_create_nonce (buffer, 32);
+ gkd_prompt_util_encode_hex (key_file, "section", "field", buffer, 32);
+ check = gkd_prompt_util_decode_hex (key_file, "section", "field", &n_check);
+ g_assert (check);
+ g_assert (n_check == 32);
+ g_assert (memcmp (buffer, check, 32) == 0);
+
+ g_free (check);
+}
+
+DEFINE_TEST(decode_nonexistant_hex)
+{
+ gsize n_data;
+
+ if (gkd_prompt_util_decode_hex (key_file, "nonexist", "nope", &n_data))
+ g_assert_not_reached ();
+}
+
+static void
+do_encrypt_decrypt_text (const gchar *text)
+{
+ gcry_mpi_t mpi;
+ gpointer key, enc;
+ gsize n_key, n_enc;
+ guchar iv[16];
+ gchar *check;
+
+ g_test_message ("prompt encrypt/decrypt text: %s", text);
+
+ /* Test making a key */
+ mpi = gcry_mpi_new (512);
+ gcry_mpi_randomize (mpi, 512, GCRY_WEAK_RANDOM);
+
+ if (!gkd_prompt_util_mpi_to_key (mpi, &key, &n_key))
+ g_assert_not_reached ();
+
+ gcry_create_nonce (iv, 16);
+ enc = gkd_prompt_util_encrypt_text (key, n_key, iv, 16, text, &n_enc);
+ egg_secure_clear (key, n_key);
+ egg_secure_free (key);
+
+ g_assert (enc);
+ /* Always greater due to null term */
+ g_assert (n_enc > strlen (text));
+ g_assert (n_enc % 16 == 0);
+
+ if (!gkd_prompt_util_mpi_to_key (mpi, &key, &n_key))
+ g_assert_not_reached ();
+
+ check = gkd_prompt_util_decrypt_text (key, n_key, iv, 16, enc, n_enc);
+ egg_secure_clear (key, n_key);
+ egg_secure_free (key);
+ g_free (enc);
+
+ g_assert (check);
+ g_assert (strlen (check) < n_enc);
+ g_assert_cmpstr (check, ==, text);
+
+ gcry_mpi_release (mpi);
+}
+
+DEFINE_TEST(encrypt_decrypt_text)
+{
+ do_encrypt_decrypt_text ("");
+ do_encrypt_decrypt_text ("blah");
+ do_encrypt_decrypt_text ("0123456789ABCDEF");
+ do_encrypt_decrypt_text ("0123456789ABCDE");
+ do_encrypt_decrypt_text ("0123456789ABCDEF 12345");
+}
diff --git a/egg/Makefile.am b/egg/Makefile.am
index 584df42..9fe621c 100644
--- a/egg/Makefile.am
+++ b/egg/Makefile.am
@@ -5,6 +5,7 @@ noinst_LTLIBRARIES = \
libegg-creds.la \
libegg-dbus.la \
libegg-secure.la \
+ libegg-prompt.la \
libegg-secure-entry.la
BUILT_SOURCES = \
@@ -67,7 +68,7 @@ libegg_creds_la_SOURCES = \
egg-unix-credentials.c egg-unix-credentials.h
libegg_dbus_la_SOURCES = \
- egg-dbus.c egg-dbus.h
+ egg-dbus.c egg-dbus.h
libegg_dbus_la_CFLAGS = \
$(DBUS_CFLAGS) \
@@ -76,7 +77,22 @@ libegg_dbus_la_CFLAGS = \
libegg_dbus_la_LIBADD = \
$(DBUS_LIBS) \
$(GLIB_LIBS)
-
+
+libegg_prompt_la_SOURCES = \
+ egg-dh.c egg-dh.h \
+ egg-hex.c egg-hex.h \
+ egg-libgcrypt.c egg-libgcrypt.h \
+ egg-secure-memory.c egg-secure-memory.h
+
+libegg_prompt_la_CFLAGS = \
+ -DEGG_DH_NO_ASN1=1 \
+ $(LIBGCRYPT_CFLAGS) \
+ $(GLIB_CFLAGS)
+
+libegg_prompt_la_LIBS = \
+ $(LIBGCRYPT_LIBS) \
+ $(GLIB_LIBS)
+
# -------------------------------------------------------------------
if WITH_TESTS
diff --git a/egg/egg-dh.c b/egg/egg-dh.c
index ba917b4..ccb2243 100644
--- a/egg/egg-dh.c
+++ b/egg/egg-dh.c
@@ -107,6 +107,8 @@ typedef struct _Parameters {
gcry_mpi_t g;
} Parameters;
+#ifndef EGG_DH_NO_ASN1
+
static gboolean
parse_der_pkcs3 (const guchar *data, gsize n_data, Parameters *params)
{
@@ -165,3 +167,5 @@ egg_dh_parse_pkcs3 (const guchar *data, gsize n_data, gcry_mpi_t *p, gcry_mpi_t
*g = params.g;
return TRUE;
}
+
+#endif /* EGG_DH_NO_ASN1 */
diff --git a/egg/egg-dh.h b/egg/egg-dh.h
index fd09bbc..eb7959d 100644
--- a/egg/egg-dh.h
+++ b/egg/egg-dh.h
@@ -32,6 +32,8 @@ gboolean egg_dh_gen_secret (gcry_mpi_t p, gcry_mpi_t g, gcry_mpi_t *X, g
gboolean egg_dh_gen_key (gcry_mpi_t Y, gcry_mpi_t x, gcry_mpi_t p, gcry_mpi_t *k);
+#ifndef EGG_DH_NO_ASN1
gboolean egg_dh_parse_pkcs3 (const guchar *data, gsize n_data, gcry_mpi_t *p, gcry_mpi_t *g);
+#endif
#endif /* EGG_DH_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]