[gnome-keyring/dbus-api] [pkcs11] Implement DH key pair generation.



commit ad805c86202fd561fe6e9ae79ba8bf53c0471bf3
Author: Stef Walter <stef memberwebs com>
Date:   Mon Nov 16 20:59:16 2009 +0000

    [pkcs11] Implement DH key pair generation.
    
    Also rework how the DH stuff works in the egg component.

 daemon/prompt/gkd-prompt-tool.c |    4 +-
 daemon/prompt/gkd-prompt.c      |    4 +-
 egg/egg-dh.c                    |   32 ++++--
 egg/egg-dh.h                    |    4 +-
 egg/tests/unit-test-dh.c        |   30 +++++-
 pkcs11/gck/Makefile.am          |    4 +
 pkcs11/gck/gck-crypto.c         |   21 ++++
 pkcs11/gck/gck-crypto.h         |    9 ++
 pkcs11/gck/gck-dh-key.c         |  148 ++++++++++++++++++++++++++++
 pkcs11/gck/gck-dh-key.h         |   57 +++++++++++
 pkcs11/gck/gck-dh-mechanism.c   |  113 +++++++++++++++++++++
 pkcs11/gck/gck-dh-mechanism.h   |   45 +++++++++
 pkcs11/gck/gck-dh-private-key.c |  207 +++++++++++++++++++++++++++++++++++++++
 pkcs11/gck/gck-dh-private-key.h |   57 +++++++++++
 pkcs11/gck/gck-dh-public-key.c  |  186 +++++++++++++++++++++++++++++++++++
 pkcs11/gck/gck-dh-public-key.h  |   57 +++++++++++
 pkcs11/gck/gck-module.c         |   22 ++++-
 pkcs11/gck/gck-session.c        |  150 ++++++++++++++++++++---------
 pkcs11/gck/gck-types.h          |    3 +
 19 files changed, 1084 insertions(+), 69 deletions(-)
---
diff --git a/daemon/prompt/gkd-prompt-tool.c b/daemon/prompt/gkd-prompt-tool.c
index 26bc2f1..efd078d 100644
--- a/daemon/prompt/gkd-prompt-tool.c
+++ b/daemon/prompt/gkd-prompt-tool.c
@@ -241,8 +241,8 @@ negotiate_transport_crypto (void)
 	    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)) {
+		if (egg_dh_gen_pair (prime, base, 0, &pub, &secret) &&
+		    egg_dh_gen_secret (peer, secret, prime, &key)) {
 
 			/* Build up a key we can use */
 			gkd_prompt_util_encode_mpi (output_data, "transport", "public", pub);
diff --git a/daemon/prompt/gkd-prompt.c b/daemon/prompt/gkd-prompt.c
index 8f735e7..c25fd54 100644
--- a/daemon/prompt/gkd-prompt.c
+++ b/daemon/prompt/gkd-prompt.c
@@ -286,7 +286,7 @@ prepare_transport_crypto (GkdPrompt *self)
 
 	/* Figure out our prime, base, public and secret bits */
 	if (!egg_dh_default_params ("ietf-ike-grp-modp-1536", &self->pv->prime, &base) ||
-	    !egg_dh_gen_secret (self->pv->prime, base, &pub, &self->pv->secret))
+	    !egg_dh_gen_pair (self->pv->prime, base, 0, &pub, &self->pv->secret))
 		g_return_if_reached ();
 
 	/* Send over the prime, base, and public bits */
@@ -309,7 +309,7 @@ receive_transport_crypto (GkdPrompt *self)
 	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);
+	ret = egg_dh_gen_secret (peer, self->pv->secret, self->pv->prime, &key);
 	gcry_mpi_release (peer);
 	if (!ret)
 		return FALSE;
diff --git a/egg/egg-dh.c b/egg/egg-dh.c
index e68cb7b..ea1b4b6 100644
--- a/egg/egg-dh.c
+++ b/egg/egg-dh.c
@@ -206,19 +206,24 @@ egg_dh_default_params (const gchar *name, gcry_mpi_t *prime, gcry_mpi_t *base)
 }
 
 gboolean
-egg_dh_gen_secret (gcry_mpi_t p, gcry_mpi_t g,
-                   gcry_mpi_t *X, gcry_mpi_t *x)
+egg_dh_gen_pair (gcry_mpi_t p, gcry_mpi_t g, guint bits,
+                 gcry_mpi_t *X, gcry_mpi_t *x)
 {
-	gint bits;
+	guint pbits;
 
 	g_return_val_if_fail (g, FALSE);
 	g_return_val_if_fail (p, FALSE);
 	g_return_val_if_fail (X, FALSE);
 	g_return_val_if_fail (x, FALSE);
 
-	/* Secret key value must be less than half of p */
-	bits = gcry_mpi_get_nbits (p) - 1;
-	g_return_val_if_fail (bits >= 0, FALSE);
+	pbits = gcry_mpi_get_nbits (p);
+	g_return_val_if_fail (pbits > 1, FALSE);
+
+	if (bits == 0) {
+		bits = pbits;
+	} else if (bits > pbits) {
+		g_return_val_if_reached (FALSE);
+	}
 
 	/*
 	 * Generate a strong random number of bits, and not zero.
@@ -229,9 +234,16 @@ egg_dh_gen_secret (gcry_mpi_t p, gcry_mpi_t g,
 	*x = gcry_mpi_snew (bits);
 	g_return_val_if_fail (*x, FALSE);
 	while (gcry_mpi_cmp_ui (*x, 0) == 0)
-		gcry_mpi_randomize (*x, (bits / 8) * 8, GCRY_STRONG_RANDOM);
+		gcry_mpi_randomize (*x, bits, GCRY_STRONG_RANDOM);
+
+	/* Secret key value must be less than half of p */
+	if (gcry_mpi_get_nbits (*x) > bits)
+		gcry_mpi_clear_highbit (*x, bits);
+	if (gcry_mpi_get_nbits (*x) > pbits - 1)
+		gcry_mpi_clear_highbit (*x, pbits - 1);
+	g_assert (gcry_mpi_cmp (p, *x) > 0);
 
-	*X = gcry_mpi_new (bits);
+	*X = gcry_mpi_new (gcry_mpi_get_nbits (*x));
 	g_return_val_if_fail (*X, FALSE);
 	gcry_mpi_powm (*X, g, *x, p);
 
@@ -239,8 +251,8 @@ egg_dh_gen_secret (gcry_mpi_t p, gcry_mpi_t g,
 }
 
 gboolean
-egg_dh_gen_key (gcry_mpi_t Y, gcry_mpi_t x,
-                gcry_mpi_t p, gcry_mpi_t *k)
+egg_dh_gen_secret (gcry_mpi_t Y, gcry_mpi_t x,
+                   gcry_mpi_t p, gcry_mpi_t *k)
 {
 	gint bits;
 
diff --git a/egg/egg-dh.h b/egg/egg-dh.h
index bee18c1..83ffd0b 100644
--- a/egg/egg-dh.h
+++ b/egg/egg-dh.h
@@ -28,9 +28,9 @@
 
 gboolean   egg_dh_default_params   (const gchar *name, gcry_mpi_t *prime, gcry_mpi_t *base);
 
-gboolean   egg_dh_gen_secret       (gcry_mpi_t p, gcry_mpi_t g, gcry_mpi_t *X, gcry_mpi_t *x);
+gboolean   egg_dh_gen_pair         (gcry_mpi_t p, gcry_mpi_t g, guint bits, gcry_mpi_t *X, gcry_mpi_t *x);
 
-gboolean   egg_dh_gen_key          (gcry_mpi_t Y, gcry_mpi_t x, gcry_mpi_t p, gcry_mpi_t *k);
+gboolean   egg_dh_gen_secret       (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);
diff --git a/egg/tests/unit-test-dh.c b/egg/tests/unit-test-dh.c
index 17b11f3..e96613b 100644
--- a/egg/tests/unit-test-dh.c
+++ b/egg/tests/unit-test-dh.c
@@ -73,15 +73,15 @@ DEFINE_TEST(dh_perform)
 	g_free (data);
 
 	/* Generate secrets */
-	ret = egg_dh_gen_secret (p, g, &X1, &x1);
+	ret = egg_dh_gen_pair (p, g, 0, &X1, &x1);
 	g_assert (ret);
-	ret = egg_dh_gen_secret (p, g, &X2, &x2);
+	ret = egg_dh_gen_pair (p, g, 0, &X2, &x2);
 	g_assert (ret);
 
 	/* Calculate keys */
-	ret = egg_dh_gen_key (X2, x1, p, &k1);
+	ret = egg_dh_gen_secret (X2, x1, p, &k1);
 	g_assert (ret);
-	ret = egg_dh_gen_key (X1, x2, p, &k2);
+	ret = egg_dh_gen_secret (X1, x2, p, &k2);
 	g_assert (ret);
 
 	/* Keys must be the same */
@@ -97,6 +97,28 @@ DEFINE_TEST(dh_perform)
 	gcry_mpi_release (k2);
 }
 
+DEFINE_TEST(dh_short_pair)
+{
+	gcry_mpi_t p, g;
+	gcry_mpi_t x1, X1;
+	gboolean ret;
+
+	/* Load up the parameters */
+	ret = egg_dh_default_params ("ietf-ike-grp-modp-1024", &p, &g);
+	g_assert (ret);
+	g_assert_cmpuint (gcry_mpi_get_nbits (p), ==, 1024);
+	
+	/* Generate secrets */
+	ret = egg_dh_gen_pair (p, g, 512, &X1, &x1);
+	g_assert (ret);
+	g_assert_cmpuint (gcry_mpi_get_nbits (x1), <=, 512);
+
+	gcry_mpi_release (p);
+	gcry_mpi_release (g);
+	gcry_mpi_release (x1);
+	gcry_mpi_release (X1);
+}
+
 static void
 test_dh_default (const gchar *name, guint bits)
 {
diff --git a/pkcs11/gck/Makefile.am b/pkcs11/gck/Makefile.am
index 0833682..8a82d67 100644
--- a/pkcs11/gck/Makefile.am
+++ b/pkcs11/gck/Makefile.am
@@ -27,6 +27,10 @@ libgck_la_SOURCES = \
 	gck-data-der.c gck-data-der.h \
 	gck-data-file.c gck-data-file.h \
 	gck-data-types.h \
+	gck-dh-key.c gdk-dh-key.h \
+	gck-dh-mechanism.c gck-dh-mechanism.h \
+	gck-dh-private-key.c gck-dh-private-key.h \
+	gck-dh-public-key.c gck-dh-public-key.h \
 	gck-factory.c gck-factory.h \
 	gck-file-tracker.c gck-file-tracker.h \
 	gck-manager.c gck-manager.h \
diff --git a/pkcs11/gck/gck-crypto.c b/pkcs11/gck/gck-crypto.c
index d2a1429..f85a918 100644
--- a/pkcs11/gck/gck-crypto.c
+++ b/pkcs11/gck/gck-crypto.c
@@ -22,6 +22,7 @@
 #include "config.h"
 
 #include "gck-crypto.h"
+#include "gck-dh-mechanism.h"
 #include "gck-mechanism-dsa.h"
 #include "gck-mechanism-rsa.h"
 #include "gck-session.h"
@@ -383,6 +384,26 @@ gck_crypto_perform (GckSession *session, CK_MECHANISM_TYPE mech, CK_ATTRIBUTE_TY
 	}
 }
 
+CK_RV
+gck_crypto_generate_key_pair (GckSession *session, CK_MECHANISM_TYPE mech,
+                              CK_ATTRIBUTE_PTR pub_atts, CK_ULONG n_pub_atts,
+                              CK_ATTRIBUTE_PTR priv_atts, CK_ULONG n_priv_atts,
+                              GckObject **pub_key, GckObject **priv_key)
+{
+	g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (pub_key, CKR_GENERAL_ERROR);
+	g_return_val_if_fail (priv_key, CKR_GENERAL_ERROR);
+
+	switch (mech) {
+	case CKM_DH_PKCS_KEY_PAIR_GEN:
+		return gck_dh_mechanism_generate (session, pub_atts, n_pub_atts,
+		                                  priv_atts, n_priv_atts,
+		                                  pub_key, priv_key);
+	default:
+		return CKR_MECHANISM_INVALID;
+	}
+}
+
 /* ----------------------------------------------------------------------------
  * PREPARE FUNCTIONS
  */
diff --git a/pkcs11/gck/gck-crypto.h b/pkcs11/gck/gck-crypto.h
index 1b2598a..2b8ef2e 100644
--- a/pkcs11/gck/gck-crypto.h
+++ b/pkcs11/gck/gck-crypto.h
@@ -122,4 +122,13 @@ CK_RV                    gck_crypto_data_to_sexp                       (const gc
                                                                         CK_ULONG n_data,
                                                                         gcry_sexp_t *sexp);
 
+CK_RV                    gck_crypto_generate_key_pair                  (GckSession *session,
+                                                                        CK_MECHANISM_TYPE mech,
+                                                                        CK_ATTRIBUTE_PTR pub_atts,
+                                                                        CK_ULONG n_pub_atts,
+                                                                        CK_ATTRIBUTE_PTR priv_atts,
+                                                                        CK_ULONG n_priv_atts,
+                                                                        GckObject **pub_key,
+                                                                        GckObject **priv_key);
+
 #endif /* GCKCRYPTO_H_ */
diff --git a/pkcs11/gck/gck-dh-key.c b/pkcs11/gck/gck-dh-key.c
new file mode 100644
index 0000000..2c0ef64
--- /dev/null
+++ b/pkcs11/gck/gck-dh-key.c
@@ -0,0 +1,148 @@
+/*
+ * 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 "pkcs11/pkcs11.h"
+
+#include "gck-attributes.h"
+#include "gck-crypto.h"
+#include "gck-dh-key.h"
+#include "gck-dh-mechanism.h"
+#include "gck-session.h"
+#include "gck-util.h"
+
+struct _GckDhKeyPrivate {
+	gcry_mpi_t prime;
+	gcry_mpi_t base;
+	gpointer id;
+	gsize n_id;
+};
+
+G_DEFINE_TYPE (GckDhKey, gck_dh_key, GCK_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC_DH_KEY
+ */
+
+static CK_RV
+gck_dh_key_real_get_attribute (GckObject *base, GckSession *session, CK_ATTRIBUTE* attr)
+{
+	GckDhKey *self = GCK_DH_KEY (base);
+
+	switch (attr->type)
+	{
+
+	case CKA_KEY_TYPE:
+		return gck_attribute_set_ulong (attr, CKK_DH);
+
+	case CKA_START_DATE:
+	case CKA_END_DATE:
+		return gck_attribute_set_empty (attr);
+
+	case CKA_LOCAL:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_KEY_GEN_MECHANISM:
+		return gck_attribute_set_ulong (attr, CK_UNAVAILABLE_INFORMATION);
+
+	case CKA_ALLOWED_MECHANISMS:
+		return gck_attribute_set_data (attr, (CK_VOID_PTR)GCK_DH_MECHANISMS,
+		                               sizeof (GCK_DH_MECHANISMS));
+
+	case CKA_ID:
+		return gck_attribute_set_data (attr, self->pv->id, self->pv->n_id);
+
+	case CKA_SUBJECT:
+		return gck_attribute_set_empty (attr);
+
+	case CKA_PRIME:
+		return gck_attribute_set_mpi (attr, self->pv->prime);
+
+	case CKA_BASE:
+		return gck_attribute_set_mpi (attr, self->pv->base);
+	};
+
+	return GCK_OBJECT_CLASS (gck_dh_key_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gck_dh_key_init (GckDhKey *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_DH_KEY, GckDhKeyPrivate);
+}
+
+static void
+gck_dh_key_finalize (GObject *obj)
+{
+	GckDhKey *self = GCK_DH_KEY (obj);
+
+	gcry_mpi_release (self->pv->prime);
+	self->pv->prime = NULL;
+
+	gcry_mpi_release (self->pv->base);
+	self->pv->base = NULL;
+
+	g_free (self->pv->id);
+	self->pv->id = NULL;
+	self->pv->n_id = 0;
+
+	G_OBJECT_CLASS (gck_dh_key_parent_class)->finalize (obj);
+}
+
+static void
+gck_dh_key_class_init (GckDhKeyClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+
+	gck_dh_key_parent_class = g_type_class_peek_parent (klass);
+
+	gobject_class->finalize = gck_dh_key_finalize;
+
+	gck_class->get_attribute = gck_dh_key_real_get_attribute;
+
+	g_type_class_add_private (klass, sizeof (GckDhKeyPrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+void
+gck_dh_key_initialize (GckDhKey *self, gcry_mpi_t prime, gcry_mpi_t base,
+                       gpointer id, gsize n_id)
+{
+	g_return_if_fail (GCK_IS_DH_KEY (self));
+	g_return_if_fail (base);
+	g_return_if_fail (prime);
+	g_return_if_fail (!self->pv->base);
+	g_return_if_fail (!self->pv->prime);
+
+	self->pv->base = base;
+	self->pv->prime = prime;
+	self->pv->id = id;
+	self->pv->n_id = n_id;
+}
diff --git a/pkcs11/gck/gck-dh-key.h b/pkcs11/gck/gck-dh-key.h
new file mode 100644
index 0000000..bb7e68c
--- /dev/null
+++ b/pkcs11/gck/gck-dh-key.h
@@ -0,0 +1,57 @@
+/*
+ * 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 __GCK_DH_KEY_H__
+#define __GCK_DH_KEY_H__
+
+#include <glib-object.h>
+
+#include "gck-object.h"
+#include "gck-types.h"
+
+#define GCK_TYPE_DH_KEY               (gck_dh_key_get_type ())
+#define GCK_DH_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_DH_KEY, GckDhKey))
+#define GCK_DH_KEY_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_DH_KEY, GckDhKeyClass))
+#define GCK_IS_DH_KEY(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_DH_KEY))
+#define GCK_IS_DH_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_DH_KEY))
+#define GCK_DH_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_DH_KEY, GckDhKeyClass))
+
+typedef struct _GckDhKeyClass GckDhKeyClass;
+typedef struct _GckDhKeyPrivate GckDhKeyPrivate;
+
+struct _GckDhKey {
+	GckObject parent;
+	GckDhKeyPrivate *pv;
+};
+
+struct _GckDhKeyClass {
+	GckObjectClass parent_class;
+};
+
+GType                     gck_dh_key_get_type           (void);
+
+void                      gck_dh_key_initialize         (GckDhKey *self,
+                                                         gcry_mpi_t prime,
+                                                         gcry_mpi_t base,
+                                                         gpointer id,
+                                                         gsize n_id);
+
+#endif /* __GCK_DH_KEY_H__ */
diff --git a/pkcs11/gck/gck-dh-mechanism.c b/pkcs11/gck/gck-dh-mechanism.c
new file mode 100644
index 0000000..4f901dd
--- /dev/null
+++ b/pkcs11/gck/gck-dh-mechanism.c
@@ -0,0 +1,113 @@
+/*
+ * 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  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  License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * 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 "gck-attributes.h"
+#include "gck-dh-mechanism.h"
+#include "gck-dh-private-key.h"
+#include "gck-dh-public-key.h"
+#include "gck-session.h"
+
+#include "egg/egg-dh.h"
+#include "egg/egg-libgcrypt.h"
+#include "egg/egg-secure-memory.h"
+
+CK_RV
+gck_dh_mechanism_generate (GckSession *session, CK_ATTRIBUTE_PTR pub_atts,
+                           CK_ULONG n_pub_atts, CK_ATTRIBUTE_PTR priv_atts,
+                           CK_ULONG n_priv_atts, GckObject **pub_key,
+                           GckObject **priv_key)
+{
+	gcry_mpi_t prime = NULL;
+	gcry_mpi_t base = NULL;
+	gcry_mpi_t pub = NULL;
+	gcry_mpi_t priv = NULL;
+	gcry_error_t gcry;
+	guchar *buffer, *id;
+	gsize n_buffer, n_id;
+	GckManager *manager;
+	GckModule *module;
+	gulong bits;
+
+	g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (pub_key, CKR_GENERAL_ERROR);
+	g_return_val_if_fail (priv_key, CKR_GENERAL_ERROR);
+
+	if (!gck_attributes_find_mpi (pub_atts, n_pub_atts, CKA_PRIME, &prime) ||
+	    !gck_attributes_find_mpi (pub_atts, n_pub_atts, CKA_BASE, &base)) {
+		gcry_mpi_release (prime);
+		gcry_mpi_release (base);
+		return CKR_TEMPLATE_INCOMPLETE;
+	}
+
+	gck_attributes_consume (pub_atts, n_pub_atts, CKA_PRIME, CKA_BASE, G_MAXULONG);
+
+	if (!gck_attributes_find_ulong (priv_atts, n_priv_atts, CKA_VALUE_BITS, &bits))
+		bits = gcry_mpi_get_nbits (prime);
+
+	gck_attributes_consume (priv_atts, n_priv_atts, CKA_VALUE_BITS, G_MAXULONG);
+
+	/* The private key must be less than or equal to prime */
+	if (bits > gcry_mpi_get_nbits (prime)) {
+		gcry_mpi_release (prime);
+		gcry_mpi_release (base);
+		return CKR_TEMPLATE_INCONSISTENT;
+	}
+
+	if (!egg_dh_gen_pair (prime, base, bits, &priv, &pub)) {
+		gcry_mpi_release (prime);
+		gcry_mpi_release (base);
+		return CKR_FUNCTION_FAILED;
+	}
+
+	/* Write the public key out to raw data, so we can use it for an ID */
+	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &n_buffer, pub);
+	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+	buffer = g_malloc (n_buffer);
+	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buffer, n_buffer, &n_buffer, pub);
+	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+	if (n_buffer < 16) {
+		n_id = n_buffer;
+		id = g_memdup (buffer, n_id);
+	} else {
+		n_id = 16;
+		id = g_memdup (buffer + (n_buffer - 16), n_id);
+	}
+
+	manager = gck_manager_for_template (pub_atts, n_pub_atts, session);
+	module = gck_session_get_module (session);
+
+	*pub_key = GCK_OBJECT (gck_dh_public_key_new (module, manager, prime, base,
+	                                              pub, id, n_id));
+
+	id = g_memdup (id, n_id);
+	prime = gcry_mpi_copy (prime);
+	base = gcry_mpi_copy (base);
+
+	*priv_key = GCK_OBJECT (gck_dh_private_key_new (module, manager, prime, base,
+	                                                priv, id, n_id));
+
+	gck_attributes_consume (pub_atts, n_pub_atts, CKA_PRIME, CKA_BASE, G_MAXULONG);
+
+	g_free (buffer);
+	return CKR_OK;
+}
diff --git a/pkcs11/gck/gck-dh-mechanism.h b/pkcs11/gck/gck-dh-mechanism.h
new file mode 100644
index 0000000..38624b2
--- /dev/null
+++ b/pkcs11/gck/gck-dh-mechanism.h
@@ -0,0 +1,45 @@
+/*
+ * 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  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  License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * 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 GCK_DH_MECHANISM_H_
+#define GCK_DH_MECHANISM_H_
+
+#include "gck-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <glib.h>
+
+#include <gcrypt.h>
+
+static const CK_MECHANISM_TYPE GCK_DH_MECHANISMS[] = {
+	CKM_DH_PKCS_DERIVE
+};
+
+CK_RV                    gck_dh_mechanism_generate                     (GckSession *session,
+                                                                        CK_ATTRIBUTE_PTR pub_atts,
+                                                                        CK_ULONG n_pub_atts,
+                                                                        CK_ATTRIBUTE_PTR priv_atts,
+                                                                        CK_ULONG n_priv_atts,
+                                                                        GckObject **pub_key,
+                                                                        GckObject **priv_key);
+
+#endif /* GCK_DH_MECHANISM_H_ */
diff --git a/pkcs11/gck/gck-dh-private-key.c b/pkcs11/gck/gck-dh-private-key.c
new file mode 100644
index 0000000..ac894ae
--- /dev/null
+++ b/pkcs11/gck/gck-dh-private-key.c
@@ -0,0 +1,207 @@
+/*
+ * 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 Private 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 Private License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Private
+ * 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 "pkcs11/pkcs11.h"
+
+#include "gck-attributes.h"
+#include "gck-crypto.h"
+#include "gck-factory.h"
+#include "gck-dh-private-key.h"
+#include "gck-session.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+struct _GckDhPrivateKey {
+	GckDhKey parent;
+	gcry_mpi_t value;
+};
+
+G_DEFINE_TYPE (GckDhPrivateKey, gck_dh_private_key, GCK_TYPE_DH_KEY);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+factory_create_dh_private_key (GckSession *session, GckTransaction *transaction,
+                               CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+{
+	GckManager *manager;
+	gcry_mpi_t prime = NULL;
+	gcry_mpi_t base = NULL;
+	gcry_mpi_t value = NULL;
+	CK_ATTRIBUTE_PTR idattr;
+
+	if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &prime) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &base) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_VALUE, &value)) {
+		gcry_mpi_release (prime);
+		gcry_mpi_release (base);
+		gcry_mpi_release (value);
+		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+	}
+
+	manager = gck_manager_for_template (attrs, n_attrs, session);
+	idattr = gck_attributes_find (attrs, n_attrs, CKA_ID);
+
+	*object = GCK_OBJECT (gck_dh_private_key_new (gck_session_get_module (session),
+	                                             manager, prime, base, value,
+	                                             idattr ? g_memdup (idattr->pValue, idattr->ulValueLen) : NULL,
+	                                             idattr ? idattr->ulValueLen : 0));
+	gck_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_BASE, CKA_VALUE, G_MAXULONG);
+}
+
+/* -----------------------------------------------------------------------------
+ * DH_PRIVATE_KEY
+ */
+
+static CK_RV
+gck_dh_private_key_real_get_attribute (GckObject *base, GckSession *session, CK_ATTRIBUTE* attr)
+{
+	GckDhPrivateKey *self = GCK_DH_PRIVATE_KEY (base);
+
+	switch (attr->type)
+	{
+
+	case CKA_CLASS:
+		return gck_attribute_set_ulong (attr, CKO_PRIVATE_KEY);
+
+	case CKA_PRIVATE:
+		return gck_attribute_set_bool (attr, TRUE);
+
+	case CKA_SENSITIVE:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_DECRYPT:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_SIGN:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_SIGN_RECOVER:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_DERIVE:
+		return gck_attribute_set_bool (attr, TRUE);
+
+	case CKA_UNWRAP:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_EXTRACTABLE:
+		return gck_attribute_set_bool (attr, TRUE);
+
+	case CKA_ALWAYS_SENSITIVE:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_NEVER_EXTRACTABLE:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_WRAP_WITH_TRUSTED:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_UNWRAP_TEMPLATE:
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	case CKA_ALWAYS_AUTHENTICATE:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_VALUE:
+		return gck_attribute_set_mpi (attr, self->value);
+
+	case CKA_VALUE_BITS:
+		return gck_attribute_set_ulong (attr, gcry_mpi_get_nbits (self->value));
+	};
+
+	return GCK_OBJECT_CLASS (gck_dh_private_key_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gck_dh_private_key_init (GckDhPrivateKey *self)
+{
+
+}
+
+static void
+gck_dh_private_key_finalize (GObject *obj)
+{
+	GckDhPrivateKey *self = GCK_DH_PRIVATE_KEY (obj);
+
+	gcry_mpi_release (self->value);
+	self->value = NULL;
+
+	G_OBJECT_CLASS (gck_dh_private_key_parent_class)->finalize (obj);
+}
+
+static void
+gck_dh_private_key_class_init (GckDhPrivateKeyClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+
+	gck_dh_private_key_parent_class = g_type_class_peek_parent (klass);
+
+	gobject_class->finalize = gck_dh_private_key_finalize;
+
+	gck_class->get_attribute = gck_dh_private_key_real_get_attribute;
+}
+
+/* -----------------------------------------------------------------------------
+ * PRIVATE
+ */
+
+GckFactory*
+gck_dh_private_key_get_factory (void)
+{
+	static CK_OBJECT_CLASS klass = CKO_PRIVATE_KEY;
+	static CK_KEY_TYPE type = CKK_DH;
+
+	static CK_ATTRIBUTE attributes[] = {
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_KEY_TYPE, &type, sizeof (type) }
+	};
+
+	static GckFactory factory = {
+		attributes,
+		G_N_ELEMENTS (attributes),
+		factory_create_dh_private_key
+	};
+
+	return &factory;
+}
+
+GckDhPrivateKey*
+gck_dh_private_key_new (GckModule *module, GckManager *manager,
+                        gcry_mpi_t prime, gcry_mpi_t base, gcry_mpi_t value,
+                        gpointer id, gsize n_id)
+{
+	GckDhPrivateKey *key;
+
+	key = g_object_new (GCK_TYPE_DH_PRIVATE_KEY,
+	                    "manager", manager,
+	                    "module", module,
+	                    NULL);
+
+	gck_dh_key_initialize (GCK_DH_KEY (key), prime, base, id, n_id);
+	key->value = value;
+	return key;
+}
diff --git a/pkcs11/gck/gck-dh-private-key.h b/pkcs11/gck/gck-dh-private-key.h
new file mode 100644
index 0000000..88b0b64
--- /dev/null
+++ b/pkcs11/gck/gck-dh-private-key.h
@@ -0,0 +1,57 @@
+/*
+ * 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 Private 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 Private License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Private
+ * 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 __GCK_DH_PRIVATE_KEY_H__
+#define __GCK_DH_PRIVATE_KEY_H__
+
+#include <glib-object.h>
+
+#include "gck-dh-key.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_DH_PRIVATE_KEY            (gck_dh_private_key_get_factory ())
+
+#define GCK_TYPE_DH_PRIVATE_KEY               (gck_dh_private_key_get_type ())
+#define GCK_DH_PRIVATE_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_DH_PRIVATE_KEY, GckDhPrivateKey))
+#define GCK_DH_PRIVATE_KEY_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_DH_PRIVATE_KEY, GckDhPrivateKeyClass))
+#define GCK_IS_DH_PRIVATE_KEY(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_DH_PRIVATE_KEY))
+#define GCK_IS_DH_PRIVATE_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_DH_PRIVATE_KEY))
+#define GCK_DH_PRIVATE_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_DH_PRIVATE_KEY, GckDhPrivateKeyClass))
+
+typedef struct _GckDhPrivateKeyClass GckDhPrivateKeyClass;
+
+struct _GckDhPrivateKeyClass {
+	GckDhKeyClass parent_class;
+};
+
+GType                     gck_dh_private_key_get_type          (void);
+
+GckFactory*               gck_dh_private_key_get_factory       (void);
+
+GckDhPrivateKey*          gck_dh_private_key_new               (GckModule *module,
+                                                                GckManager *manager,
+                                                                gcry_mpi_t prime,
+                                                                gcry_mpi_t base,
+                                                                gcry_mpi_t value,
+                                                                gpointer id,
+                                                                gsize n_id);
+
+#endif /* __GCK_DH_PRIVATE_KEY_H__ */
diff --git a/pkcs11/gck/gck-dh-public-key.c b/pkcs11/gck/gck-dh-public-key.c
new file mode 100644
index 0000000..41f7c40
--- /dev/null
+++ b/pkcs11/gck/gck-dh-public-key.c
@@ -0,0 +1,186 @@
+/*
+ * 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 "pkcs11/pkcs11.h"
+
+#include "gck-attributes.h"
+#include "gck-crypto.h"
+#include "gck-factory.h"
+#include "gck-dh-public-key.h"
+#include "gck-session.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+struct _GckDhPublicKey {
+	GckDhKey parent;
+	gcry_mpi_t value;
+};
+
+G_DEFINE_TYPE (GckDhPublicKey, gck_dh_public_key, GCK_TYPE_DH_KEY);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+factory_create_dh_public_key (GckSession *session, GckTransaction *transaction,
+                              CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+{
+	GckManager *manager;
+	gcry_mpi_t prime = NULL;
+	gcry_mpi_t base = NULL;
+	gcry_mpi_t value = NULL;
+	CK_ATTRIBUTE_PTR idattr;
+
+	if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &prime) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &base) ||
+	    !gck_attributes_find_mpi (attrs, n_attrs, CKA_VALUE, &value)) {
+		gcry_mpi_release (prime);
+		gcry_mpi_release (base);
+		gcry_mpi_release (value);
+		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+	}
+
+	manager = gck_manager_for_template (attrs, n_attrs, session);
+	idattr = gck_attributes_find (attrs, n_attrs, CKA_ID);
+
+	*object = GCK_OBJECT (gck_dh_public_key_new (gck_session_get_module (session),
+	                                             manager, prime, base, value,
+	                                             idattr ? g_memdup (idattr->pValue, idattr->ulValueLen) : NULL,
+	                                             idattr ? idattr->ulValueLen : 0));
+	gck_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_BASE, CKA_VALUE, G_MAXULONG);
+}
+
+/* -----------------------------------------------------------------------------
+ * DH_PUBLIC_KEY
+ */
+
+static CK_RV
+gck_dh_public_key_real_get_attribute (GckObject *base, GckSession *session, CK_ATTRIBUTE* attr)
+{
+	GckDhPublicKey *self = GCK_DH_PUBLIC_KEY (base);
+
+	switch (attr->type)
+	{
+
+	case CKA_CLASS:
+		return gck_attribute_set_ulong (attr, CKO_PUBLIC_KEY);
+
+	case CKA_DERIVE:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_ENCRYPT:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_VERIFY:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_VERIFY_RECOVER:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_WRAP:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_TRUSTED:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_WRAP_TEMPLATE:
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	case CKA_VALUE:
+		return gck_attribute_set_mpi (attr, self->value);
+	};
+
+	return GCK_OBJECT_CLASS (gck_dh_public_key_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gck_dh_public_key_init (GckDhPublicKey *self)
+{
+
+}
+
+static void
+gck_dh_public_key_finalize (GObject *obj)
+{
+	GckDhPublicKey *self = GCK_DH_PUBLIC_KEY (obj);
+
+	gcry_mpi_release (self->value);
+	self->value = NULL;
+
+	G_OBJECT_CLASS (gck_dh_public_key_parent_class)->finalize (obj);
+}
+
+static void
+gck_dh_public_key_class_init (GckDhPublicKeyClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+
+	gck_dh_public_key_parent_class = g_type_class_peek_parent (klass);
+
+	gobject_class->finalize = gck_dh_public_key_finalize;
+
+	gck_class->get_attribute = gck_dh_public_key_real_get_attribute;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GckFactory*
+gck_dh_public_key_get_factory (void)
+{
+	static CK_OBJECT_CLASS klass = CKO_PUBLIC_KEY;
+	static CK_KEY_TYPE type = CKK_DH;
+
+	static CK_ATTRIBUTE attributes[] = {
+		{ CKA_CLASS, &klass, sizeof (klass) },
+		{ CKA_KEY_TYPE, &type, sizeof (type) }
+	};
+
+	static GckFactory factory = {
+		attributes,
+		G_N_ELEMENTS (attributes),
+		factory_create_dh_public_key
+	};
+
+	return &factory;
+}
+
+GckDhPublicKey*
+gck_dh_public_key_new (GckModule *module, GckManager *manager,
+                       gcry_mpi_t prime, gcry_mpi_t base, gcry_mpi_t value,
+                       gpointer id, gsize n_id)
+{
+	GckDhPublicKey *key;
+
+	key = g_object_new (GCK_TYPE_DH_PUBLIC_KEY,
+	                    "manager", manager,
+	                    "module", module,
+	                    NULL);
+
+	key->value = value;
+	gck_dh_key_initialize (GCK_DH_KEY (key), prime, base, id, n_id);
+	return key;
+}
diff --git a/pkcs11/gck/gck-dh-public-key.h b/pkcs11/gck/gck-dh-public-key.h
new file mode 100644
index 0000000..fd41136
--- /dev/null
+++ b/pkcs11/gck/gck-dh-public-key.h
@@ -0,0 +1,57 @@
+/*
+ * 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 __GCK_DH_PUBLIC_KEY_H__
+#define __GCK_DH_PUBLIC_KEY_H__
+
+#include <glib-object.h>
+
+#include "gck-dh-key.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_DH_PUBLIC_KEY            (gck_dh_public_key_get_factory ())
+
+#define GCK_TYPE_DH_PUBLIC_KEY               (gck_dh_public_key_get_type ())
+#define GCK_DH_PUBLIC_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_DH_PUBLIC_KEY, GckDhPublicKey))
+#define GCK_DH_PUBLIC_KEY_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_DH_PUBLIC_KEY, GckDhPublicKeyClass))
+#define GCK_IS_DH_PUBLIC_KEY(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_DH_PUBLIC_KEY))
+#define GCK_IS_DH_PUBLIC_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_DH_PUBLIC_KEY))
+#define GCK_DH_PUBLIC_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_DH_PUBLIC_KEY, GckDhPublicKeyClass))
+
+typedef struct _GckDhPublicKeyClass GckDhPublicKeyClass;
+
+struct _GckDhPublicKeyClass {
+	GckDhKeyClass parent_class;
+};
+
+GType                     gck_dh_public_key_get_type           (void);
+
+GckFactory*               gck_dh_public_key_get_factory        (void);
+
+GckDhPublicKey*           gck_dh_public_key_new                (GckModule *module,
+                                                                GckManager *manager,
+                                                                gcry_mpi_t prime,
+                                                                gcry_mpi_t base,
+                                                                gcry_mpi_t value,
+                                                                gpointer id,
+                                                                gsize n_id);
+
+#endif /* __GCK_DH_PUBLIC_KEY_H__ */
diff --git a/pkcs11/gck/gck-module.c b/pkcs11/gck/gck-module.c
index e23b8ce..160ad54 100644
--- a/pkcs11/gck/gck-module.c
+++ b/pkcs11/gck/gck-module.c
@@ -32,7 +32,9 @@
 #include "gck-manager.h"
 #include "gck-memory-store.h"
 #include "gck-module.h"
+#include "gck-dh-private-key.h"
 #include "gck-private-xsa-key.h"
+#include "gck-dh-public-key.h"
 #include "gck-public-xsa-key.h"
 #include "gck-session.h"
 #include "gck-store.h"
@@ -145,7 +147,19 @@ static const MechanismAndInfo mechanism_list[] = {
 	 * CKM_DSA
 	 * For DSA, min and max are the minimum and maximum modulus in bits
 	 */
-	{ CKM_DSA, { 512, 1024, CKF_SIGN | CKF_VERIFY } }
+	{ CKM_DSA, { 512, 1024, CKF_SIGN | CKF_VERIFY } },
+
+	/*
+	 * CKM_DH_PKCS_KEY_PAIR_GEN
+	 * For DH derivation the min and max are sizes of prime in bits.
+	 */
+	{ CKM_DH_PKCS_KEY_PAIR_GEN, { 768, 8192, CKF_GENERATE_KEY_PAIR } },
+
+	/*
+	 * CKM_DH_PKCS_DERIVE
+	 * For DH derivation the min and max are sizes of prime in bits.
+	 */
+	{ CKM_DH_PKCS_DERIVE, { 768, 8192, CKF_DERIVE } }
 };
 
 /* Hidden function that you should not use */
@@ -560,10 +574,12 @@ gck_module_init (GckModule *self)
 	self->pv->transient_objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gck_util_dispose_unref);
 
 	/* Register session object factories */
-	gck_module_register_factory (self, GCK_FACTORY_PRIVATE_XSA_KEY);
 	gck_module_register_factory (self, GCK_FACTORY_CERTIFICATE);
-	gck_module_register_factory (self, GCK_FACTORY_PUBLIC_XSA_KEY);
 	gck_module_register_factory (self, GCK_FACTORY_CREDENTIAL);
+	gck_module_register_factory (self, GCK_FACTORY_DH_PRIVATE_KEY);
+	gck_module_register_factory (self, GCK_FACTORY_PRIVATE_XSA_KEY);
+	gck_module_register_factory (self, GCK_FACTORY_DH_PUBLIC_KEY);
+	gck_module_register_factory (self, GCK_FACTORY_PUBLIC_XSA_KEY);
 }
 
 static void
diff --git a/pkcs11/gck/gck-session.c b/pkcs11/gck/gck-session.c
index 44c9175..dda5260 100644
--- a/pkcs11/gck/gck-session.c
+++ b/pkcs11/gck/gck-session.c
@@ -377,6 +377,52 @@ attributes_find_boolean (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
 	return FALSE;
 }
 
+static void
+finish_up_object_creation (GckSession *self, GckObject *object, GckTransaction *transaction,
+                           CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+	gboolean is_private;
+	gulong i;
+
+	g_assert (GCK_IS_SESSION (self));
+	g_assert (GCK_IS_OBJECT (object));
+	g_assert (GCK_IS_TRANSACTION (transaction));
+	g_assert (!gck_transaction_get_failed (transaction));
+
+	gck_object_create_attributes (object, self, transaction, attrs, n_attrs);
+	if (gck_transaction_get_failed (transaction))
+		return;
+
+	/* See if we can create due to read-only */
+	if (gck_object_is_token (object)) {
+		if (!gck_object_is_transient (object) &&
+		    gck_module_get_write_protected (self->pv->module))
+			return gck_transaction_fail (transaction, CKR_TOKEN_WRITE_PROTECTED);
+		else if (self->pv->read_only)
+			return gck_transaction_fail (transaction, CKR_SESSION_READ_ONLY);
+	}
+
+	/* Can only create public objects unless logged in */
+	if (gck_session_get_logged_in (self) != CKU_USER &&
+	    gck_object_get_attribute_boolean (object, self, CKA_PRIVATE, &is_private) && 
+	    is_private == TRUE) {
+		return gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
+	}
+
+	/* Find somewhere to store the object */
+	if (gck_object_is_token (object))
+		gck_module_store_token_object (self->pv->module, transaction, object); 
+	else
+		add_object (self, transaction, object);
+
+	/* Next go through and set all attributes that weren't used initially */
+	gck_attributes_consume (attrs, n_attrs, CKA_TOKEN, G_MAXULONG);
+	for (i = 0; i < n_attrs && !gck_transaction_get_failed (transaction); ++i) {
+		if (!gck_attribute_consumed (&attrs[i]))
+			gck_object_set_attribute (object, self, transaction, &attrs[i]);
+	}
+}
+
 /* -----------------------------------------------------------------------------
  * OBJECT 
  */
@@ -819,9 +865,6 @@ gck_session_create_object_for_factory (GckSession *self, GckFactory *factory,
                                        GckObject **object)
 {
 	GckTransaction *transaction;
-	CK_ATTRIBUTE_PTR attrs;
-	CK_ULONG n_attrs, i;
-	gboolean is_private;
 	CK_RV rv;
 
 	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_GENERAL_ERROR);
@@ -836,55 +879,19 @@ gck_session_create_object_for_factory (GckSession *self, GckFactory *factory,
 	 * Duplicate the memory for the attributes (but not values) so we
 	 * can 'consume' in the factory function
 	 */
-	attrs = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
-	n_attrs = count;
+	template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
 
 	/* Actually create the object */
 	*object = NULL;
-	(factory->func) (self, transaction, attrs, n_attrs, object);
+	(factory->func) (self, transaction, template, count, object);
 
-	/* Give the object a chance to create additional attributes */
+	/* Complete creation, and do storage */
 	if (!gck_transaction_get_failed (transaction)) {
 		g_return_val_if_fail (*object, CKR_GENERAL_ERROR);
-		gck_object_create_attributes (*object, self, transaction, attrs, n_attrs);
+		finish_up_object_creation (self, *object, transaction, template, count);
 	}
 
-	/* See if we can create due to read-only */
-	if (!gck_transaction_get_failed (transaction)) {
-		if (gck_object_is_token (*object)) {
-			if (!gck_object_is_transient (*object) &&
-			    gck_module_get_write_protected (self->pv->module))
-				gck_transaction_fail (transaction, CKR_TOKEN_WRITE_PROTECTED);
-			else if (self->pv->read_only)
-				gck_transaction_fail (transaction, CKR_SESSION_READ_ONLY);
-		}
-	}
-
-	/* Can only create public objects unless logged in */
-	if (!gck_transaction_get_failed (transaction)) {
-		if (gck_session_get_logged_in (self) != CKU_USER &&
-		    gck_object_get_attribute_boolean (*object, self, CKA_PRIVATE, &is_private) && 
-		    is_private == TRUE) {
-			gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
-		}
-	}
-
-	/* Find somewhere to store the object */
-	if (!gck_transaction_get_failed (transaction)) {
-		if (gck_object_is_token (*object))
-			gck_module_store_token_object (self->pv->module, transaction, *object); 
-		else
-			add_object (self, transaction, *object);
-	}
-
-	/* Next go through and set all attributes that weren't used initially */
-	gck_attributes_consume (attrs, n_attrs, CKA_TOKEN, G_MAXULONG);
-	for (i = 0; i < n_attrs && !gck_transaction_get_failed (transaction); ++i) {
-		if (!gck_attribute_consumed (&attrs[i]))
-			gck_object_set_attribute (*object, self, transaction, &attrs[i]);
-	}
-
-	g_free (attrs);
+	g_free (template);
 
 	gck_transaction_complete (transaction);
 	rv = gck_transaction_get_result (transaction);
@@ -1462,8 +1469,59 @@ gck_session_C_GenerateKeyPair (GckSession* self, CK_MECHANISM_PTR mechanism,
                                CK_ATTRIBUTE_PTR priv_template, CK_ULONG priv_count,
                                CK_OBJECT_HANDLE_PTR pub_key, CK_OBJECT_HANDLE_PTR priv_key)
 {
-	/* TODO: We need to implement this */
- 	return CKR_FUNCTION_NOT_SUPPORTED;
+	GckObject *pub = NULL;
+	GckObject *priv = NULL;
+	GckTransaction *transaction;
+	CK_RV rv;
+
+	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
+	if (!mechanism)
+		return CKR_ARGUMENTS_BAD;
+	if (!(!pub_count || pub_template))
+		return CKR_ARGUMENTS_BAD;
+	if (!(!priv_count || priv_template))
+		return CKR_ARGUMENTS_BAD;
+	if (!pub_key || !priv_key)
+		return CKR_ARGUMENTS_BAD;
+
+	/*
+	 * Duplicate the memory for the attributes (but not values) so we
+	 * can 'consume' in the generator and create object functions.
+	 */
+	pub_template = g_memdup (pub_template, pub_count * sizeof (CK_ATTRIBUTE));
+	priv_template = g_memdup (priv_template, priv_count * sizeof (CK_ATTRIBUTE));
+	transaction = gck_transaction_new ();
+
+	/* Actually do the object creation */
+	rv = gck_crypto_generate_key_pair (self, mechanism->mechanism, pub_template, pub_count,
+	                                   priv_template, priv_count, &pub, &priv);
+	if (rv != CKR_OK)
+		gck_transaction_fail (transaction, rv);
+
+	if (!gck_transaction_get_failed (transaction))
+		finish_up_object_creation (self, pub, transaction, pub_template, pub_count);
+	if (!gck_transaction_get_failed (transaction))
+		finish_up_object_creation (self, priv, transaction, priv_template, priv_count);
+
+	g_free (pub_template);
+	g_free (priv_template);
+
+	gck_transaction_complete (transaction);
+	rv = gck_transaction_get_result (transaction);
+	g_object_unref (transaction);
+
+	if (rv == CKR_OK) {
+		*pub_key = gck_object_get_handle (pub);
+		*priv_key = gck_object_get_handle (priv);
+	}
+
+	/* Objects are owned by storage */
+	if (pub != NULL)
+		g_object_unref (pub);
+	if (priv != NULL)
+		g_object_unref (priv);
+
+	return rv;
 }
 
 CK_RV
diff --git a/pkcs11/gck/gck-types.h b/pkcs11/gck/gck-types.h
index 5ad1c76..b7361e2 100644
--- a/pkcs11/gck/gck-types.h
+++ b/pkcs11/gck/gck-types.h
@@ -26,6 +26,9 @@ typedef struct _GckCertificate GckCertificate;
 typedef struct _GckCertificateKey GckCertificateKey;
 typedef struct _GckCertificateTrust GckCertificateTrust;
 typedef struct _GckCredential GckCredential;
+typedef struct _GckDhKey GckDhKey;
+typedef struct _GckDhPrivateKey GckDhPrivateKey;
+typedef struct _GckDhPublicKey GckDhPublicKey;
 typedef struct _GckFactory GckFactory;
 typedef struct _GckManager GckManager;
 typedef struct _GckModule GckModule;



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