[gnome-keyring/dbus-api] [pkcs11] Add support for AES secret keys and DH derive.



commit 3e324f117fd8c1ae4c4cf9ebd8511737c3482d9b
Author: Stef Walter <stef memberwebs com>
Date:   Wed Nov 18 17:31:34 2009 +0000

    [pkcs11] Add support for AES secret keys and DH derive.
    
    Implement CKM_DH_PKCS_DERIVE and CKK_AES related stuff.

 pkcs11/gck/Makefile.am          |    3 +
 pkcs11/gck/gck-aes-key.c        |  226 +++++++++++++++++++++++++++++++++++++++
 pkcs11/gck/gck-aes-key.h        |   50 +++++++++
 pkcs11/gck/gck-aes-mechanism.h  |   33 ++++++
 pkcs11/gck/gck-crypto.c         |   38 +++++++-
 pkcs11/gck/gck-crypto.h         |    9 ++
 pkcs11/gck/gck-dh-key.c         |    7 ++
 pkcs11/gck/gck-dh-key.h         |    2 +
 pkcs11/gck/gck-dh-mechanism.c   |   99 +++++++++++++++++
 pkcs11/gck/gck-dh-mechanism.h   |    7 ++
 pkcs11/gck/gck-dh-private-key.c |    7 ++
 pkcs11/gck/gck-dh-private-key.h |    2 +
 pkcs11/gck/gck-module.c         |    2 +
 pkcs11/gck/gck-object.c         |   40 +++++++
 pkcs11/gck/gck-object.h         |   10 ++
 pkcs11/gck/gck-secret-key.c     |  160 +++++++++++++++++++++++++++
 pkcs11/gck/gck-secret-key.h     |   51 +++++++++
 pkcs11/gck/gck-session.c        |   65 ++++++++++--
 pkcs11/gck/gck-session.h        |    5 +
 pkcs11/gck/gck-types.h          |    2 +
 20 files changed, 808 insertions(+), 10 deletions(-)
---
diff --git a/pkcs11/gck/Makefile.am b/pkcs11/gck/Makefile.am
index 8a82d67..fc9f983 100644
--- a/pkcs11/gck/Makefile.am
+++ b/pkcs11/gck/Makefile.am
@@ -17,6 +17,8 @@ BUILT_SOURCES = \
 	asn1-def-pk.h asn1-def-pkix.h
 
 libgck_la_SOURCES = \
+	gck-aes-key.c gck-aes-key.h \
+	gck-aes-mechanism.h \
 	gck-attributes.c gck-attributes.h \
 	gck-certificate.c gck-certificate.h \
 	gck-certificate-key.c gck-certificate-key.h \
@@ -42,6 +44,7 @@ libgck_la_SOURCES = \
 	gck-private-xsa-key.c gck-private-xsa-key.h \
 	gck-public-xsa-key.c gck-public-xsa-key.h \
 	gck-secret.c gck-secret.h \
+	gck-secret-key.c gck-secret-key.h \
 	gck-serializable.c gck-serializable.h \
 	gck-session.c gck-session.h \
 	gck-sexp.c gck-sexp.h \
diff --git a/pkcs11/gck/gck-aes-key.c b/pkcs11/gck/gck-aes-key.c
new file mode 100644
index 0000000..ee97b2c
--- /dev/null
+++ b/pkcs11/gck/gck-aes-key.c
@@ -0,0 +1,226 @@
+/*
+ * 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-aes-key.h"
+#include "gck-session.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+#include "egg/egg-secure-memory.h"
+
+struct _GckAesKey {
+	GckSecretKey parent;
+	gpointer value;
+	gsize n_value;
+};
+
+G_DEFINE_TYPE (GckAesKey, gck_aes_key, GCK_TYPE_SECRET_KEY);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static int
+algorithm_for_length (gsize length)
+{
+	switch (length) {
+	case 16:
+		return GCRY_CIPHER_AES128;
+	case 24:
+		return GCRY_CIPHER_AES192;
+	case 32:
+		return GCRY_CIPHER_AES256;
+	default:
+		return 0;
+	}
+}
+
+static CK_RV
+attribute_set_check_value (GckAesKey *self, CK_ATTRIBUTE *attr)
+{
+	gcry_cipher_hd_t cih;
+	gcry_error_t gcry;
+	int algorithm;
+	gpointer data;
+	CK_RV rv;
+
+	g_assert (GCK_IS_AES_KEY (self));
+	g_assert (attr);
+
+	/* Just asking for the length */
+	if (!attr->pValue) {
+		attr->ulValueLen = 3;
+		return CKR_OK;
+	}
+
+	algorithm = algorithm_for_length (self->n_value);
+	g_return_val_if_fail (algorithm != 0, CKR_GENERAL_ERROR);
+
+	gcry = gcry_cipher_open (&cih, algorithm, GCRY_CIPHER_MODE_ECB, 0);
+	if (gcry != 0) {
+		g_warning ("couldn't open %s cipher in ECB mode: %s",
+		           gcry_cipher_algo_name (algorithm), gcry_strerror (gcry));
+		return CKR_FUNCTION_FAILED;
+	}
+
+	/* Setup the key */
+	gcry = gcry_cipher_setkey (cih, self->value, self->n_value);
+	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+	/* Buffer of zeros */
+	data = g_malloc0 (self->n_value);
+
+	/* Encrypt it */
+	gcry = gcry_cipher_encrypt (cih, data, self->n_value, NULL, 0);
+	g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+	/* Use the first three bytes */
+	g_assert (self->n_value > 3);
+	rv = gck_attribute_set_data (attr, data, 3);
+
+	gcry_cipher_close (cih);
+	g_free (data);
+
+	return rv;
+}
+
+static void
+factory_create_aes_key (GckSession *session, GckTransaction *transaction,
+                        CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+{
+	GckAesKey *key;
+	GckManager *manager;
+	CK_ATTRIBUTE_PTR value;
+
+	value = gck_attributes_find (attrs, n_attrs, CKA_VALUE);
+	if (value == NULL)
+		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+
+	if (algorithm_for_length (value->ulValueLen) == 0)
+		return gck_transaction_fail (transaction, CKR_TEMPLATE_INCONSISTENT);
+
+	manager = gck_manager_for_template (attrs, n_attrs, session);
+	*object = g_object_new (GCK_TYPE_AES_KEY,
+	                        "module", gck_session_get_module (session),
+	                        "manager", manager,
+	                        NULL);
+	key = GCK_AES_KEY (*object);
+
+	key->value = egg_secure_alloc (value->ulValueLen);
+	key->n_value = value->ulValueLen;
+	memcpy (key->value, value->pValue, key->n_value);
+
+	gck_attribute_consume (value);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gck_aes_key_real_get_attribute (GckObject *base, GckSession *session, CK_ATTRIBUTE *attr)
+{
+	GckAesKey *self = GCK_AES_KEY (base);
+
+	switch (attr->type)
+	{
+	case CKA_KEY_TYPE:
+		return gck_attribute_set_ulong (attr, CKK_AES);
+
+	case CKA_VALUE:
+		return gck_attribute_set_data (attr, self->value, self->n_value);
+
+	case CKA_VALUE_LEN:
+		return gck_attribute_set_ulong (attr, self->n_value);
+
+	case CKA_CHECK_VALUE:
+		return attribute_set_check_value (self, attr);
+
+	case CKA_ALLOWED_MECHANISMS:
+		return gck_attribute_set_empty (attr);
+	};
+
+	return GCK_OBJECT_CLASS (gck_aes_key_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gck_aes_key_init (GckAesKey *self)
+{
+
+}
+
+static void
+gck_aes_key_finalize (GObject *obj)
+{
+	GckAesKey *self = GCK_AES_KEY (obj);
+
+	if (self->value) {
+		egg_secure_clear (self->value, self->n_value);
+		egg_secure_free (self->value);
+		self->value = NULL;
+		self->n_value = 0;
+	}
+
+	G_OBJECT_CLASS (gck_aes_key_parent_class)->finalize (obj);
+}
+
+static void
+gck_aes_key_class_init (GckAesKeyClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+
+	gck_aes_key_parent_class = g_type_class_peek_parent (klass);
+
+	gobject_class->finalize = gck_aes_key_finalize;
+
+	gck_class->get_attribute = gck_aes_key_real_get_attribute;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GckFactory*
+gck_aes_key_get_factory (void)
+{
+	static CK_OBJECT_CLASS klass = CKO_SECRET_KEY;
+	static CK_KEY_TYPE type = CKK_AES;
+
+	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_aes_key
+	};
+
+	return &factory;
+}
diff --git a/pkcs11/gck/gck-aes-key.h b/pkcs11/gck/gck-aes-key.h
new file mode 100644
index 0000000..168485e
--- /dev/null
+++ b/pkcs11/gck/gck-aes-key.h
@@ -0,0 +1,50 @@
+/*
+ * 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_AES_KEY_H__
+#define __GCK_AES_KEY_H__
+
+#include <glib-object.h>
+
+#include "gck-secret-key.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_AES_KEY            (gck_aes_key_get_factory ())
+
+#define GCK_TYPE_AES_KEY               (gck_aes_key_get_type ())
+#define GCK_AES_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_AES_KEY, GckAesKey))
+#define GCK_AES_KEY_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_AES_KEY, GckAesKeyClass))
+#define GCK_IS_AES_KEY(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_AES_KEY))
+#define GCK_IS_AES_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_AES_KEY))
+#define GCK_AES_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_AES_KEY, GckAesKeyClass))
+
+typedef struct _GckAesKeyClass GckAesKeyClass;
+typedef struct _GckAesKeyPrivate GckAesKeyPrivate;
+
+struct _GckAesKeyClass {
+	GckSecretKeyClass parent_class;
+};
+
+GType                     gck_aes_key_get_type           (void);
+
+GckFactory*               gck_aes_key_get_factory        (void);
+
+#endif /* __GCK_AES_KEY_H__ */
diff --git a/pkcs11/gck/gck-aes-mechanism.h b/pkcs11/gck/gck-aes-mechanism.h
new file mode 100644
index 0000000..1f1dd66
--- /dev/null
+++ b/pkcs11/gck/gck-aes-mechanism.h
@@ -0,0 +1,33 @@
+/*
+ * 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_AES_MECHANISM_H_
+#define GCK_AES_MECHANISM_H_
+
+#include "gck-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+#include <glib.h>
+
+#define GCK_AES_MECHANISM_KEY_LENGTH     16
+
+#endif /* GCK_AES_MECHANISM_H_ */
diff --git a/pkcs11/gck/gck-crypto.c b/pkcs11/gck/gck-crypto.c
index f85a918..db139fd 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-aes-mechanism.h"
 #include "gck-dh-mechanism.h"
 #include "gck-mechanism-dsa.h"
 #include "gck-mechanism-rsa.h"
@@ -404,6 +405,29 @@ gck_crypto_generate_key_pair (GckSession *session, CK_MECHANISM_TYPE mech,
 	}
 }
 
+CK_RV
+gck_crypto_derive_key (GckSession *session, CK_MECHANISM_PTR mech, GckObject *base,
+                       CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **derived)
+{
+	g_return_val_if_fail (GCK_IS_SESSION (session), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (GCK_IS_OBJECT (base), CKR_GENERAL_ERROR);
+	g_return_val_if_fail (derived, CKR_GENERAL_ERROR);
+
+	if (!gck_object_has_attribute_ulong (base, session, CKA_ALLOWED_MECHANISMS, mech->mechanism))
+		return CKR_KEY_TYPE_INCONSISTENT;
+
+	if (!gck_object_has_attribute_boolean (base, session, CKA_DERIVE, TRUE))
+		return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+	switch (mech->mechanism) {
+	case CKM_DH_PKCS_DERIVE:
+		return gck_dh_mechanism_derive (session, mech, base, attrs,
+		                                n_attrs, derived);
+	default:
+		return CKR_MECHANISM_INVALID;
+	}
+}
+
 /* ----------------------------------------------------------------------------
  * PREPARE FUNCTIONS
  */
@@ -441,7 +465,7 @@ gck_crypto_prepare_xsa (GckSession *session, CK_MECHANISM_TYPE mech, GckObject *
 }
 
 /* --------------------------------------------------------------------------
- * INITIALIZATION
+ * UTILITY
  */
 
 
@@ -450,3 +474,15 @@ gck_crypto_initialize (void)
 {
 	egg_libgcrypt_initialize ();
 }
+
+gulong
+gck_crypto_secret_key_length (CK_KEY_TYPE type)
+{
+	switch (type) {
+	case CKK_AES:
+		return GCK_AES_MECHANISM_KEY_LENGTH;
+	default:
+		return 0;
+	}
+}
+
diff --git a/pkcs11/gck/gck-crypto.h b/pkcs11/gck/gck-crypto.h
index 2b8ef2e..a32a95e 100644
--- a/pkcs11/gck/gck-crypto.h
+++ b/pkcs11/gck/gck-crypto.h
@@ -131,4 +131,13 @@ CK_RV                    gck_crypto_generate_key_pair                  (GckSessi
                                                                         GckObject **pub_key,
                                                                         GckObject **priv_key);
 
+CK_RV                    gck_crypto_derive_key                         (GckSession *session,
+                                                                        CK_MECHANISM_PTR mech,
+                                                                        GckObject *base,
+                                                                        CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs,
+                                                                        GckObject **derived);
+
+gulong                   gck_crypto_secret_key_length                  (CK_KEY_TYPE type);
+
 #endif /* GCKCRYPTO_H_ */
diff --git a/pkcs11/gck/gck-dh-key.c b/pkcs11/gck/gck-dh-key.c
index 2c0ef64..a4e7d86 100644
--- a/pkcs11/gck/gck-dh-key.c
+++ b/pkcs11/gck/gck-dh-key.c
@@ -146,3 +146,10 @@ gck_dh_key_initialize (GckDhKey *self, gcry_mpi_t prime, gcry_mpi_t base,
 	self->pv->id = id;
 	self->pv->n_id = n_id;
 }
+
+gcry_mpi_t
+gck_dh_key_get_prime (GckDhKey *self)
+{
+	g_return_val_if_fail (GCK_IS_DH_KEY (self), NULL);
+	return self->pv->prime;
+}
diff --git a/pkcs11/gck/gck-dh-key.h b/pkcs11/gck/gck-dh-key.h
index bb7e68c..17c0707 100644
--- a/pkcs11/gck/gck-dh-key.h
+++ b/pkcs11/gck/gck-dh-key.h
@@ -54,4 +54,6 @@ void                      gck_dh_key_initialize         (GckDhKey *self,
                                                          gpointer id,
                                                          gsize n_id);
 
+gcry_mpi_t                gck_dh_key_get_prime          (GckDhKey *self);
+
 #endif /* __GCK_DH_KEY_H__ */
diff --git a/pkcs11/gck/gck-dh-mechanism.c b/pkcs11/gck/gck-dh-mechanism.c
index 4f901dd..c16e1da 100644
--- a/pkcs11/gck/gck-dh-mechanism.c
+++ b/pkcs11/gck/gck-dh-mechanism.c
@@ -22,6 +22,7 @@
 #include "config.h"
 
 #include "gck-attributes.h"
+#include "gck-crypto.h"
 #include "gck-dh-mechanism.h"
 #include "gck-dh-private-key.h"
 #include "gck-dh-public-key.h"
@@ -111,3 +112,101 @@ gck_dh_mechanism_generate (GckSession *session, CK_ATTRIBUTE_PTR pub_atts,
 	g_free (buffer);
 	return CKR_OK;
 }
+
+static gpointer
+prepare_and_truncate_secret (gcry_mpi_t secret, CK_ATTRIBUTE_PTR attrs,
+                             CK_ULONG n_attrs, gsize *n_value)
+{
+	CK_ULONG length = 0;
+	CK_KEY_TYPE type;
+	gcry_error_t gcry;
+	guchar *value;
+	gsize offset = 0;
+
+	g_assert (n_value);
+
+	/* What length should we truncate to? */
+	if (!gck_attributes_find_ulong (attrs, n_attrs, CKA_VALUE_LEN, &length)) {
+		if (gck_attributes_find_ulong (attrs, n_attrs, CKA_KEY_TYPE, &type))
+			length = gck_crypto_secret_key_length (type);
+	}
+
+	/* Write out the secret */
+	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, n_value, secret);
+	g_return_val_if_fail (gcry == 0, NULL);
+	if (*n_value < length)
+		offset = length - *n_value;
+	value = egg_secure_alloc (*n_value + offset);
+	gcry = gcry_mpi_print (GCRYMPI_FMT_USG, value + offset, *n_value, n_value, secret);
+	g_return_val_if_fail (gcry == 0, NULL);
+
+	if (length != 0 && length < *n_value) {
+		offset = *n_value - length;
+		memmove (value, value + offset, length);
+		*n_value = length;
+	}
+
+	return value;
+}
+
+CK_RV
+gck_dh_mechanism_derive (GckSession *session, CK_MECHANISM_PTR mech, GckObject *base,
+                         CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **derived)
+{
+	gcry_mpi_t peer = NULL;
+	gcry_mpi_t prime;
+	gcry_mpi_t priv;
+	gcry_mpi_t secret;
+	gcry_error_t gcry;
+	CK_ATTRIBUTE attr;
+	GArray *array;
+	gboolean ret;
+	gsize n_value;
+	gpointer value;
+	CK_RV rv;
+
+	g_return_val_if_fail (GCK_IS_DH_PRIVATE_KEY (base), CKR_GENERAL_ERROR);
+
+	if (mech->ulParameterLen && mech->pParameter) {
+		gcry = gcry_mpi_scan (&peer, GCRYMPI_FMT_USG, mech->pParameter,
+		                      mech->ulParameterLen, NULL);
+		if (gcry != 0)
+			peer = NULL;
+	}
+
+	if (peer == NULL)
+		return CKR_MECHANISM_PARAM_INVALID;
+
+	prime = gck_dh_key_get_prime (GCK_DH_KEY (base));
+	priv = gck_dh_private_key_get_value (GCK_DH_PRIVATE_KEY (base));
+	ret = egg_dh_gen_secret (peer, priv, prime, &secret);
+	gcry_mpi_release (peer);
+
+	if (ret != TRUE)
+		return CKR_FUNCTION_FAILED;
+
+	value = prepare_and_truncate_secret (secret, attrs, n_attrs, &n_value);
+	g_return_val_if_fail (value, CKR_GENERAL_ERROR);
+	gcry_mpi_release (secret);
+
+	/* Now setup the attributes with our new value */
+	array = g_array_new (FALSE, FALSE, sizeof (CK_ATTRIBUTE));
+
+	/* Prepend the value */
+	attr.type = CKA_VALUE;
+	attr.pValue = value;
+	attr.ulValueLen = n_value;
+	g_array_append_val (array, attr);
+
+	/* Add the remainder of the attributes */
+	g_array_append_vals (array, attrs, n_attrs);
+
+	/* Now create an object with these attributes */
+	rv = gck_session_create_object_for_attributes (session, (CK_ATTRIBUTE_PTR)array->data,
+	                                               array->len, derived);
+
+	egg_secure_free (value);
+	g_array_free (array, TRUE);
+
+	return rv;
+}
diff --git a/pkcs11/gck/gck-dh-mechanism.h b/pkcs11/gck/gck-dh-mechanism.h
index 38624b2..3a3ea85 100644
--- a/pkcs11/gck/gck-dh-mechanism.h
+++ b/pkcs11/gck/gck-dh-mechanism.h
@@ -42,4 +42,11 @@ CK_RV                    gck_dh_mechanism_generate                     (GckSessi
                                                                         GckObject **pub_key,
                                                                         GckObject **priv_key);
 
+CK_RV                    gck_dh_mechanism_derive                       (GckSession *session,
+                                                                        CK_MECHANISM_PTR mech,
+                                                                        GckObject *base,
+                                                                        CK_ATTRIBUTE_PTR attrs,
+                                                                        CK_ULONG n_attrs,
+                                                                        GckObject **derived);
+
 #endif /* GCK_DH_MECHANISM_H_ */
diff --git a/pkcs11/gck/gck-dh-private-key.c b/pkcs11/gck/gck-dh-private-key.c
index ac894ae..4017275 100644
--- a/pkcs11/gck/gck-dh-private-key.c
+++ b/pkcs11/gck/gck-dh-private-key.c
@@ -205,3 +205,10 @@ gck_dh_private_key_new (GckModule *module, GckManager *manager,
 	key->value = value;
 	return key;
 }
+
+gcry_mpi_t
+gck_dh_private_key_get_value (GckDhPrivateKey *self)
+{
+	g_return_val_if_fail (GCK_IS_DH_PRIVATE_KEY (self), NULL);
+	return self->value;
+}
diff --git a/pkcs11/gck/gck-dh-private-key.h b/pkcs11/gck/gck-dh-private-key.h
index 88b0b64..bc7911c 100644
--- a/pkcs11/gck/gck-dh-private-key.h
+++ b/pkcs11/gck/gck-dh-private-key.h
@@ -54,4 +54,6 @@ GckDhPrivateKey*          gck_dh_private_key_new               (GckModule *modul
                                                                 gpointer id,
                                                                 gsize n_id);
 
+gcry_mpi_t                gck_dh_private_key_get_value         (GckDhPrivateKey *self);
+
 #endif /* __GCK_DH_PRIVATE_KEY_H__ */
diff --git a/pkcs11/gck/gck-module.c b/pkcs11/gck/gck-module.c
index 160ad54..3301cd2 100644
--- a/pkcs11/gck/gck-module.c
+++ b/pkcs11/gck/gck-module.c
@@ -25,6 +25,7 @@
 #include "pkcs11/pkcs11g.h"
 #include "pkcs11/pkcs11i.h"
 
+#include "gck-aes-key.h"
 #include "gck-attributes.h"
 #include "gck-certificate.h"
 #include "gck-credential.h"
@@ -574,6 +575,7 @@ 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_AES_KEY);
 	gck_module_register_factory (self, GCK_FACTORY_CERTIFICATE);
 	gck_module_register_factory (self, GCK_FACTORY_CREDENTIAL);
 	gck_module_register_factory (self, GCK_FACTORY_DH_PRIVATE_KEY);
diff --git a/pkcs11/gck/gck-object.c b/pkcs11/gck/gck-object.c
index 06ed1ec..0cb20c3 100644
--- a/pkcs11/gck/gck-object.c
+++ b/pkcs11/gck/gck-object.c
@@ -744,6 +744,46 @@ gck_object_get_attribute_data (GckObject *self, GckSession *session,
 	return attr.pValue;
 }
 
+gboolean
+gck_object_has_attribute_ulong (GckObject *self, GckSession *session,
+                                CK_ATTRIBUTE_TYPE type, gulong value)
+{
+	gulong *data;
+	gsize n_data, i;
+
+	g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (GCK_IS_SESSION (session), FALSE);
+
+	data = gck_object_get_attribute_data (self, session, type, &n_data);
+	if (data == NULL)
+		return FALSE;
+
+	g_return_val_if_fail (n_data % sizeof (gulong) == 0, FALSE);
+	for (i = 0; i < n_data / sizeof (gulong); ++i) {
+		if (data[i] == value) {
+			g_free (data);
+			return TRUE;
+		}
+	}
+
+	g_free (data);
+	return FALSE;
+}
+
+gboolean
+gck_object_has_attribute_boolean (GckObject *self, GckSession *session,
+                                  CK_ATTRIBUTE_TYPE type, gboolean value)
+{
+	gboolean data;
+
+	g_return_val_if_fail (GCK_IS_OBJECT (self), FALSE);
+	g_return_val_if_fail (GCK_IS_SESSION (session), FALSE);
+
+	if (!gck_object_get_attribute_boolean (self, session, type, &data))
+		return FALSE;
+	return data == value;
+}
+
 void
 gck_object_destroy (GckObject *self, GckTransaction *transaction)
 {
diff --git a/pkcs11/gck/gck-object.h b/pkcs11/gck/gck-object.h
index 75fa935..d9b28d1 100644
--- a/pkcs11/gck/gck-object.h
+++ b/pkcs11/gck/gck-object.h
@@ -140,4 +140,14 @@ void*                  gck_object_get_attribute_data     (GckObject *self,
                                                           CK_ATTRIBUTE_TYPE type,
                                                           gsize *n_data);
 
+gboolean               gck_object_has_attribute_ulong    (GckObject *self,
+                                                          GckSession *session,
+                                                          CK_ATTRIBUTE_TYPE type,
+                                                          gulong value);
+
+gboolean               gck_object_has_attribute_boolean  (GckObject *self,
+                                                          GckSession *session,
+                                                          CK_ATTRIBUTE_TYPE type,
+                                                          gboolean value);
+
 #endif /* __GCK_OBJECT_H__ */
diff --git a/pkcs11/gck/gck-secret-key.c b/pkcs11/gck/gck-secret-key.c
new file mode 100644
index 0000000..dedc790
--- /dev/null
+++ b/pkcs11/gck/gck-secret-key.c
@@ -0,0 +1,160 @@
+/*
+ * 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-secret-key.h"
+#include "gck-session.h"
+#include "gck-util.h"
+
+struct _GckSecretKeyPrivate {
+	gpointer id;
+	gsize n_id;
+};
+
+G_DEFINE_TYPE (GckSecretKey, gck_secret_key, GCK_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC_SECRET_KEY
+ */
+
+static CK_RV
+gck_secret_key_real_get_attribute (GckObject *base, GckSession *session, CK_ATTRIBUTE* attr)
+{
+	GckSecretKey *self = GCK_SECRET_KEY (base);
+
+	switch (attr->type)
+	{
+	case CKA_CLASS:
+		return gck_attribute_set_ulong (attr, CKO_SECRET_KEY);
+
+	case CKA_SENSITIVE:
+	case CKA_ENCRYPT:
+	case CKA_DECRYPT:
+	case CKA_SIGN:
+	case CKA_VERIFY:
+	case CKA_WRAP:
+	case CKA_UNWRAP:
+	case CKA_DERIVE:
+		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_TRUSTED:
+		return gck_attribute_set_bool (attr, FALSE);
+
+	case CKA_WRAP_TEMPLATE:
+	case CKA_UNWRAP_TEMPLATE:
+		return CKR_ATTRIBUTE_TYPE_INVALID;
+
+	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_ID:
+		return gck_attribute_set_data (attr, self->pv->id, self->pv->n_id);
+
+	case CKA_KEY_GEN_MECHANISM:
+		return gck_attribute_set_ulong (attr, CK_UNAVAILABLE_INFORMATION);
+	};
+
+	return GCK_OBJECT_CLASS (gck_secret_key_parent_class)->get_attribute (base, session, attr);
+}
+
+static void
+gck_secret_key_real_create_attributes (GckObject *object, GckSession *session, GckTransaction *transaction,
+                                       CK_ATTRIBUTE *attrs, CK_ULONG n_attrs)
+{
+	GckSecretKey *self = GCK_SECRET_KEY (object);
+	CK_ATTRIBUTE_PTR id;
+
+	if (!self->pv->n_id) {
+		id = gck_attributes_find (attrs, n_attrs, CKA_ID);
+		if (id == NULL) {
+			self->pv->id = NULL;
+			self->pv->n_id = 0;
+		} else {
+			self->pv->id = g_memdup (id->pValue, id->ulValueLen);
+			self->pv->n_id = id->ulValueLen;
+			gck_attribute_consume (id);
+		}
+	}
+}
+
+static void
+gck_secret_key_init (GckSecretKey *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_SECRET_KEY, GckSecretKeyPrivate);
+}
+
+static void
+gck_secret_key_finalize (GObject *obj)
+{
+	GckSecretKey *self = GCK_SECRET_KEY (obj);
+
+	g_free (self->pv->id);
+	self->pv->id = NULL;
+	self->pv->n_id = 0;
+
+	G_OBJECT_CLASS (gck_secret_key_parent_class)->finalize (obj);
+}
+
+static void
+gck_secret_key_class_init (GckSecretKeyClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+	GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+
+	gck_secret_key_parent_class = g_type_class_peek_parent (klass);
+
+	gobject_class->finalize = gck_secret_key_finalize;
+
+	gck_class->get_attribute = gck_secret_key_real_get_attribute;
+	gck_class->create_attributes = gck_secret_key_real_create_attributes;
+
+	g_type_class_add_private (klass, sizeof (GckSecretKeyPrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
diff --git a/pkcs11/gck/gck-secret-key.h b/pkcs11/gck/gck-secret-key.h
new file mode 100644
index 0000000..c3dfe3c
--- /dev/null
+++ b/pkcs11/gck/gck-secret-key.h
@@ -0,0 +1,51 @@
+/*
+ * 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_SECRET_KEY_H__
+#define __GCK_SECRET_KEY_H__
+
+#include <glib-object.h>
+
+#include "gck-object.h"
+#include "gck-types.h"
+
+#define GCK_TYPE_SECRET_KEY               (gck_secret_key_get_type ())
+#define GCK_SECRET_KEY(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_SECRET_KEY, GckSecretKey))
+#define GCK_SECRET_KEY_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_SECRET_KEY, GckSecretKeyClass))
+#define GCK_IS_SECRET_KEY(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_SECRET_KEY))
+#define GCK_IS_SECRET_KEY_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_SECRET_KEY))
+#define GCK_SECRET_KEY_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_SECRET_KEY, GckSecretKeyClass))
+
+typedef struct _GckSecretKeyClass GckSecretKeyClass;
+typedef struct _GckSecretKeyPrivate GckSecretKeyPrivate;
+
+struct _GckSecretKey {
+	GckObject parent;
+	GckSecretKeyPrivate *pv;
+};
+
+struct _GckSecretKeyClass {
+	GckObjectClass parent_class;
+};
+
+GType                     gck_secret_key_get_type           (void);
+
+#endif /* __GCK_SECRET_KEY_H__ */
diff --git a/pkcs11/gck/gck-session.c b/pkcs11/gck/gck-session.c
index dda5260..f321cb3 100644
--- a/pkcs11/gck/gck-session.c
+++ b/pkcs11/gck/gck-session.c
@@ -905,6 +905,22 @@ gck_session_create_object_for_factory (GckSession *self, GckFactory *factory,
 	return rv;
 }
 
+CK_RV
+gck_session_create_object_for_attributes (GckSession *self, CK_ATTRIBUTE_PTR attrs,
+                                          CK_ULONG n_attrs, GckObject **object)
+{
+	GckFactory *factory;
+
+	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_GENERAL_ERROR);
+
+	/* Find out if we can create such an object */
+	factory = gck_module_find_factory (gck_session_get_module (self), attrs, n_attrs);
+	if (factory == NULL)
+		return CKR_TEMPLATE_INCOMPLETE;
+
+	return gck_session_create_object_for_factory (self, factory, attrs, n_attrs, object);
+}
+
 /* -----------------------------------------------------------------------------
  * PKCS#11
  */
@@ -967,7 +983,6 @@ gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
                             CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object)
 {
 	GckObject *object = NULL;
-	GckFactory *factory;
 	CK_RV rv;
 
 	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
@@ -976,12 +991,7 @@ gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
 	if (!(!count || template))
 		return CKR_ARGUMENTS_BAD;
 
-	/* Find out if we can create such an object */
-	factory = gck_module_find_factory (gck_session_get_module (self), template, count);
-	if (!factory)
-		return CKR_TEMPLATE_INCOMPLETE;
-
-	rv = gck_session_create_object_for_factory (self, factory, template, count, &object);
+	rv = gck_session_create_object_for_attributes (self, template, count, &object);
 	if (rv == CKR_OK) {
 		g_assert (object);
 		*new_object = gck_object_get_handle (object);
@@ -1548,8 +1558,45 @@ gck_session_C_DeriveKey (GckSession* self, CK_MECHANISM_PTR mechanism,
                          CK_OBJECT_HANDLE base_key, CK_ATTRIBUTE_PTR template,
                          CK_ULONG count, CK_OBJECT_HANDLE_PTR key)
 {
-	/* Our keys don't support derivation */
- 	return CKR_FUNCTION_NOT_SUPPORTED;	
+	GckTransaction *transaction;
+	GckObject *base = NULL;
+	GckObject *derived = NULL;
+	CK_RV rv;
+
+	g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
+	if (!mechanism)
+		return CKR_ARGUMENTS_BAD;
+	if (!(!count || template))
+		return CKR_ARGUMENTS_BAD;
+	if (!key)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = gck_session_lookup_readable_object (self, base_key, &base);
+	if (rv != CKR_OK)
+		return rv;
+
+	/*
+	 * Duplicate the memory for the attributes (but not values) so we
+	 * can 'consume' in the generator and create object functions.
+	 */
+	template = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
+	transaction = gck_transaction_new ();
+
+	/* Actually do the object creation */
+	rv = gck_crypto_derive_key (self, mechanism, base, template, count, &derived);
+	if (rv != CKR_OK)
+		gck_transaction_fail (transaction, rv);
+
+	g_free (template);
+
+	gck_transaction_complete (transaction);
+	rv = gck_transaction_get_result (transaction);
+	g_object_unref (transaction);
+
+	if (rv == CKR_OK)
+		*key = gck_object_get_handle (derived);
+
+	return rv;
 }
 
 CK_RV
diff --git a/pkcs11/gck/gck-session.h b/pkcs11/gck/gck-session.h
index 6afb563..6904509 100644
--- a/pkcs11/gck/gck-session.h
+++ b/pkcs11/gck/gck-session.h
@@ -116,6 +116,11 @@ CK_RV                    gck_session_create_object_for_factory          (GckSess
                                                                          CK_ULONG n_attrs,
                                                                          GckObject **object);
 
+CK_RV                    gck_session_create_object_for_attributes       (GckSession *self,
+                                                                         CK_ATTRIBUTE_PTR attrs,
+                                                                         CK_ULONG n_attrs,
+                                                                         GckObject **object);
+
 CK_RV                    gck_session_C_GetFunctionStatus                (GckSession *self);
 
 CK_RV                    gck_session_C_CancelFunction                   (GckSession *self);
diff --git a/pkcs11/gck/gck-types.h b/pkcs11/gck/gck-types.h
index b7361e2..1920f8f 100644
--- a/pkcs11/gck/gck-types.h
+++ b/pkcs11/gck/gck-types.h
@@ -22,6 +22,7 @@
 #ifndef __GCK_TYPES_H__
 #define __GCK_TYPES_H__
 
+typedef struct _GckAesKey GckAesKey;
 typedef struct _GckCertificate GckCertificate;
 typedef struct _GckCertificateKey GckCertificateKey;
 typedef struct _GckCertificateTrust GckCertificateTrust;
@@ -36,6 +37,7 @@ typedef struct _GckObject GckObject;
 typedef struct _GckPrivateXsaKey GckPrivateXsaKey;
 typedef struct _GckPublicXsaKey GckPublicXsaKey;
 typedef struct _GckSecret GckSecret;
+typedef struct _GckSecretKey GckSecretKey;
 typedef struct _GckSession GckSession;
 typedef struct _GckSessionPrivateKey GckSessionPrivateKey;
 typedef struct _GckSessionPublicKey GckSessionPublicKey;



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