[gnome-keyring/dbus-api] [gp11] Implement support for generate, wrap, unwrap, derive.



commit e616479ba2976a9e58b02d11c379ed68919dbbf7
Author: Stef Walter <stef memberwebs com>
Date:   Fri Nov 20 17:29:53 2009 +0000

    [gp11] Implement support for generate, wrap, unwrap, derive.
    
    Implement gp11_session_generate_key_pair...(),
    gp11_session_wrap_key...(), gp11_session_unwrap_key...(),
    and gp11_session_derive_key...().

 gp11/gp11-misc.c                   |   83 ++++
 gp11/gp11-session.c                |  852 +++++++++++++++++++++++++++++++++---
 gp11/gp11.h                        |  158 ++++---
 gp11/tests/Makefile.am             |    1 +
 gp11/tests/gp11-test-module.c      |  253 ++++++++++-
 gp11/tests/gp11-test.h             |   13 +
 gp11/tests/test-gp11-mechanism.c   |   60 +++
 gp11/tests/unit-test-gp11-crypto.c |  353 +++++++++++++--
 8 files changed, 1573 insertions(+), 200 deletions(-)
---
diff --git a/gp11/gp11-misc.c b/gp11/gp11-misc.c
index 5b097f0..35fa958 100644
--- a/gp11/gp11-misc.c
+++ b/gp11/gp11-misc.c
@@ -352,3 +352,86 @@ _gp11_ulong_equal (gconstpointer v1, gconstpointer v2)
 {
 	return *((const gulong*)v1) == *((const gulong*)v2);
 }
+
+static GQuark mechanism_quark = 0;
+
+static void
+free_refs (gpointer data)
+{
+	gint *refs = data;
+	g_assert (refs);
+	g_assert (*refs == 0);
+	g_slice_free (gint, data);
+}
+
+GP11Mechanism*
+gp11_mechanism_new (gulong type)
+{
+	return gp11_mechanism_new_with_param (type, NULL, 0);
+}
+
+GP11Mechanism*
+gp11_mechanism_new_with_param (gulong type, gconstpointer parameter,
+                               gulong n_parameter)
+{
+	static volatile gsize inited_quark = 0;
+	GP11Mechanism *mech;
+	gint *refs;
+
+	/* Initialize first time around */
+	if (g_once_init_enter (&inited_quark)) {
+		mechanism_quark = g_quark_from_static_string ("GP11Mechanism::refs");
+		g_once_init_leave (&inited_quark, 1);
+	}
+
+	mech = g_slice_new (GP11Mechanism);
+	mech->type = type;
+	mech->parameter = g_memdup (parameter, n_parameter);
+	mech->n_parameter = n_parameter;
+
+	refs = g_slice_new (gint);
+	*refs = 1;
+	g_dataset_id_set_data_full (mech, mechanism_quark, refs, free_refs);
+
+	return mech;
+}
+
+GP11Mechanism*
+gp11_mechanism_ref (GP11Mechanism* mech)
+{
+	gint *refs;
+
+	g_return_val_if_fail (mech, NULL);
+
+	refs = g_dataset_id_get_data (mech, mechanism_quark);
+	if (refs == NULL) {
+		g_warning ("Encountered invalid GP11Mechanism struct. Either it was unreffed or "
+		           "possibly allocated on the stack. Always use gp11_mechanism_new () and friends.");
+		return NULL;
+	}
+
+	g_atomic_int_add (refs, 1);
+	return mech;
+}
+
+void
+gp11_mechanism_unref (GP11Mechanism* mech)
+{
+	gint *refs;
+
+	if (!mech)
+		return;
+
+	refs = g_dataset_id_get_data (mech, mechanism_quark);
+	if (refs == NULL) {
+		g_warning ("Encountered invalid GP11Mechanism struct. Either it was unreffed or "
+		           "possibly allocated on the stack. Always use gp11_mechanism_new () and friends.");
+		return;
+	}
+
+	if (g_atomic_int_dec_and_test (refs)) {
+		g_free (mech->parameter);
+		g_dataset_id_remove_data (mech, mechanism_quark);
+		g_slice_free (GP11Mechanism, mech);
+	}
+}
diff --git a/gp11/gp11-session.c b/gp11/gp11-session.c
index 452c60d..08bc11e 100644
--- a/gp11/gp11-session.c
+++ b/gp11/gp11-session.c
@@ -1039,6 +1039,736 @@ gp11_session_find_objects_finish (GP11Session *self, GAsyncResult *result, GErro
 	return objlist_from_handles (self, args->objects, args->n_objects);
 }
 
+/* -----------------------------------------------------------------------------
+ * KEY PAIR GENERATION
+ */
+
+typedef struct _GenerateKeyPair {
+	GP11Arguments base;
+	GP11Mechanism *mechanism;
+	GP11Attributes *public_attrs;
+	GP11Attributes *private_attrs;
+	CK_OBJECT_HANDLE public_key;
+	CK_OBJECT_HANDLE private_key;
+} GenerateKeyPair;
+
+static void
+free_generate_key_pair (GenerateKeyPair *args)
+{
+	gp11_mechanism_unref (args->mechanism);
+	gp11_attributes_unref (args->public_attrs);
+	gp11_attributes_unref (args->private_attrs);
+	g_free (args);
+}
+
+static CK_RV
+perform_generate_key_pair (GenerateKeyPair *args)
+{
+	CK_ATTRIBUTE_PTR pub_attrs, priv_attrs;
+	CK_ULONG n_pub_attrs, n_priv_attrs;
+
+	g_assert (sizeof (CK_MECHANISM) == sizeof (GP11Mechanism));
+
+	pub_attrs = _gp11_attributes_commit_out (args->public_attrs, &n_pub_attrs);
+	priv_attrs = _gp11_attributes_commit_out (args->private_attrs, &n_priv_attrs);
+
+	return (args->base.pkcs11->C_GenerateKeyPair) (args->base.handle,
+	                                               (CK_MECHANISM_PTR)args->mechanism,
+	                                               pub_attrs, n_pub_attrs,
+	                                               priv_attrs, n_priv_attrs,
+	                                               &args->public_key,
+	                                               &args->private_key);
+}
+
+/**
+ * gp11_session_generate_key_pair_full:
+ * @self: The session to use.
+ * @mechanism: The mechanism to use for key generation.
+ * @public_attrs: Additional attributes for the generated public key.
+ * @private_attrs: Additional attributes for the generated private key.
+ * @public_key: A location to return the resulting public key.
+ * @private_key: A location to return the resulting private key.
+ * @cancellable: Optional cancellation object, or NULL.
+ * @err: A location to return an error, or NULL.
+ *
+ * Generate a new key pair of public and private keys. This call may block for an
+ * indefinite period.
+ *
+ * Return value: TRUE if the operation succeeded.
+ **/
+gboolean
+gp11_session_generate_key_pair_full (GP11Session *self, GP11Mechanism *mechanism,
+                                     GP11Attributes *public_attrs, GP11Attributes *private_attrs,
+                                     GP11Object **public_key, GP11Object **private_key,
+                                     GCancellable *cancellable, GError **err)
+{
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	GenerateKeyPair args = { GP11_ARGUMENTS_INIT, mechanism, public_attrs, private_attrs, 0, 0 };
+	gboolean ret;
+
+	g_return_val_if_fail (GP11_IS_SESSION (self), FALSE);
+	g_return_val_if_fail (mechanism, FALSE);
+	g_return_val_if_fail (public_attrs, FALSE);
+	g_return_val_if_fail (private_attrs, FALSE);
+	g_return_val_if_fail (public_key, FALSE);
+	g_return_val_if_fail (private_key, FALSE);
+
+	_gp11_attributes_lock (public_attrs);
+	_gp11_attributes_lock (private_attrs);
+	ret = _gp11_call_sync (self, perform_generate_key_pair, NULL, &args, cancellable, err);
+	_gp11_attributes_unlock (private_attrs);
+	_gp11_attributes_unlock (public_attrs);
+
+	if (!ret)
+		return FALSE;
+
+	*public_key = gp11_object_from_handle (data->slot, args.public_key);
+	*private_key = gp11_object_from_handle (data->slot, args.private_key);
+	return TRUE;
+}
+
+/**
+ * gp11_session_generate_key_pair_async:
+ * @self: The session to use.
+ * @mechanism: The mechanism to use for key generation.
+ * @public_attrs: Additional attributes for the generated public key.
+ * @private_attrs: Additional attributes for the generated private key.
+ * @cancellable: Optional cancellation object or NULL.
+ * @callback: Called when the operation completes.
+ * @user_data: Data to pass to the callback.
+ *
+ * Generate a new key pair of public and private keys. This call will
+ * return immediately and complete asynchronously.
+ **/
+void
+gp11_session_generate_key_pair_async (GP11Session *self, GP11Mechanism *mechanism,
+                                      GP11Attributes *public_attrs, GP11Attributes *private_attrs,
+                                      GCancellable *cancellable, GAsyncReadyCallback callback,
+                                      gpointer user_data)
+{
+	GenerateKeyPair *args = _gp11_call_async_prep (self, self, perform_generate_key_pair,
+	                                               NULL, sizeof (*args), free_generate_key_pair);
+
+	g_return_if_fail (GP11_IS_SESSION (self));
+	g_return_if_fail (mechanism);
+	g_return_if_fail (public_attrs);
+	g_return_if_fail (private_attrs);
+
+	args->public_attrs = gp11_attributes_ref (public_attrs);
+	_gp11_attributes_lock (public_attrs);
+	args->private_attrs = gp11_attributes_ref (private_attrs);
+	_gp11_attributes_lock (private_attrs);
+	args->mechanism = gp11_mechanism_ref (mechanism);
+
+	_gp11_call_async_ready_go (args, cancellable, callback, user_data);
+}
+
+/**
+ * gp11_session_generate_key_pair_finish:
+ * @self: The session to use.
+ * @result: The async result passed to the callback.
+ * @public_key: A location to return the resulting public key.
+ * @private_key: A location to return the resulting private key.
+ * @err: A location to return an error.
+ *
+ * Get the result of a generate key pair operation.
+ *
+ * Return value: TRUE if the operation succeeded.
+ **/
+gboolean
+gp11_session_generate_key_pair_finish (GP11Session *self, GAsyncResult *result,
+                                       GP11Object **public_key, GP11Object **private_key,
+                                       GError **err)
+{
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	GenerateKeyPair *args;
+
+	g_return_val_if_fail (GP11_IS_SESSION (self), FALSE);
+	g_return_val_if_fail (public_key, FALSE);
+	g_return_val_if_fail (private_key, FALSE);
+
+	args = _gp11_call_arguments (result, GenerateKeyPair);
+	_gp11_attributes_unlock (args->public_attrs);
+	_gp11_attributes_unlock (args->private_attrs);
+
+	if (!_gp11_call_basic_finish (result, err))
+		return FALSE;
+
+	*public_key = gp11_object_from_handle (data->slot, args->public_key);
+	*private_key = gp11_object_from_handle (data->slot, args->private_key);
+	return TRUE;
+}
+
+/* -----------------------------------------------------------------------------
+ * KEY WRAPPING
+ */
+
+typedef struct _WrapKey {
+	GP11Arguments base;
+	GP11Mechanism *mechanism;
+	CK_OBJECT_HANDLE wrapper;
+	CK_OBJECT_HANDLE wrapped;
+	gpointer result;
+	gulong n_result;
+} WrapKey;
+
+static void
+free_wrap_key (WrapKey *args)
+{
+	gp11_mechanism_unref (args->mechanism);
+	g_free (args->result);
+	g_free (args);
+}
+
+static CK_RV
+perform_wrap_key (WrapKey *args)
+{
+	CK_RV rv;
+
+	g_assert (sizeof (CK_MECHANISM) == sizeof (GP11Mechanism));
+
+	/* Get the length of the result */
+	rv = (args->base.pkcs11->C_WrapKey) (args->base.handle,
+	                                     (CK_MECHANISM_PTR)args->mechanism,
+	                                     args->wrapper, args->wrapped,
+	                                     NULL, &args->n_result);
+	if (rv != CKR_OK)
+		return rv;
+
+	/* And try again with a real buffer */
+	args->result = g_malloc0 (args->n_result);
+	return (args->base.pkcs11->C_WrapKey) (args->base.handle,
+	                                       (CK_MECHANISM_PTR)args->mechanism,
+	                                       args->wrapper, args->wrapped,
+	                                       args->result, &args->n_result);
+}
+
+/**
+ * gp11_session_wrap_key:
+ * @self: The session to use.
+ * @wrapper: The key to use for wrapping.
+ * @mechanism: The mechanism type to use for wrapping.
+ * @wrapped: The key to wrap.
+ * @n_result: A location in which to return the length of the wrapped data.
+ * @err: A location to return an error, or NULL.
+ *
+ * Wrap a key into a byte stream. This call may block for an
+ * indefinite period.
+ *
+ * Return value: The wrapped data or NULL if the operation failed.
+ **/
+gpointer
+gp11_session_wrap_key (GP11Session *self, GP11Object *key, gulong mech_type,
+                       GP11Object *wrapped, gsize *n_result, GError **err)
+{
+	GP11Mechanism mech = { mech_type, NULL, 0 };
+	return gp11_session_wrap_key_full (self, key, &mech, wrapped, n_result, NULL, err);
+}
+
+/**
+ * gp11_session_wrap_key_full:
+ * @self: The session to use.
+ * @wrapper: The key to use for wrapping.
+ * @mechanism: The mechanism to use for wrapping.
+ * @wrapped: The key to wrap.
+ * @n_result: A location in which to return the length of the wrapped data.
+ * @cancellable: Optional cancellation object, or NULL.
+ * @err: A location to return an error, or NULL.
+ *
+ * Wrap a key into a byte stream. This call may block for an
+ * indefinite period.
+ *
+ * Return value: The wrapped data or NULL if the operation failed.
+ **/
+gpointer
+gp11_session_wrap_key_full (GP11Session *self, GP11Object *wrapper, GP11Mechanism *mechanism,
+                            GP11Object *wrapped, gsize *n_result, GCancellable *cancellable,
+                            GError **err)
+{
+	WrapKey args = { GP11_ARGUMENTS_INIT, mechanism, 0, 0, NULL, 0 };
+	gboolean ret;
+
+	g_return_val_if_fail (GP11_IS_SESSION (self), FALSE);
+	g_return_val_if_fail (mechanism, FALSE);
+	g_return_val_if_fail (GP11_IS_OBJECT (wrapped), FALSE);
+	g_return_val_if_fail (GP11_IS_OBJECT (wrapper), FALSE);
+	g_return_val_if_fail (n_result, FALSE);
+
+	g_object_get (wrapper, "handle", &args.wrapper, NULL);
+	g_return_val_if_fail (args.wrapper != 0, NULL);
+	g_object_get (wrapped, "handle", &args.wrapped, NULL);
+	g_return_val_if_fail (args.wrapped != 0, NULL);
+
+	ret = _gp11_call_sync (self, perform_wrap_key, NULL, &args, cancellable, err);
+
+	if (!ret)
+		return FALSE;
+
+	*n_result = args.n_result;
+	return args.result;
+}
+
+/**
+ * gp11_session_wrap_key_async:
+ * @self: The session to use.
+ * @wrapper: The key to use for wrapping.
+ * @mechanism: The mechanism to use for wrapping.
+ * @wrapped: The key to wrap.
+ * @cancellable: Optional cancellation object or NULL.
+ * @callback: Called when the operation completes.
+ * @user_data: Data to pass to the callback.
+ *
+ * Wrap a key into a byte stream. This call will
+ * return immediately and complete asynchronously.
+ **/
+void
+gp11_session_wrap_key_async (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
+                             GP11Object *wrapped, GCancellable *cancellable,
+                             GAsyncReadyCallback callback, gpointer user_data)
+{
+	WrapKey *args = _gp11_call_async_prep (self, self, perform_wrap_key,
+	                                       NULL, sizeof (*args), free_wrap_key);
+
+	g_return_if_fail (GP11_IS_SESSION (self));
+	g_return_if_fail (mechanism);
+	g_return_if_fail (GP11_IS_OBJECT (wrapped));
+	g_return_if_fail (GP11_IS_OBJECT (key));
+
+	args->mechanism = gp11_mechanism_ref (mechanism);
+	g_object_get (key, "handle", &args->wrapper, NULL);
+	g_return_if_fail (args->wrapper != 0);
+	g_object_get (wrapped, "handle", &args->wrapped, NULL);
+	g_return_if_fail (args->wrapped != 0);
+
+	_gp11_call_async_ready_go (args, cancellable, callback, user_data);
+}
+
+/**
+ * gp11_session_wrap_key_finish:
+ * @self: The session to use.
+ * @result: The async result passed to the callback.
+ * @n_result: A location in which to return the length of the wrapped data.
+ * @err: A location to return an error.
+ *
+ * Get the result of a wrap key operation.
+ *
+ * Return value: The wrapped data or NULL if the operation failed.
+ **/
+gpointer
+gp11_session_wrap_key_finish (GP11Session *self, GAsyncResult *result,
+                              gsize *n_result, GError **err)
+{
+	WrapKey *args;
+	gpointer ret;
+
+	g_return_val_if_fail (GP11_IS_SESSION (self), NULL);
+	g_return_val_if_fail (n_result, NULL);
+
+	args = _gp11_call_arguments (result, WrapKey);
+
+	if (!_gp11_call_basic_finish (result, err))
+		return NULL;
+
+	*n_result = args->n_result;
+	args->n_result = 0;
+	ret = args->result;
+	args->result = NULL;
+
+	return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * KEY UNWRAPPING
+ */
+
+typedef struct _UnwrapKey {
+	GP11Arguments base;
+	GP11Mechanism *mechanism;
+	GP11Attributes *attrs;
+	CK_OBJECT_HANDLE wrapper;
+	gconstpointer input;
+	gulong n_input;
+	CK_OBJECT_HANDLE unwrapped;
+} UnwrapKey;
+
+static void
+free_unwrap_key (UnwrapKey *args)
+{
+	gp11_mechanism_unref (args->mechanism);
+	gp11_attributes_unref (args->attrs);
+	g_free (args);
+}
+
+static CK_RV
+perform_unwrap_key (UnwrapKey *args)
+{
+	CK_ATTRIBUTE_PTR attrs;
+	CK_ULONG n_attrs;
+
+	g_assert (sizeof (CK_MECHANISM) == sizeof (GP11Mechanism));
+
+	attrs = _gp11_attributes_commit_out (args->attrs, &n_attrs);
+
+	return (args->base.pkcs11->C_UnwrapKey) (args->base.handle,
+	                                         (CK_MECHANISM_PTR)args->mechanism,
+	                                         args->wrapper, (CK_BYTE_PTR)args->input,
+	                                         args->n_input, attrs, n_attrs,
+	                                         &args->unwrapped);
+}
+
+/**
+ * gp11_session_unwrap_key:
+ * @self: The session to use.
+ * @wrapper: The key to use for unwrapping.
+ * @mech_type: The mechanism type to use for derivation.
+ * @input: The wrapped data as a byte stream.
+ * @n_input: The length of the wrapped data.
+ * @err: A location to return an error, or NULL.
+ * @...: Additional attributes for the unwrapped key.
+ *
+ * Unwrap a key from a byte stream. This call may block for an
+ * indefinite period.
+ *
+ * The arguments must be triples of: attribute type, data type, value
+ *
+ * <para>The variable argument list should contain:
+ * 	<variablelist>
+ *		<varlistentry>
+ * 			<term>a)</term>
+ * 			<listitem><para>The gulong attribute type (ie: CKA_LABEL). </para></listitem>
+ * 		</varlistentry>
+ * 		<varlistentry>
+ * 			<term>b)</term>
+ * 			<listitem><para>The attribute data type (one of GP11_BOOLEAN, GP11_ULONG,
+ * 				GP11_STRING, GP11_DATE) orthe raw attribute value length.</para></listitem>
+ * 		</varlistentry>
+ * 		<varlistentry>
+ * 			<term>c)</term>
+ * 			<listitem><para>The attribute value, either a gboolean, gulong, gchar*, GDate* or
+ * 				a pointer to a raw attribute value.</para></listitem>
+ * 		</varlistentry>
+ * 	</variablelist>
+ * The variable argument list should be terminated with GP11_INVALID.</para>
+ *
+ * Return value: The new unwrapped key or NULL if the operation failed.
+ **/
+GP11Object*
+gp11_session_unwrap_key (GP11Session *self, GP11Object *key, gulong mech_type,
+                         gconstpointer input, gsize n_input, GError **err, ...)
+{
+	GP11Mechanism mech = { mech_type, NULL, 0 };
+	GP11Attributes *attrs;
+	GP11Object *object;
+	va_list va;
+
+	va_start (va, err);
+	attrs = gp11_attributes_new_valist (g_realloc, va);
+	va_end (va);
+
+	object = gp11_session_unwrap_key_full (self, key, &mech, input, n_input, attrs, NULL, err);
+	gp11_attributes_unref (attrs);
+	return object;
+}
+
+/**
+ * gp11_session_unwrap_key_full:
+ * @self: The session to use.
+ * @wrapper: The key to use for unwrapping.
+ * @mechanism: The mechanism to use for unwrapping.
+ * @input: The wrapped data as a byte stream.
+ * @n_input: The length of the wrapped data.
+ * @attrs: Additional attributes for the unwrapped key.
+ * @cancellable: Optional cancellation object, or NULL.
+ * @err: A location to return an error, or NULL.
+ *
+ * Unwrap a key from a byte stream. This call may block for an
+ * indefinite period.
+ *
+ * Return value: The new unwrapped key or NULL if the operation failed.
+ **/
+GP11Object*
+gp11_session_unwrap_key_full (GP11Session *self, GP11Object *wrapper, GP11Mechanism *mechanism,
+                              gconstpointer input, gsize n_input, GP11Attributes *attrs,
+                              GCancellable *cancellable, GError **err)
+{
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	UnwrapKey args = { GP11_ARGUMENTS_INIT, mechanism, attrs, 0, input, n_input, 0 };
+	gboolean ret;
+
+	g_return_val_if_fail (GP11_IS_SESSION (self), FALSE);
+	g_return_val_if_fail (GP11_IS_OBJECT (wrapper), FALSE);
+	g_return_val_if_fail (mechanism, FALSE);
+	g_return_val_if_fail (attrs, FALSE);
+
+	g_object_get (wrapper, "handle", &args.wrapper, NULL);
+	g_return_val_if_fail (args.wrapper != 0, NULL);
+
+	_gp11_attributes_lock (attrs);
+	ret = _gp11_call_sync (self, perform_unwrap_key, NULL, &args, cancellable, err);
+	_gp11_attributes_unlock (attrs);
+
+	if (!ret)
+		return NULL;
+
+	return gp11_object_from_handle (data->slot, args.unwrapped);
+}
+
+/**
+ * gp11_session_unwrap_key_async:
+ * @self: The session to use.
+ * @wrapper: The key to use for unwrapping.
+ * @mechanism: The mechanism to use for unwrapping.
+ * @input: The wrapped data as a byte stream.
+ * @n_input: The length of the wrapped data.
+ * @attrs: Additional attributes for the unwrapped key.
+ * @cancellable: Optional cancellation object or NULL.
+ * @callback: Called when the operation completes.
+ * @user_data: Data to pass to the callback.
+ *
+ * Unwrap a key from a byte stream. This call will
+ * return immediately and complete asynchronously.
+ **/
+void
+gp11_session_unwrap_key_async (GP11Session *self, GP11Object *wrapper, GP11Mechanism *mechanism,
+                               gconstpointer input, gsize n_input, GP11Attributes *attrs,
+                               GCancellable *cancellable, GAsyncReadyCallback callback,
+                               gpointer user_data)
+{
+	UnwrapKey *args = _gp11_call_async_prep (self, self, perform_unwrap_key,
+	                                         NULL, sizeof (*args), free_unwrap_key);
+
+	g_return_if_fail (GP11_IS_SESSION (self));
+	g_return_if_fail (GP11_IS_OBJECT (wrapper));
+	g_return_if_fail (attrs);
+
+	g_object_get (wrapper, "handle", &args->wrapper, NULL);
+	g_return_if_fail (args->wrapper != 0);
+
+	args->mechanism = gp11_mechanism_ref (mechanism);
+	args->attrs = gp11_attributes_ref (attrs);
+	args->input = input;
+	args->n_input = n_input;
+	_gp11_attributes_lock (attrs);
+
+	_gp11_call_async_ready_go (args, cancellable, callback, user_data);
+}
+
+/**
+ * gp11_session_wrap_key_finish:
+ * @self: The session to use.
+ * @result: The async result passed to the callback.
+ * @err: A location to return an error.
+ *
+ * Get the result of a unwrap key operation.
+ *
+ * Return value: The new unwrapped key or NULL if the operation failed.
+ **/
+GP11Object*
+gp11_session_unwrap_key_finish (GP11Session *self, GAsyncResult *result, GError **err)
+{
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	UnwrapKey *args;
+
+	g_return_val_if_fail (GP11_IS_SESSION (self), NULL);
+
+	args = _gp11_call_arguments (result, UnwrapKey);
+	_gp11_attributes_unlock (args->attrs);
+
+	if (!_gp11_call_basic_finish (result, err))
+		return NULL;
+	return gp11_object_from_handle (data->slot, args->unwrapped);
+}
+
+/* -----------------------------------------------------------------------------
+ * KEY DERIVATION
+ */
+
+typedef struct _DeriveKey {
+	GP11Arguments base;
+	GP11Mechanism *mechanism;
+	GP11Attributes *attrs;
+	CK_OBJECT_HANDLE key;
+	CK_OBJECT_HANDLE derived;
+} DeriveKey;
+
+static void
+free_derive_key (DeriveKey *args)
+{
+	gp11_mechanism_unref (args->mechanism);
+	gp11_attributes_unref (args->attrs);
+	g_free (args);
+}
+
+static CK_RV
+perform_derive_key (DeriveKey *args)
+{
+	CK_ATTRIBUTE_PTR attrs;
+	CK_ULONG n_attrs;
+
+	g_assert (sizeof (CK_MECHANISM) == sizeof (GP11Mechanism));
+
+	attrs = _gp11_attributes_commit_out (args->attrs, &n_attrs);
+
+	return (args->base.pkcs11->C_DeriveKey) (args->base.handle,
+	                                         (CK_MECHANISM_PTR)args->mechanism,
+	                                         args->key, attrs, n_attrs,
+	                                         &args->derived);
+}
+
+/**
+ * gp11_session_derive_key_full:
+ * @self: The session to use.
+ * @base: The key to derive from.
+ * @mech_type: The mechanism type to use for derivation.
+ * @err: A location to return an error, or NULL.
+ * @...: Additional attributes for the derived key.
+ *
+ * Derive a key from another key. This call may block for an
+ * indefinite period.
+ *
+ * The arguments must be triples of: attribute type, data type, value
+ *
+ * <para>The variable argument list should contain:
+ * 	<variablelist>
+ *		<varlistentry>
+ * 			<term>a)</term>
+ * 			<listitem><para>The gulong attribute type (ie: CKA_LABEL). </para></listitem>
+ * 		</varlistentry>
+ * 		<varlistentry>
+ * 			<term>b)</term>
+ * 			<listitem><para>The attribute data type (one of GP11_BOOLEAN, GP11_ULONG,
+ * 				GP11_STRING, GP11_DATE) orthe raw attribute value length.</para></listitem>
+ * 		</varlistentry>
+ * 		<varlistentry>
+ * 			<term>c)</term>
+ * 			<listitem><para>The attribute value, either a gboolean, gulong, gchar*, GDate* or
+ * 				a pointer to a raw attribute value.</para></listitem>
+ * 		</varlistentry>
+ * 	</variablelist>
+ * The variable argument list should be terminated with GP11_INVALID.</para>
+ *
+ * Return value: The new derived key or NULL if the operation failed.
+ **/
+GP11Object*
+gp11_session_derive_key (GP11Session *self, GP11Object *key, gulong mech_type,
+                         GError **err, ...)
+{
+	GP11Mechanism mech = { mech_type, NULL, 0 };
+	GP11Attributes *attrs;
+	GP11Object *object;
+	va_list va;
+
+	va_start (va, err);
+	attrs = gp11_attributes_new_valist (g_realloc, va);
+	va_end (va);
+
+	object = gp11_session_derive_key_full (self, key, &mech, attrs, NULL, err);
+	gp11_attributes_unref (attrs);
+	return object;
+}
+
+/**
+ * gp11_session_derive_key_full:
+ * @self: The session to use.
+ * @base: The key to derive from.
+ * @mechanism: The mechanism to use for derivation.
+ * @attrs: Additional attributes for the derived key.
+ * @cancellable: Optional cancellation object, or NULL.
+ * @err: A location to return an error, or NULL.
+ *
+ * Derive a key from another key. This call may block for an
+ * indefinite period.
+ *
+ * Return value: The new derived key or NULL if the operation failed.
+ **/
+GP11Object*
+gp11_session_derive_key_full (GP11Session *self, GP11Object *base, GP11Mechanism *mechanism,
+                              GP11Attributes *attrs, GCancellable *cancellable, GError **err)
+{
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	DeriveKey args = { GP11_ARGUMENTS_INIT, mechanism, attrs, 0, 0 };
+	gboolean ret;
+
+	g_return_val_if_fail (GP11_IS_SESSION (self), FALSE);
+	g_return_val_if_fail (GP11_IS_OBJECT (base), FALSE);
+	g_return_val_if_fail (mechanism, FALSE);
+	g_return_val_if_fail (attrs, FALSE);
+
+	g_object_get (base, "handle", &args.key, NULL);
+	g_return_val_if_fail (args.key != 0, NULL);
+
+	_gp11_attributes_lock (attrs);
+	ret = _gp11_call_sync (self, perform_derive_key, NULL, &args, cancellable, err);
+	_gp11_attributes_unlock (attrs);
+
+	if (!ret)
+		return NULL;
+
+	return gp11_object_from_handle (data->slot, args.derived);
+}
+
+/**
+ * gp11_session_derive_key_async:
+ * @self: The session to use.
+ * @base: The key to derive from.
+ * @mechanism: The mechanism to use for derivation.
+ * @attrs: Additional attributes for the derived key.
+ * @cancellable: Optional cancellation object or NULL.
+ * @callback: Called when the operation completes.
+ * @user_data: Data to pass to the callback.
+ *
+ * Derive a key from another key. This call will
+ * return immediately and complete asynchronously.
+ **/
+void
+gp11_session_derive_key_async (GP11Session *self, GP11Object *base, GP11Mechanism *mechanism,
+                               GP11Attributes *attrs, GCancellable *cancellable,
+                               GAsyncReadyCallback callback, gpointer user_data)
+{
+	DeriveKey *args = _gp11_call_async_prep (self, self, perform_derive_key,
+	                                         NULL, sizeof (*args), free_derive_key);
+
+	g_return_if_fail (GP11_IS_SESSION (self));
+	g_return_if_fail (GP11_IS_OBJECT (base));
+	g_return_if_fail (attrs);
+
+	g_object_get (base, "handle", &args->key, NULL);
+	g_return_if_fail (args->key != 0);
+
+	args->mechanism = gp11_mechanism_ref (mechanism);
+	args->attrs = gp11_attributes_ref (attrs);
+	_gp11_attributes_lock (attrs);
+
+	_gp11_call_async_ready_go (args, cancellable, callback, user_data);
+}
+
+/**
+ * gp11_session_wrap_key_finish:
+ * @self: The session to use.
+ * @result: The async result passed to the callback.
+ * @err: A location to return an error.
+ *
+ * Get the result of a derive key operation.
+ *
+ * Return value: The new derived key or NULL if the operation failed.
+ **/
+GP11Object*
+gp11_session_derive_key_finish (GP11Session *self, GAsyncResult *result, GError **err)
+{
+	GP11SessionData *data = GP11_SESSION_GET_DATA (self);
+	DeriveKey *args;
+
+	g_return_val_if_fail (GP11_IS_SESSION (self), NULL);
+
+	args = _gp11_call_arguments (result, DeriveKey);
+	_gp11_attributes_unlock (args->attrs);
+
+	if (!_gp11_call_basic_finish (result, err))
+		return NULL;
+
+	return gp11_object_from_handle (data->slot, args->derived);
+}
+
 /* --------------------------------------------------------------------------------------------------
  * AUTHENTICATE 
  */
@@ -1227,7 +1957,7 @@ typedef struct _Crypt {
 	
 	/* Input */
 	CK_OBJECT_HANDLE key;
-	CK_MECHANISM mech;
+	GP11Mechanism *mech;
 	guchar *input;
 	CK_ULONG n_input;
 	
@@ -1249,7 +1979,7 @@ perform_crypt (Crypt *args)
 	g_assert (!args->n_result);
 	
 	/* Initialize the crypt operation */
-	rv = (args->init_func) (args->base.handle, &args->mech, args->key);
+	rv = (args->init_func) (args->base.handle, (CK_MECHANISM_PTR)args->mech, args->key);
 	if (rv != CKR_OK)
 		return rv;
 	
@@ -1281,13 +2011,13 @@ static void
 free_crypt (Crypt *args)
 {
 	g_free (args->input);
-	g_free (args->mech.pParameter);
+	gp11_mechanism_unref (args->mech);
 	g_free (args->result);
 	g_free (args);
 }
 
 static guchar*
-crypt_sync (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args, const guchar *input, 
+crypt_sync (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism, const guchar *input,
             gsize n_input, gsize *n_result, GCancellable *cancellable, GError **err,
             CK_C_EncryptInit init_func, CK_C_Encrypt complete_func)
 {
@@ -1295,18 +2025,16 @@ crypt_sync (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args, const
 	GP11Slot *slot;
 
 	g_return_val_if_fail (GP11_IS_OBJECT (key), NULL);
-	g_return_val_if_fail (mech_args, NULL);
+	g_return_val_if_fail (mechanism, NULL);
 	g_return_val_if_fail (init_func, NULL);
 	g_return_val_if_fail (complete_func, NULL);
 
 	memset (&args, 0, sizeof (args));
 	g_object_get (key, "handle", &args.key, NULL);
 	g_return_val_if_fail (args.key != 0, NULL);
-	
-	args.mech.mechanism = mech_args->type;
-	args.mech.pParameter = mech_args->parameter;
-	args.mech.ulParameterLen = mech_args->n_parameter;
-	
+
+	args.mech = mechanism;
+
 	/* No need to copy in this case */
 	args.input = (guchar*)input;
 	args.n_input = n_input;
@@ -1328,7 +2056,7 @@ crypt_sync (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args, const
 }
 
 static void
-crypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args, const guchar *input, 
+crypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism, const guchar *input,
              gsize n_input, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data,
              CK_C_EncryptInit init_func, CK_C_Encrypt complete_func)
 {
@@ -1336,18 +2064,15 @@ crypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args, const
 	GP11Slot *slot;
 
 	g_return_if_fail (GP11_IS_OBJECT (key));
-	g_return_if_fail (mech_args);
+	g_return_if_fail (mechanism);
 	g_return_if_fail (init_func);
 	g_return_if_fail (complete_func);
 	
 	g_object_get (key, "handle", &args->key, NULL);
 	g_return_if_fail (args->key != 0);
 
-	args->mech.mechanism = mech_args->type;
-	args->mech.pParameter = mech_args->parameter && mech_args->n_parameter ? 
-	                                   g_memdup (mech_args->parameter, mech_args->n_parameter) : NULL;
-	args->mech.ulParameterLen = mech_args->n_parameter;
-	
+	args->mech = gp11_mechanism_ref (mechanism);
+
 	args->input = input && n_input ? g_memdup (input, n_input) : NULL;
 	args->n_input = n_input;
 	
@@ -1403,15 +2128,15 @@ guchar*
 gp11_session_encrypt (GP11Session *self, GP11Object *key, gulong mech_type, const guchar *input, 
                       gsize n_input, gsize *n_result, GError **err)
 {
-	GP11Mechanism mech_args = { mech_type, NULL, 0 };
-	return gp11_session_encrypt_full (self, key, &mech_args, input, n_input, n_result, NULL, err);
+	GP11Mechanism mechanism = { mech_type, NULL, 0 };
+	return gp11_session_encrypt_full (self, key, &mechanism, input, n_input, n_result, NULL, err);
 }
 
 /**
  * gp11_session_encrypt_full:
  * @self: The session.
  * @key: The key to encrypt with.
- * @mech_args: The mechanism type and parameters to use for encryption.
+ * @mechanism: The mechanism type and parameters to use for encryption.
  * @input: The data to encrypt.
  * @n_input: The length of the data to encrypt.
  * @n_result: A location to store the length of the result data.
@@ -1424,7 +2149,7 @@ gp11_session_encrypt (GP11Session *self, GP11Object *key, gulong mech_type, cons
  * Returns: The data that was encrypted, or NULL if an error occured.
  */
 guchar*
-gp11_session_encrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_encrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
                            const guchar *input, gsize n_input, gsize *n_result,
                            GCancellable *cancellable, GError **err)
 {
@@ -1438,7 +2163,7 @@ gp11_session_encrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *me
 	funcs = gp11_module_get_functions (module);
 	g_return_val_if_fail (module != NULL, NULL);
 
-	ret = crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err, 
+	ret = crypt_sync (self, key, mechanism, input, n_input, n_result, cancellable, err,
 	                  funcs->C_EncryptInit, funcs->C_Encrypt);
 	
 	g_object_unref (module);
@@ -1449,7 +2174,7 @@ gp11_session_encrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *me
  * gp11_session_encrypt_async:
  * @self: The session.
  * @key: The key to encrypt with.
- * @mech_args: The mechanism type and parameters to use for encryption.
+ * @mechanism: The mechanism type and parameters to use for encryption.
  * @input: The data to encrypt.
  * @n_input: The length of the data to encrypt.
  * @cancellable: A GCancellable which can be used to cancel the operation.
@@ -1458,11 +2183,9 @@ gp11_session_encrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *me
  * 
  * Encrypt data in a mechanism specific manner. This call will 
  * return immediately and complete asynchronously.
- * 
- * Returns: The data that was encrypted.
- */
+ **/
 void
-gp11_session_encrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_encrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
                             const guchar *input, gsize n_input, GCancellable *cancellable,
                             GAsyncReadyCallback callback, gpointer user_data)
 {
@@ -1475,7 +2198,7 @@ gp11_session_encrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *m
 	funcs = gp11_module_get_functions (module);
 	g_return_if_fail (module != NULL);
 
-	crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data,
+	crypt_async (self, key, mechanism, input, n_input, cancellable, callback, user_data,
 	             funcs->C_EncryptInit, funcs->C_Encrypt);
 	
 	g_object_unref (module);
@@ -1522,15 +2245,15 @@ guchar*
 gp11_session_decrypt (GP11Session *self, GP11Object *key, gulong mech_type, const guchar *input,
                       gsize n_input, gsize *n_result, GError **err)
 {
-	GP11Mechanism mech_args = { mech_type, NULL, 0 };
-	return gp11_session_decrypt_full (self, key, &mech_args, input, n_input, n_result, NULL, err);
+	GP11Mechanism mechanism = { mech_type, NULL, 0 };
+	return gp11_session_decrypt_full (self, key, &mechanism, input, n_input, n_result, NULL, err);
 }
 
 /**
  * gp11_session_decrypt_full:
  * @self: The session.
  * @key: The key to decrypt with.
- * @mech_args: The mechanism type and parameters to use for decryption.
+ * @mechanism: The mechanism type and parameters to use for decryption.
  * @input: The data to decrypt.
  * @n_input: The length of the data to decrypt.
  * @n_result: A location to store the length of the result data.
@@ -1543,7 +2266,7 @@ gp11_session_decrypt (GP11Session *self, GP11Object *key, gulong mech_type, cons
  * Returns: The data that was decrypted, or NULL if an error occured.
  */
 guchar*
-gp11_session_decrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_decrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
                            const guchar *input, gsize n_input, gsize *n_result,
                            GCancellable *cancellable, GError **err)
 {
@@ -1557,7 +2280,7 @@ gp11_session_decrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *me
 	funcs = gp11_module_get_functions (module);
 	g_return_val_if_fail (module != NULL, NULL);
 
-	ret = crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err,
+	ret = crypt_sync (self, key, mechanism, input, n_input, n_result, cancellable, err,
 	                  funcs->C_DecryptInit, funcs->C_Decrypt);
 	g_object_unref (module);
 	return ret;
@@ -1567,7 +2290,7 @@ gp11_session_decrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *me
  * gp11_session_decrypt_async:
  * @self: The session.
  * @key: The key to decrypt with.
- * @mech_args: The mechanism type and parameters to use for decryption.
+ * @mechanism: The mechanism type and parameters to use for decryption.
  * @input: The data to decrypt.
  * @n_input: The length of the data to decrypt.
  * @cancellable: A GCancellable which can be used to cancel the operation.
@@ -1576,11 +2299,9 @@ gp11_session_decrypt_full (GP11Session *self, GP11Object *key, GP11Mechanism *me
  * 
  * Decrypt data in a mechanism specific manner. This call will 
  * return immediately and complete asynchronously.
- * 
- * Returns: The data that was decrypted.
  */
 void
-gp11_session_decrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_decrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
                             const guchar *input, gsize n_input, GCancellable *cancellable,
                             GAsyncReadyCallback callback, gpointer user_data)
 {
@@ -1593,7 +2314,7 @@ gp11_session_decrypt_async (GP11Session *self, GP11Object *key, GP11Mechanism *m
 	funcs = gp11_module_get_functions (module);
 	g_return_if_fail (module != NULL);
 
-	crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data,
+	crypt_async (self, key, mechanism, input, n_input, cancellable, callback, user_data,
 	             funcs->C_DecryptInit, funcs->C_Decrypt);
 	g_object_unref (module);
 }
@@ -1639,15 +2360,15 @@ guchar*
 gp11_session_sign (GP11Session *self, GP11Object *key, gulong mech_type, const guchar *input, 
                    gsize n_input, gsize *n_result, GError **err)
 {
-	GP11Mechanism mech_args = { mech_type, NULL, 0 };
-	return gp11_session_sign_full (self, key, &mech_args, input, n_input, n_result, NULL, err);
+	GP11Mechanism mechanism = { mech_type, NULL, 0 };
+	return gp11_session_sign_full (self, key, &mechanism, input, n_input, n_result, NULL, err);
 }
 
 /**
  * gp11_session_sign_full:
  * @self: The session.
  * @key: The key to sign with.
- * @mech_args: The mechanism type and parameters to use for signing.
+ * @mechanism: The mechanism type and parameters to use for signing.
  * @input: The data to sign.
  * @n_input: The length of the data to sign.
  * @n_result: A location to store the length of the result data.
@@ -1660,7 +2381,7 @@ gp11_session_sign (GP11Session *self, GP11Object *key, gulong mech_type, const g
  * Returns: The data that was signed, or NULL if an error occured.
  */
 guchar*
-gp11_session_sign_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_sign_full (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
                         const guchar *input, gsize n_input, gsize *n_result,
                         GCancellable *cancellable, GError **err)
 {
@@ -1674,7 +2395,7 @@ gp11_session_sign_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_
 	funcs = gp11_module_get_functions (module);
 	g_return_val_if_fail (module != NULL, NULL);
 
-	ret = crypt_sync (self, key, mech_args, input, n_input, n_result, cancellable, err,
+	ret = crypt_sync (self, key, mechanism, input, n_input, n_result, cancellable, err,
 	                  funcs->C_SignInit, funcs->C_Sign);
 	g_object_unref (module);
 	return ret;
@@ -1684,7 +2405,7 @@ gp11_session_sign_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_
  * gp11_session_sign_async:
  * @self: The session.
  * @key: The key to sign with.
- * @mech_args: The mechanism type and parameters to use for signing.
+ * @mechanism: The mechanism type and parameters to use for signing.
  * @input: The data to sign.
  * @n_input: The length of the data to sign.
  * @cancellable: A GCancellable which can be used to cancel the operation.
@@ -1693,11 +2414,9 @@ gp11_session_sign_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_
  * 
  * Sign data in a mechanism specific manner. This call will 
  * return immediately and complete asynchronously.
- * 
- * Returns: The data that was signed.
  */
 void
-gp11_session_sign_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_sign_async (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
                          const guchar *input, gsize n_input, GCancellable *cancellable,
                          GAsyncReadyCallback callback, gpointer user_data)
 {
@@ -1710,7 +2429,7 @@ gp11_session_sign_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech
 	funcs = gp11_module_get_functions (module);
 	g_return_if_fail (module != NULL);
 
-	crypt_async (self, key, mech_args, input, n_input, cancellable, callback, user_data,
+	crypt_async (self, key, mechanism, input, n_input, cancellable, callback, user_data,
 	             funcs->C_SignInit, funcs->C_Sign);
 	g_object_unref (module);
 }
@@ -1745,7 +2464,7 @@ typedef struct _Verify {
 
 	/* Input */
 	CK_OBJECT_HANDLE key;
-	CK_MECHANISM mech;
+	GP11Mechanism *mech;
 	guchar *input;
 	CK_ULONG n_input;
 	guchar *signature;
@@ -1759,7 +2478,7 @@ perform_verify (Verify *args)
 	CK_RV rv;
 	
 	/* Initialize the crypt operation */
-	rv = (args->base.pkcs11->C_VerifyInit) (args->base.handle, &args->mech, args->key);
+	rv = (args->base.pkcs11->C_VerifyInit) (args->base.handle, (CK_MECHANISM_PTR)args->mech, args->key);
 	if (rv != CKR_OK)
 		return rv;
 	
@@ -1787,7 +2506,7 @@ free_verify (Verify *args)
 {
 	g_free (args->input);
 	g_free (args->signature);
-	g_free (args->mech.pParameter);
+	gp11_mechanism_unref (args->mech);
 	g_free (args);
 }
 
@@ -1811,8 +2530,8 @@ gboolean
 gp11_session_verify (GP11Session *self, GP11Object *key, gulong mech_type, const guchar *input,
                      gsize n_input, const guchar *signature, gsize n_signature, GError **err)
 {
-	GP11Mechanism mech_args = { mech_type, NULL, 0 };
-	return gp11_session_verify_full (self, key, &mech_args, input, n_input, 
+	GP11Mechanism mechanism = { mech_type, NULL, 0 };
+	return gp11_session_verify_full (self, key, &mechanism, input, n_input,
 	                                 signature, n_signature, NULL, err);	
 }
 
@@ -1820,7 +2539,7 @@ gp11_session_verify (GP11Session *self, GP11Object *key, gulong mech_type, const
  * gp11_session_verify_full:
  * @self: The session.
  * @key: The key to verify with.
- * @mech_args: The mechanism type and parameters to use for signing.
+ * @mechanism: The mechanism type and parameters to use for signing.
  * @input: The data to verify.
  * @n_input: The length of the data to verify.
  * @signature: The signature.
@@ -1834,7 +2553,7 @@ gp11_session_verify (GP11Session *self, GP11Object *key, gulong mech_type, const
  * Returns: TRUE if the data verified correctly, otherwise a failure or error occurred.
  */
 gboolean
-gp11_session_verify_full (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_verify_full (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
                           const guchar *input, gsize n_input, const guchar *signature,
                           gsize n_signature, GCancellable *cancellable, GError **err)
 {
@@ -1842,16 +2561,14 @@ gp11_session_verify_full (GP11Session *self, GP11Object *key, GP11Mechanism *mec
 	GP11Slot *slot;
 	
 	g_return_val_if_fail (GP11_IS_OBJECT (key), FALSE);
-	g_return_val_if_fail (mech_args, FALSE);
+	g_return_val_if_fail (mechanism, FALSE);
 
 	memset (&args, 0, sizeof (args));
 	g_object_get (key, "handle", &args.key, NULL);
 	g_return_val_if_fail (args.key != 0, FALSE);
-	
-	args.mech.mechanism = mech_args->type;
-	args.mech.pParameter = mech_args->parameter;
-	args.mech.ulParameterLen = mech_args->n_parameter;
-	
+
+	args.mech = mechanism;
+
 	/* No need to copy in this case */
 	args.input = (guchar*)input;
 	args.n_input = n_input;
@@ -1869,7 +2586,7 @@ gp11_session_verify_full (GP11Session *self, GP11Object *key, GP11Mechanism *mec
  * gp11_session_verify_async:
  * @self: The session.
  * @key: The key to verify with.
- * @mech_args: The mechanism type and parameters to use for signing.
+ * @mechanism: The mechanism type and parameters to use for signing.
  * @input: The data to verify.
  * @n_input: The length of the data to verify.
  * @signature: The signature.
@@ -1882,7 +2599,7 @@ gp11_session_verify_full (GP11Session *self, GP11Object *key, GP11Mechanism *mec
  * immediately and completes asynchronously.
  */
 void
-gp11_session_verify_async (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args,
+gp11_session_verify_async (GP11Session *self, GP11Object *key, GP11Mechanism *mechanism,
                            const guchar *input, gsize n_input, const guchar *signature,
                            gsize n_signature, GCancellable *cancellable,
                            GAsyncReadyCallback callback, gpointer user_data)
@@ -1891,16 +2608,13 @@ gp11_session_verify_async (GP11Session *self, GP11Object *key, GP11Mechanism *me
 	GP11Slot *slot;
 	
 	g_return_if_fail (GP11_IS_OBJECT (key));
-	g_return_if_fail (mech_args);
+	g_return_if_fail (mechanism);
 	
 	g_object_get (key, "handle", &args->key, NULL);
 	g_return_if_fail (args->key != 0);
 
-	args->mech.mechanism = mech_args->type;
-	args->mech.pParameter = mech_args->parameter && mech_args->n_parameter ? 
-	                                   g_memdup (mech_args->parameter, mech_args->n_parameter) : NULL;
-	args->mech.ulParameterLen = mech_args->n_parameter;
-	
+	args->mech = gp11_mechanism_ref (mechanism);
+
 	args->input = input && n_input ? g_memdup (input, n_input) : NULL;
 	args->n_input = n_input;
 	args->signature = signature && n_signature ? g_memdup (signature, n_signature) : NULL;
diff --git a/gp11/gp11.h b/gp11/gp11.h
index 3cd9f37..009ef38 100644
--- a/gp11/gp11.h
+++ b/gp11/gp11.h
@@ -57,6 +57,16 @@ typedef struct GP11Mechanism {
 	gulong n_parameter;
 } GP11Mechanism;
 
+GP11Mechanism*      gp11_mechanism_new                      (gulong type);
+
+GP11Mechanism*      gp11_mechanism_new_with_param           (gulong type,
+                                                             gconstpointer parameter,
+                                                             gulong n_parameter);
+
+GP11Mechanism*      gp11_mechanism_ref                      (GP11Mechanism* mech);
+
+void                gp11_mechanism_unref                    (GP11Mechanism* mech);
+
 typedef struct GP11Attribute {
 	gulong type;
 	guchar *value;
@@ -714,25 +724,32 @@ GP11Object*         gp11_session_generate_key_finish        (GP11Session *self,
                                                              GError **err,
                                                              ...) GP11_INVALID_TERMINATED;
 
-gboolean            gp11_session_generate_key_pair          (GP11Session *self,
+#endif /* UNIMPLEMENTED */
+
+gboolean            gp11_session_generate_key_pair_full     (GP11Session *self,
                                                              GP11Mechanism *mechanism,
+                                                             GP11Attributes *public_attrs,
+                                                             GP11Attributes *private_attrs,
                                                              GP11Object **public_key,
                                                              GP11Object **private_key,
-                                                             GError **err,
-                                                             ...) GP11_INVALID_TERMINATED;
+                                                             GCancellable *cancellable,
+                                                             GError **err);
 
 void                gp11_session_generate_key_pair_async    (GP11Session *self,
                                                              GP11Mechanism *mechanism,
+                                                             GP11Attributes *public_attrs,
+                                                             GP11Attributes *private_attrs,
+                                                             GCancellable *cancellable,
                                                              GAsyncReadyCallback callback,
-                                                             gpointer user_data,
-                                                             ...) GP11_INVALID_TERMINATED;
+                                                             gpointer user_data);
 
 gboolean            gp11_session_generate_key_pair_finish   (GP11Session *self,
                                                              GAsyncResult *result,
                                                              GP11Object **public_key,
                                                              GP11Object **private_key,
-                                                             GError **err,
-                                                             ...) GP11_INVALID_TERMINATED;
+                                                             GError **err);
+
+#ifdef UNIMPLEMENTED
 
 gboolean            gp11_session_seed_random                (GP11Session *self,
                                                              const guchar *seed,
@@ -774,7 +791,7 @@ guchar*             gp11_session_encrypt                     (GP11Session *self,
 
 guchar*             gp11_session_encrypt_full                (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               gsize *n_result,
@@ -783,7 +800,7 @@ guchar*             gp11_session_encrypt_full                (GP11Session *self,
 
 void                gp11_session_encrypt_async               (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               GCancellable *cancellable,
@@ -799,13 +816,13 @@ guchar*             gp11_session_encrypt_finish              (GP11Session *self,
 
 GP11Processor*      gp11_session_batch_encrypt               (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               GCancellable *cancellable,
                                                               GError **err);
 
 void                gp11_session_batch_encrypt_async         (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               GCancellable *cancellable,
                                                               GAsyncReadyCallback callback,
                                                               gpointer user_data);
@@ -827,7 +844,7 @@ guchar*             gp11_session_decrypt                     (GP11Session *self,
 
 guchar*             gp11_session_decrypt_full                (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               gsize *n_result,
@@ -836,7 +853,7 @@ guchar*             gp11_session_decrypt_full                (GP11Session *self,
 
 void                gp11_session_decrypt_async               (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               GCancellable *cancellable,
@@ -852,13 +869,13 @@ guchar*             gp11_session_decrypt_finish              (GP11Session *self,
 
 GP11Processor*      gp11_session_batch_decrypt               (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               GCancellable *cancellable,
                                                               GError **err);
 
 void                gp11_session_batch_decrypt_async         (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               GCancellable *cancellable,
                                                               GAsyncReadyCallback callback,
                                                               gpointer user_data);
@@ -875,7 +892,7 @@ guchar*             gp11_session_digest                      (GP11Session *self,
                                                               GError **err);
 
 guchar*             gp11_session_digest_full                 (GP11Session *self,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               gsize *n_result,
@@ -883,7 +900,7 @@ guchar*             gp11_session_digest_full                 (GP11Session *self,
                                                               GError **err);
 
 void                gp11_session_digest_async                (GP11Session *self,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               GCancellable *cancellable,
@@ -896,12 +913,12 @@ guchar*             gp11_session_digest_finish               (GP11Session *self,
                                                               GError **err);
 
 GP11Processor*      gp11_session_batch_digest	             (GP11Session *self,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               GCancellable *cancellable,
                                                               GError **err);
 
 void                gp11_session_batch_digest_async          (GP11Session *self,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               GCancellable *cancellable,
                                                               GAsyncReadyCallback callback,
                                                               gpointer user_data);
@@ -979,7 +996,7 @@ guchar*             gp11_session_sign                        (GP11Session *self,
 
 guchar*             gp11_session_sign_full                   (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               gsize *n_result,
@@ -988,7 +1005,7 @@ guchar*             gp11_session_sign_full                   (GP11Session *self,
 
 void                gp11_session_sign_async                  (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               GCancellable *cancellable,
@@ -1004,13 +1021,13 @@ guchar*             gp11_session_sign_finish                 (GP11Session *self,
 
 GP11Processor*      gp11_session_batch_sign                  (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               GCancellable *cancellable,
                                                               GError **err);
 
 void                gp11_session_batch_sign_async            (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               GCancellable *cancellable,
                                                               GAsyncReadyCallback callback,
                                                               gpointer user_data);
@@ -1048,7 +1065,7 @@ guchar*             gp11_session_sign_recover                (GP11Session *self,
 
 guchar*             gp11_session_sign_recover_full           (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               gsize *n_result,
@@ -1057,7 +1074,7 @@ guchar*             gp11_session_sign_recover_full           (GP11Session *self,
 
 void                gp11_session_sign_recover_async          (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               GCancellable *cancellable,
@@ -1082,7 +1099,7 @@ gboolean            gp11_session_verify                      (GP11Session *self,
 
 gboolean            gp11_session_verify_full                 (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               const guchar *signature,
@@ -1118,7 +1135,7 @@ GkrProcessor*       gp11_session_batch_verify                (GP11Session *self,
 
 void                gp11_session_batch_verify_async          (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               GCancellable *cancellable,
@@ -1139,7 +1156,7 @@ guchar*             gp11_session_verify_recover              (GP11Session *self,
 
 guchar*             gp11_session_verify_recover_full         (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               gsize *n_result,
@@ -1148,7 +1165,7 @@ guchar*             gp11_session_verify_recover_full         (GP11Session *self,
 
 void                gp11_session_verify_recover_async        (GP11Session *self,
                                                               GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+                                                              GP11Mechanism *mechanism,
                                                               const guchar *input,
                                                               gsize n_input,
                                                               GCancellable *cancellable,
@@ -1160,93 +1177,92 @@ guchar*             gp11_session_verify_recover_finish       (GP11Session *self,
                                                               gsize *n_result,
                                                               GError **err);
 
-guchar*             gp11_session_wrap                        (GP11Session *self,
-                                                              GP11Object *key,
+#endif /* UNIMPLEMENTED */
+
+gpointer            gp11_session_wrap_key                    (GP11Session *self,
+                                                              GP11Object *wrapper,
                                                               gulong mech_type,
-                                                              GP11Object *wrapped_key,
+                                                              GP11Object *wrapped,
                                                               gsize *n_result,
                                                               GError **err);
 
-guchar*             gp11_session_wrap                        (GP11Session *self,
-                                                              GP11Object *key,
-                                                              GP11Mechanism *mech_args,
-                                                              GP11Object *wrapped_key,
+gpointer            gp11_session_wrap_key_full               (GP11Session *self,
+                                                              GP11Object *wrapper,
+                                                              GP11Mechanism *mechanism,
+                                                              GP11Object *wrapped,
                                                               gsize *n_result,
                                                               GCancellable *cancellable,
                                                               GError **err);
 
-void                gp11_session_wrap_async                  (GP11Session *self,
-                                                              GP11Object *key,
-                                                              GP11Mechanism *mech_args,
-                                                              GP11Object *wrapped_key,
+void                gp11_session_wrap_key_async              (GP11Session *self,
+                                                              GP11Object *wrapper,
+                                                              GP11Mechanism *mechanism,
+                                                              GP11Object *wrapped,
                                                               GCancellable *cancellable,
                                                               GAsyncReadyCallback callback,
                                                               gpointer user_data);
 
-guchar*             gp11_session_wrap_finish                 (GP11Session *self,
+gpointer            gp11_session_wrap_key_finish             (GP11Session *self,
                                                               GAsyncResult *result,
                                                               gsize *n_result,
                                                               GError **err);
 
-GP11Object*         gp11_session_unwrap                      (GP11Session *self,
-                                                              GP11Object *key,
+GP11Object*         gp11_session_unwrap_key                  (GP11Session *self,
+                                                              GP11Object *wrapper,
                                                               gulong mech_type,
-                                                              const guchar *input,
+                                                              gconstpointer input,
                                                               gsize n_input,
                                                               GError **err,
                                                               ...) GP11_INVALID_TERMINATED;
 
-GP11Object*         gp11_session_unwrap                      (GP11Session *self,
-                                                              GP11Object *key,
-                                                              GP11Mechanism *mech_args,
-                                                              const guchar *input,
+GP11Object*         gp11_session_unwrap_key_full             (GP11Session *self,
+                                                              GP11Object *wrapper,
+                                                              GP11Mechanism *mechanism,
+                                                              gconstpointer input,
                                                               gsize n_input,
+                                                              GP11Attributes *attrs,
                                                               GCancellable *cancellable,
-                                                              GError **err,
-                                                              ...) GP11_INVALID_TERMINATED;
+                                                              GError **err);
 
-void                gp11_session_unwrap_async                (GP11Session *self,
-                                                              GP11Object *key,
-                                                              GP11Mechanism *mech_args,
-                                                              const guchar *input,
+void                gp11_session_unwrap_key_async            (GP11Session *self,
+                                                              GP11Object *wrapper,
+                                                              GP11Mechanism *mechanism,
+                                                              gconstpointer input,
                                                               gsize n_input,
+                                                              GP11Attributes *attrs,
                                                               GCancellable *cancellable,
                                                               GAsyncReadyCallback callback,
                                                               gpointer user_data);
-                                                              ...) GP11_INVALID_TERMINATED;
 
-GP11Object*         gp11_session_unwrap_finish               (GP11Session *self,
+GP11Object*         gp11_session_unwrap_key_finish           (GP11Session *self,
                                                               GAsyncResult *result,
                                                               GError **err);
 
-GP11Object*         gp11_session_derive                      (GP11Session *self,
-                                                              GP11Object *key,
+GP11Object*         gp11_session_derive_key                  (GP11Session *self,
+                                                              GP11Object *base,
                                                               gulong mech_type,
                                                               GError **err,
                                                               ...) GP11_INVALID_TERMINATED;
 
-GP11Object*         gp11_session_derive_full                 (GP11Session *self,
-                                                              GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+GP11Object*         gp11_session_derive_key_full             (GP11Session *self,
+                                                              GP11Object *base,
+                                                              GP11Mechanism *mechanism,
+                                                              GP11Attributes *attrs,
                                                               GCancellable *cancellable,
-                                                              GError **err,
-                                                              ...) GP11_INVALID_TERMINATED;
+                                                              GError **err);
 
-void                gp11_session_derive_async                (GP11Session *self,
-                                                              GP11Object *key,
-                                                              GP11Mechanism *mech_args,
+void                gp11_session_derive_key_async            (GP11Session *self,
+                                                              GP11Object *base,
+                                                              GP11Mechanism *mechanism,
+                                                              GP11Attributes *attrs,
                                                               GCancellable *cancellable,
                                                               GAsyncReadyCallback callback,
                                                               gpointer user_data);
-                                                              ...) GP11_INVALID_TERMINATED;
 
-GP11Object*         gp11_session_derive_finish               (GP11Session *self,
+GP11Object*         gp11_session_derive_key_finish           (GP11Session *self,
                                                               GAsyncResult *result,
                                                               GError **err);
 
-#endif /* UNIMPLEMENTED */
-
-
 /* ------------------------------------------------------------------------
  * OBJECT
  */
diff --git a/gp11/tests/Makefile.am b/gp11/tests/Makefile.am
index 6cd06fb..9b0b4c1 100644
--- a/gp11/tests/Makefile.am
+++ b/gp11/tests/Makefile.am
@@ -2,6 +2,7 @@
 # Keep these in the order they should be tested
 UNIT_AUTO = \
 	unit-test-gp11-attributes.c \
+	test-gp11-mechanism.c \
 	unit-test-gp11-module.c \
 	unit-test-gp11-slot.c \
 	unit-test-gp11-session.c \
diff --git a/gp11/tests/gp11-test-module.c b/gp11/tests/gp11-test-module.c
index b4ff426..41980b7 100644
--- a/gp11/tests/gp11-test-module.c
+++ b/gp11/tests/gp11-test-module.c
@@ -75,6 +75,16 @@ free_session (gpointer data)
 	g_free (sess);
 }
 
+static GP11Attributes*
+lookup_object (Session *session, CK_OBJECT_HANDLE hObject)
+{
+	GP11Attributes *attrs;
+	attrs = g_hash_table_lookup (the_objects, GUINT_TO_POINTER (hObject));
+	if (!attrs)
+		attrs = g_hash_table_lookup (session->objects, GUINT_TO_POINTER (hObject));
+	return attrs;
+}
+
 static CK_RV
 test_C_Initialize (CK_VOID_PTR pInitArgs)
 {
@@ -136,6 +146,10 @@ test_C_Initialize (CK_VOID_PTR pInitArgs)
 	                              CKA_ALLOWED_MECHANISMS, sizeof (value), &value,
 	                              CKA_DECRYPT, GP11_BOOLEAN, TRUE,
 	                              CKA_PRIVATE, GP11_BOOLEAN, TRUE,
+	                              CKA_WRAP, GP11_BOOLEAN, TRUE,
+	                              CKA_UNWRAP, GP11_BOOLEAN, TRUE,
+	                              CKA_DERIVE, GP11_BOOLEAN, TRUE,
+	                              CKA_VALUE, GP11_STRING, "value",
 	                              GP11_INVALID);
 	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PRIVATE_KEY_CAPITALIZE), attrs);
 
@@ -146,6 +160,7 @@ test_C_Initialize (CK_VOID_PTR pInitArgs)
 	                              CKA_ALLOWED_MECHANISMS, sizeof (value), &value,
 	                              CKA_ENCRYPT, GP11_BOOLEAN, TRUE,
 	                              CKA_PRIVATE, GP11_BOOLEAN, FALSE,
+	                              CKA_VALUE, GP11_STRING, "value",
 	                              GP11_INVALID);
 	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PUBLIC_KEY_CAPITALIZE), attrs);
 
@@ -157,6 +172,7 @@ test_C_Initialize (CK_VOID_PTR pInitArgs)
 	                              CKA_SIGN, GP11_BOOLEAN, TRUE,
 	                              CKA_PRIVATE, GP11_BOOLEAN, TRUE,
 	                              CKA_ALWAYS_AUTHENTICATE, GP11_BOOLEAN, TRUE,
+	                              CKA_VALUE, GP11_STRING, "value",
 	                              GP11_INVALID);
 	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PRIVATE_KEY_PREFIX), attrs);
 
@@ -167,6 +183,7 @@ test_C_Initialize (CK_VOID_PTR pInitArgs)
 	                              CKA_ALLOWED_MECHANISMS, sizeof (value), &value,
 	                              CKA_VERIFY, GP11_BOOLEAN, TRUE,
 	                              CKA_PRIVATE, GP11_BOOLEAN, FALSE,
+	                              CKA_VALUE, GP11_STRING, "value",
 	                              GP11_INVALID);
 	g_hash_table_insert (the_objects, GUINT_TO_POINTER (PUBLIC_KEY_PREFIX), attrs);
 	
@@ -613,10 +630,8 @@ test_C_DestroyObject (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject)
 	g_assert (session != NULL && "No such session found");
 	if (!session)
 		return CKR_SESSION_HANDLE_INVALID;
-	
-	attrs = g_hash_table_lookup (the_objects, GUINT_TO_POINTER (hObject));
-	if (!attrs)
-		attrs = g_hash_table_lookup (session->objects, GUINT_TO_POINTER (hObject));
+
+	attrs = lookup_object (session, hObject);
 	if (!attrs) {
 		g_assert_not_reached (); /* "no such object found" */
 		return CKR_OBJECT_HANDLE_INVALID;
@@ -654,9 +669,7 @@ test_C_GetAttributeValue (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
 	if (!session)
 		return CKR_SESSION_HANDLE_INVALID;
 	
-	attrs = g_hash_table_lookup (the_objects, GUINT_TO_POINTER (hObject));
-	if (!attrs)
-		attrs = g_hash_table_lookup (session->objects, GUINT_TO_POINTER (hObject));
+	attrs = lookup_object (session, hObject);
 	if (!attrs) {
 		g_assert_not_reached (); /* "invalid object handle passed" */
 		return CKR_OBJECT_HANDLE_INVALID;
@@ -703,9 +716,7 @@ test_C_SetAttributeValue (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject,
 	if (!session)
 		return CKR_SESSION_HANDLE_INVALID;
 
-	attrs = g_hash_table_lookup (the_objects, GUINT_TO_POINTER (hObject));
-	if (!attrs)
-		attrs = g_hash_table_lookup (session->objects, GUINT_TO_POINTER (hObject));
+	attrs = lookup_object (session, hObject);
 	if (!attrs) {
 		g_assert_not_reached (); /* "invalid object handle passed" */
 		return CKR_OBJECT_HANDLE_INVALID;
@@ -1340,21 +1351,123 @@ test_C_GenerateKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
 
 static CK_RV
 test_C_GenerateKeyPair (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
-                      CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
-                      CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
-                      CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
+                        CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount,
+                        CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount,
+                        CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey)
 {
-	g_assert_not_reached (); /* Not yet used by library */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	GP11Attributes *attrs;
+	Session *session;
+	gboolean token;
+	CK_ULONG i;
+
+	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
+	g_assert (session != NULL && "No such session found");
+	if (!session)
+		return CKR_SESSION_HANDLE_INVALID;
+
+	g_assert (pMechanism);
+	g_assert (pPublicKeyTemplate);
+	g_assert (ulPublicKeyAttributeCount);
+	g_assert (pPrivateKeyTemplate);
+	g_assert (phPublicKey);
+	g_assert (phPrivateKey);
+
+	if (pMechanism->mechanism != CKM_GENERATE)
+		return CKR_MECHANISM_INVALID;
+
+	if (!pMechanism->pParameter || pMechanism->ulParameterLen != 9 ||
+	    memcmp (pMechanism->pParameter, "generate", 9) != 0) {
+		g_assert_not_reached ();
+		return CKR_MECHANISM_PARAM_INVALID;
+	}
+
+	attrs = gp11_attributes_new ();
+	gp11_attributes_add_string (attrs, CKA_VALUE, "generated");
+	for (i = 0; i < ulPublicKeyAttributeCount; ++i)
+		gp11_attributes_add_data (attrs, pPublicKeyTemplate[i].type,
+		                          pPublicKeyTemplate[i].pValue,
+		                          pPublicKeyTemplate[i].ulValueLen);
+	*phPublicKey = ++unique_identifier;
+	if (gp11_attributes_find_boolean (attrs, CKA_TOKEN, &token) && token)
+		g_hash_table_insert (the_objects, GUINT_TO_POINTER (*phPublicKey), attrs);
+	else
+		g_hash_table_insert (session->objects, GUINT_TO_POINTER (*phPublicKey), attrs);
+
+	attrs = gp11_attributes_new ();
+	gp11_attributes_add_string (attrs, CKA_VALUE, "generated");
+	for (i = 0; i < ulPrivateKeyAttributeCount; ++i)
+		gp11_attributes_add_data (attrs, pPrivateKeyTemplate[i].type,
+		                          pPrivateKeyTemplate[i].pValue,
+		                          pPrivateKeyTemplate[i].ulValueLen);
+	*phPrivateKey = ++unique_identifier;
+	if (gp11_attributes_find_boolean (attrs, CKA_TOKEN, &token) && token)
+		g_hash_table_insert (the_objects, GUINT_TO_POINTER (*phPrivateKey), attrs);
+	else
+		g_hash_table_insert (session->objects, GUINT_TO_POINTER (*phPrivateKey), attrs);
+	return CKR_OK;
 }
 
 static CK_RV
 test_C_WrapKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
-              CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
-              CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
+                CK_OBJECT_HANDLE hWrappingKey, CK_OBJECT_HANDLE hKey,
+                CK_BYTE_PTR pWrappedKey, CK_ULONG_PTR pulWrappedKeyLen)
 {
-	g_assert_not_reached (); /* Not yet used by library */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	GP11Attributes *attrs;
+	GP11Attribute *attr;
+	Session *session;
+
+	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
+	if (!session) {
+		g_assert_not_reached ();
+		return CKR_SESSION_HANDLE_INVALID;
+	}
+
+	g_assert (pMechanism);
+	g_assert (hWrappingKey);
+	g_assert (hKey);
+	g_assert (pulWrappedKeyLen);
+
+	attrs = lookup_object (session, hWrappingKey);
+	if (!attrs) {
+		g_assert_not_reached ();
+		return CKR_WRAPPING_KEY_HANDLE_INVALID;
+	}
+
+	attrs = lookup_object (session, hKey);
+	if (!attrs) {
+		g_assert_not_reached ();
+		return CKR_WRAPPED_KEY_INVALID;
+	}
+
+	if (pMechanism->mechanism != CKM_WRAP)
+		return CKR_MECHANISM_INVALID;
+
+	if (pMechanism->pParameter) {
+		if (pMechanism->ulParameterLen != 4 ||
+		    memcmp (pMechanism->pParameter, "wrap", 4) != 0) {
+			g_assert_not_reached ();
+			return CKR_MECHANISM_PARAM_INVALID;
+		}
+	}
+
+	attr = gp11_attributes_find (attrs, CKA_VALUE);
+	if (attr == NULL)
+		return CKR_WRAPPED_KEY_INVALID;
+
+	if (!pWrappedKey) {
+		*pulWrappedKeyLen = attr->length;
+		return CKR_OK;
+	}
+
+	if (*pulWrappedKeyLen < attr->length) {
+		*pulWrappedKeyLen = attr->length;
+		return CKR_BUFFER_TOO_SMALL;
+	}
+
+	memcpy (pWrappedKey, attr->value, attr->length);
+	*pulWrappedKeyLen = attr->length;
+
+	return CKR_OK;
 }
 
 static CK_RV
@@ -1363,8 +1476,56 @@ test_C_UnwrapKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
                 CK_ULONG pulWrappedKeyLen, CK_ATTRIBUTE_PTR pTemplate,
                 CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
 {
-	g_assert_not_reached (); /* Not yet used by library */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	GP11Attributes *attrs;
+	Session *session;
+	gboolean token;
+	CK_ULONG i;
+
+	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
+	if (!session) {
+		g_assert_not_reached ();
+		return CKR_SESSION_HANDLE_INVALID;
+	}
+
+	g_assert (pMechanism);
+	g_assert (pUnwrappingKey);
+	g_assert (pWrappedKey);
+	g_assert (pulWrappedKeyLen);
+	g_assert (phKey);
+	g_assert (ulCount);
+	g_assert (pTemplate);
+	g_assert (phKey);
+
+	attrs = lookup_object (session, pUnwrappingKey);
+	if (!attrs) {
+		g_assert_not_reached ();
+		return CKR_WRAPPING_KEY_HANDLE_INVALID;
+	}
+
+	if (pMechanism->mechanism != CKM_WRAP)
+		return CKR_MECHANISM_INVALID;
+
+	if (pMechanism->pParameter) {
+		if (pMechanism->ulParameterLen != 4 ||
+		    memcmp (pMechanism->pParameter, "wrap", 4) != 0) {
+			g_assert_not_reached ();
+			return CKR_MECHANISM_PARAM_INVALID;
+		}
+	}
+
+	attrs = gp11_attributes_new ();
+	gp11_attributes_add_data (attrs, CKA_VALUE, pWrappedKey, pulWrappedKeyLen);
+	for (i = 0; i < ulCount; ++i)
+		gp11_attributes_add_data (attrs, pTemplate[i].type,
+		                          pTemplate[i].pValue,
+		                          pTemplate[i].ulValueLen);
+	*phKey = ++unique_identifier;
+	if (gp11_attributes_find_boolean (attrs, CKA_TOKEN, &token) && token)
+		g_hash_table_insert (the_objects, GUINT_TO_POINTER (*phKey), attrs);
+	else
+		g_hash_table_insert (session->objects, GUINT_TO_POINTER (*phKey), attrs);
+
+	return CKR_OK;
 }
 
 static CK_RV
@@ -1372,8 +1533,54 @@ test_C_DeriveKey (CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism,
                 CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate,
                 CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phKey)
 {
-	g_assert_not_reached (); /* Not yet used by library */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	GP11Attributes *attrs, *copy;
+	Session *session;
+	gboolean token;
+	CK_ULONG i;
+
+	session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
+	if (!session) {
+		g_assert_not_reached ();
+		return CKR_SESSION_HANDLE_INVALID;
+	}
+
+	g_assert (pMechanism);
+	g_assert (ulCount);
+	g_assert (pTemplate);
+	g_assert (phKey);
+
+	attrs = lookup_object (session, hBaseKey);
+	if (!attrs) {
+		g_assert_not_reached ();
+		return CKR_WRAPPING_KEY_HANDLE_INVALID;
+	}
+
+	if (pMechanism->mechanism != CKM_DERIVE)
+		return CKR_MECHANISM_INVALID;
+
+	if (pMechanism->pParameter) {
+		if (pMechanism->ulParameterLen != 6 ||
+		    memcmp (pMechanism->pParameter, "derive", 6) != 0) {
+			g_assert_not_reached ();
+			return CKR_MECHANISM_PARAM_INVALID;
+		}
+	}
+
+	copy = gp11_attributes_new ();
+	gp11_attributes_add_string (copy, CKA_VALUE, "derived");
+	for (i = 0; i < ulCount; ++i)
+		gp11_attributes_add_data (copy, pTemplate[i].type,
+		                          pTemplate[i].pValue,
+		                          pTemplate[i].ulValueLen);
+	for (i = 0; i < gp11_attributes_count (attrs); ++i)
+		gp11_attributes_add (copy, gp11_attributes_at (attrs, i));
+	*phKey = ++unique_identifier;
+	if (gp11_attributes_find_boolean (copy, CKA_TOKEN, &token) && token)
+		g_hash_table_insert (the_objects, GUINT_TO_POINTER (*phKey), copy);
+	else
+		g_hash_table_insert (session->objects, GUINT_TO_POINTER (*phKey), copy);
+
+	return CKR_OK;
 }
 
 static CK_RV
diff --git a/gp11/tests/gp11-test.h b/gp11/tests/gp11-test.h
index 4592e20..013ef0d 100644
--- a/gp11/tests/gp11-test.h
+++ b/gp11/tests/gp11-test.h
@@ -29,9 +29,22 @@
  * CKM_PREFIX (sign/verify)
  *     sign prefixes data with key label
  *     verify unprefixes data with key label. 
+ *
+ * CKM_GENERATE (generate-pair)
+ *     generates a pair of keys, mechanism param should be 'generate'
+ *
+ * CKM_WRAP (wrap key)
+ *     wraps key by returning value, mechanism param should be 'wrap'
+ *
+ * CKM_DERIVE (derive-key)
+ *     derives key by setting value to 'derived'.
+ *     mechanism param should be 'derive'
  */
 
 #define CKM_CAPITALIZE    (CKM_VENDOR_DEFINED | 1)
 #define CKM_PREFIX        (CKM_VENDOR_DEFINED | 2)
+#define CKM_GENERATE      (CKM_VENDOR_DEFINED | 3)
+#define CKM_WRAP          (CKM_VENDOR_DEFINED | 4)
+#define CKM_DERIVE        (CKM_VENDOR_DEFINED | 5)
 
 #endif /*TESTGP11HELPERS_H_*/
diff --git a/gp11/tests/test-gp11-mechanism.c b/gp11/tests/test-gp11-mechanism.c
new file mode 100644
index 0000000..68543a2
--- /dev/null
+++ b/gp11/tests/test-gp11-mechanism.c
@@ -0,0 +1,60 @@
+
+#include <glib.h>
+#include <string.h>
+
+#include "run-auto-test.h"
+#include "gp11-test.h"
+
+#define MECH_TYPE 55
+#define MECH_DATA "TEST DATA"
+#define N_MECH_DATA ((gsize)9)
+
+DEFINE_TEST(mech_new)
+{
+	GP11Mechanism *mech;
+
+	mech = gp11_mechanism_new (MECH_TYPE);
+
+	g_assert (mech);
+	g_assert (mech->type == MECH_TYPE);
+	g_assert (mech->parameter == NULL);
+	g_assert (mech->n_parameter == 0);
+
+	gp11_mechanism_unref (mech);
+}
+
+DEFINE_TEST(mech_new_with_param)
+{
+	GP11Mechanism *mech;
+	gpointer parameter = MECH_DATA;
+
+	mech = gp11_mechanism_new_with_param (MECH_TYPE, parameter, N_MECH_DATA);
+
+	g_assert (mech);
+	g_assert (mech->type == MECH_TYPE);
+	g_assert (mech->parameter != NULL);
+	g_assert (mech->parameter != parameter); /* Copied */
+	g_assert (mech->n_parameter == N_MECH_DATA);
+	g_assert (memcmp (mech->parameter, MECH_DATA, N_MECH_DATA) == 0);
+
+	gp11_mechanism_unref (mech);
+}
+
+DEFINE_TEST(mech_ref_unref)
+{
+	GP11Mechanism *mech, *check;
+
+	mech = gp11_mechanism_new (MECH_TYPE);
+	g_assert (mech);
+
+	check = gp11_mechanism_ref (mech);
+	g_assert (check == mech);
+
+	gp11_mechanism_unref (check);
+	gp11_mechanism_unref (mech);
+}
+
+DEFINE_TEST(mech_unref_null)
+{
+	gp11_mechanism_unref (NULL);
+}
diff --git a/gp11/tests/unit-test-gp11-crypto.c b/gp11/tests/unit-test-gp11-crypto.c
index a6bf68e..90a0438 100644
--- a/gp11/tests/unit-test-gp11-crypto.c
+++ b/gp11/tests/unit-test-gp11-crypto.c
@@ -59,22 +59,61 @@ find_key (GP11Session *session, CK_ATTRIBUTE_TYPE method, CK_MECHANISM_TYPE mech
 	
 	for (l = objects; l; l = g_list_next (l)) {
 		gp11_object_set_session (l->data, session);
-		mechs = gp11_object_get_data (l->data, CKA_ALLOWED_MECHANISMS, &n_mechs, NULL);
-		g_assert (mechs);
-		g_assert (n_mechs == sizeof (CK_MECHANISM_TYPE));
-		
-		/* We know all of them only have one allowed mech */
-		if (*mechs == mech) {
-			object = l->data;
-			g_object_ref (object);
-			break;
+		if (mech) {
+			mechs = gp11_object_get_data (l->data, CKA_ALLOWED_MECHANISMS, &n_mechs, NULL);
+			g_assert (mechs);
+			g_assert (n_mechs == sizeof (CK_MECHANISM_TYPE));
+			/* We know all of them only have one allowed mech */
+			if (*mechs != mech)
+				continue;
 		}
+		object = l->data;
+		g_object_ref (object);
+		break;
 	}
 	
 	gp11_list_unref_free (objects);
 	return object;
 }
 
+static GP11Object*
+find_key_with_value (GP11Session *session, const gchar *value)
+{
+	GList *objects;
+	GP11Object *object;
+
+	objects = gp11_session_find_objects (session, NULL, CKA_VALUE, GP11_STRING, value, GP11_INVALID);
+	g_assert (objects);
+
+	object = g_object_ref (objects->data);
+	gp11_list_unref_free (objects);
+	return object;
+}
+
+static void
+check_key_with_value (GP11Session *session, GP11Object *key, CK_OBJECT_CLASS klass, const gchar *value)
+{
+	GP11Attributes *attrs;
+	GP11Attribute *attr;
+	gulong check;
+
+	gp11_object_set_session (key, session);
+	attrs = gp11_object_get (key, NULL, CKA_CLASS, CKA_VALUE, GP11_INVALID);
+	g_assert (attrs);
+
+	if (!gp11_attributes_find_ulong (attrs, CKA_CLASS, &check))
+		g_assert_not_reached ();
+	g_assert (check == klass);
+
+	attr = gp11_attributes_find (attrs, CKA_VALUE);
+	g_assert (attr);
+	g_assert (!gp11_attribute_is_invalid (attr));
+	g_assert_cmpsize (attr->length, ==, strlen (value));
+	g_assert (memcmp (attr->value, value, attr->length) == 0);
+
+	gp11_attributes_unref (attrs);
+}
+
 static gboolean
 authenticate_object (GP11Slot *module, GP11Object *object, gchar *label, gchar **password)
 {
@@ -89,16 +128,14 @@ authenticate_object (GP11Slot *module, GP11Object *object, gchar *label, gchar *
 
 DEFINE_TEST(encrypt)
 {
-	GP11Mechanism mech;
+	GP11Mechanism *mech;
 	GError *error = NULL;
 	GAsyncResult *result = NULL;
 	GP11Object *key;
 	guchar *output;
 	gsize n_output;
 
-	mech.type = CKM_CAPITALIZE;
-	mech.n_parameter = 0;
-	mech.parameter = NULL;
+	mech = gp11_mechanism_new (CKM_CAPITALIZE);
 
 	/* Find the right key */
 	key = find_key (session, CKA_ENCRYPT, CKM_CAPITALIZE);
@@ -112,14 +149,14 @@ DEFINE_TEST(encrypt)
 	g_free (output);
 	
 	/* Full one */
-	output = gp11_session_encrypt_full (session, key, &mech, (const guchar*)"blah blah", 10, &n_output, NULL, &error);
+	output = gp11_session_encrypt_full (session, key, mech, (const guchar*)"blah blah", 10, &n_output, NULL, &error);
 	SUCCESS_RES (output, error);
 	g_assert (n_output == 10);
 	g_assert_cmpstr ((gchar*)output, ==, "BLAH BLAH");
 	g_free (output);
 	
 	/* Asynchronous one */
-	gp11_session_encrypt_async (session, key, &mech, (const guchar*)"second chance", 14, NULL, fetch_async_result, &result);
+	gp11_session_encrypt_async (session, key, mech, (const guchar*)"second chance", 14, NULL, fetch_async_result, &result);
 
 	WAIT_UNTIL (result);
 	g_assert (result != NULL);
@@ -131,22 +168,21 @@ DEFINE_TEST(encrypt)
 	g_assert_cmpstr ((gchar*)output, ==, "SECOND CHANCE");
 	g_free (output);
 
+	gp11_mechanism_unref (mech);
 	g_object_unref (result);
 	g_object_unref (key);
 }
 
 DEFINE_TEST(decrypt)
 {
-	GP11Mechanism mech;
+	GP11Mechanism *mech;
 	GError *error = NULL;
 	GAsyncResult *result = NULL;
 	GP11Object *key;
 	guchar *output;
 	gsize n_output;
 
-	mech.type = CKM_CAPITALIZE;
-	mech.n_parameter = 0;
-	mech.parameter = NULL;
+	mech = gp11_mechanism_new (CKM_CAPITALIZE);
 
 	/* Find the right key */
 	key = find_key (session, CKA_DECRYPT, CKM_CAPITALIZE);
@@ -160,14 +196,14 @@ DEFINE_TEST(decrypt)
 	g_free (output);
 	
 	/* Full one */
-	output = gp11_session_decrypt_full (session, key, &mech, (const guchar*)"TENNIS instructor", 18, &n_output, NULL, &error);
+	output = gp11_session_decrypt_full (session, key, mech, (const guchar*)"TENNIS instructor", 18, &n_output, NULL, &error);
 	SUCCESS_RES (output, error);
 	g_assert (n_output == 18);
 	g_assert_cmpstr ((gchar*)output, ==, "tennis instructor");
 	g_free (output);
 	
 	/* Asynchronous one */
-	gp11_session_decrypt_async (session, key, &mech, (const guchar*)"FAT CHANCE", 11, NULL, fetch_async_result, &result);
+	gp11_session_decrypt_async (session, key, mech, (const guchar*)"FAT CHANCE", 11, NULL, fetch_async_result, &result);
 
 	WAIT_UNTIL (result);
 	g_assert (result != NULL);
@@ -179,6 +215,7 @@ DEFINE_TEST(decrypt)
 	g_assert_cmpstr ((gchar*)output, ==, "fat chance");
 	g_free (output);
 
+	gp11_mechanism_unref (mech);
 	g_object_unref (result);
 	g_object_unref (key);
 }
@@ -207,17 +244,15 @@ DEFINE_TEST(login_context_specific)
 
 DEFINE_TEST(sign)
 {
-	GP11Mechanism mech;
+	GP11Mechanism *mech;
 	GError *error = NULL;
 	GAsyncResult *result = NULL;
 	GP11Object *key;
 	guchar *output;
 	gsize n_output;
 
-	mech.type = CKM_PREFIX;
-	mech.n_parameter = 10;
-	mech.parameter = "my-prefix:";
-	
+	mech = gp11_mechanism_new_with_param (CKM_PREFIX, "my-prefix:", 10);
+
 	/* Enable auto-login on this session, see previous test */
 	gp11_module_set_auto_authenticate (module, TRUE);
 	g_signal_connect (module, "authenticate-object", G_CALLBACK (authenticate_object), NULL);
@@ -234,14 +269,14 @@ DEFINE_TEST(sign)
 	g_free (output);
 	
 	/* Full one */
-	output = gp11_session_sign_full (session, key, &mech, (const guchar*)"Labarbara", 10, &n_output, NULL, &error);
+	output = gp11_session_sign_full (session, key, mech, (const guchar*)"Labarbara", 10, &n_output, NULL, &error);
 	SUCCESS_RES (output, error);
 	g_assert_cmpuint (n_output, ==, 20);
 	g_assert_cmpstr ((gchar*)output, ==, "my-prefix:Labarbara");
 	g_free (output);
 	
 	/* Asynchronous one */
-	gp11_session_sign_async (session, key, &mech, (const guchar*)"Conrad", 7, NULL, fetch_async_result, &result);
+	gp11_session_sign_async (session, key, mech, (const guchar*)"Conrad", 7, NULL, fetch_async_result, &result);
 
 	WAIT_UNTIL (result);
 	g_assert (result != NULL);
@@ -253,22 +288,21 @@ DEFINE_TEST(sign)
 	g_assert_cmpstr ((gchar*)output, ==, "my-prefix:Conrad");
 	g_free (output);
 
+	gp11_mechanism_unref (mech);
 	g_object_unref (result);
 	g_object_unref (key);
 }
 
 DEFINE_TEST(verify)
 {
-	GP11Mechanism mech;
+	GP11Mechanism *mech;
 	GError *error = NULL;
 	GAsyncResult *result = NULL;
 	GP11Object *key;
 	gboolean ret;
 
-	mech.type = CKM_PREFIX;
-	mech.n_parameter = 10;
-	mech.parameter = "my-prefix:";
-	
+	mech = gp11_mechanism_new_with_param (CKM_PREFIX, "my-prefix:", 10);
+
 	/* Enable auto-login on this session, shouldn't be needed */
 	gp11_module_set_auto_authenticate (module, TRUE);
 	g_signal_connect (module, "authenticate-object", G_CALLBACK (authenticate_object), NULL);
@@ -283,17 +317,17 @@ DEFINE_TEST(verify)
 	SUCCESS_RES (ret, error);
 	
 	/* Full one */
-	ret = gp11_session_verify_full (session, key, &mech, (const guchar*)"Labarbara", 10, 
+	ret = gp11_session_verify_full (session, key, mech, (const guchar*)"Labarbara", 10,
 	                                (const guchar*)"my-prefix:Labarbara", 20, NULL, &error);
 	SUCCESS_RES (ret, error);
 
 	/* Failure one */
-	ret = gp11_session_verify_full (session, key, &mech, (const guchar*)"Labarbara", 10, 
+	ret = gp11_session_verify_full (session, key, mech, (const guchar*)"Labarbara", 10,
 	                                (const guchar*)"my-prefix:Loborboro", 20, NULL, &error);
 	FAIL_RES (ret, error);
 
 	/* Asynchronous one */
-	gp11_session_verify_async (session, key, &mech, (const guchar*)"Labarbara", 10, 
+	gp11_session_verify_async (session, key, mech, (const guchar*)"Labarbara", 10,
 	                           (const guchar*)"my-prefix:Labarbara", 20, NULL, fetch_async_result, &result);
 	WAIT_UNTIL (result);
 	g_assert (result != NULL);
@@ -303,7 +337,7 @@ DEFINE_TEST(verify)
 	
 	/* Asynchronous failure */
 	result = NULL;
-	gp11_session_verify_async (session, key, &mech, (const guchar*)"Labarbara", 10, 
+	gp11_session_verify_async (session, key, mech, (const guchar*)"Labarbara", 10,
 	                           (const guchar*)"my-prefix:Labarxoro", 20, NULL, fetch_async_result, &result);
 	WAIT_UNTIL (result);
 	g_assert (result != NULL);
@@ -311,5 +345,250 @@ DEFINE_TEST(verify)
 	FAIL_RES (ret, error);
 	g_object_unref (result);
 
+	gp11_mechanism_unref (mech);
 	g_object_unref (key);
 }
+
+DEFINE_TEST(generate_key_pair)
+{
+	GP11Attributes *pub_attrs, *prv_attrs;
+	GP11Mechanism *mech;
+	GError *error = NULL;
+	GAsyncResult *result = NULL;
+	GP11Object *pub_key, *prv_key;
+	gboolean ret;
+
+	mech = gp11_mechanism_new_with_param (CKM_GENERATE, "generate", 9);
+
+	pub_attrs = gp11_attributes_new ();
+	gp11_attributes_add_ulong (pub_attrs, CKA_CLASS, CKO_PUBLIC_KEY);
+	prv_attrs = gp11_attributes_new ();
+	gp11_attributes_add_ulong (prv_attrs, CKA_CLASS, CKO_PRIVATE_KEY);
+
+	/* Full One*/
+	ret = gp11_session_generate_key_pair_full (session, mech, pub_attrs, prv_attrs,
+	                                           &pub_key, &prv_key, NULL, &error);
+	SUCCESS_RES (ret, error);
+	g_object_unref (pub_key);
+	g_object_unref (prv_key);
+
+	/* Failure one */
+	mech->type = 0;
+	pub_key = prv_key = NULL;
+	ret = gp11_session_generate_key_pair_full (session, mech, pub_attrs, prv_attrs,
+	                                           &pub_key, &prv_key, NULL, &error);
+	FAIL_RES (ret, error);
+	g_assert (pub_key == NULL);
+	g_assert (prv_key == NULL);
+
+	/* Asynchronous one */
+	mech->type = CKM_GENERATE;
+	gp11_session_generate_key_pair_async (session, mech, pub_attrs, prv_attrs, NULL, fetch_async_result, &result);
+	WAIT_UNTIL (result);
+	g_assert (result != NULL);
+	ret = gp11_session_generate_key_pair_finish (session, result, &pub_key, &prv_key, &error);
+	SUCCESS_RES (ret, error);
+	g_object_unref (result);
+	g_object_unref (pub_key);
+	g_object_unref (prv_key);
+
+	/* Asynchronous failure */
+	result = NULL;
+	mech->type = 0;
+	pub_key = prv_key = NULL;
+	gp11_session_generate_key_pair_async (session, mech, pub_attrs, prv_attrs, NULL, fetch_async_result, &result);
+	WAIT_UNTIL (result);
+	g_assert (result != NULL);
+	ret = gp11_session_generate_key_pair_finish (session, result, &pub_key, &prv_key, &error);
+	FAIL_RES (ret, error);
+	g_object_unref (result);
+	g_assert (pub_key == NULL);
+	g_assert (prv_key == NULL);
+
+	gp11_mechanism_unref (mech);
+	gp11_attributes_unref (pub_attrs);
+	gp11_attributes_unref (prv_attrs);
+}
+
+DEFINE_TEST(wrap_key)
+{
+	GP11Mechanism *mech;
+	GError *error = NULL;
+	GAsyncResult *result = NULL;
+	GP11Object *wrapper, *wrapped;
+	gpointer output;
+	gsize n_output;
+
+	mech = gp11_mechanism_new_with_param (CKM_WRAP, "wrap", 4);
+	wrapper = find_key (session, CKA_WRAP, 0);
+	wrapped = find_key_with_value (session, "value");
+
+	/* Simple One */
+	output = gp11_session_wrap_key (session, wrapper, CKM_WRAP, wrapped, &n_output, &error);
+	SUCCESS_RES (output, error);
+	g_assert (output);
+	g_assert_cmpsize (n_output, ==, 5);
+	g_assert (memcmp (output, "value", 5) == 0);
+	g_free (output);
+
+	/* Full One*/
+	output = gp11_session_wrap_key_full (session, wrapper, mech, wrapped, &n_output, NULL, &error);
+	SUCCESS_RES (output, error);
+	g_assert_cmpsize (n_output, ==, 5);
+	g_assert (memcmp (output, "value", 5) == 0);
+	g_free (output);
+
+	/* Failure one */
+	mech->type = 0;
+	n_output = 0;
+	output = gp11_session_wrap_key_full (session, wrapper, mech, wrapped, &n_output, NULL, &error);
+	FAIL_RES (output, error);
+	g_assert_cmpsize (n_output, ==, 0);
+
+	/* Asynchronous one */
+	mech->type = CKM_WRAP;
+	gp11_session_wrap_key_async (session, wrapper, mech, wrapped, NULL, fetch_async_result, &result);
+	WAIT_UNTIL (result);
+	g_assert (result != NULL);
+	output = gp11_session_wrap_key_finish (session, result, &n_output, &error);
+	SUCCESS_RES (output, error);
+	g_assert_cmpsize (n_output, ==, 5);
+	g_assert (memcmp (output, "value", 5) == 0);
+	g_object_unref (result);
+	g_free (output);
+
+	/* Asynchronous failure */
+	result = NULL;
+	mech->type = 0;
+	n_output = 0;
+	gp11_session_wrap_key_async (session, wrapper, mech, wrapped, NULL, fetch_async_result, &result);
+	WAIT_UNTIL (result);
+	g_assert (result != NULL);
+	output = gp11_session_wrap_key_finish (session, result, &n_output, &error);
+	FAIL_RES (output, error);
+	g_assert_cmpsize (n_output, ==, 0);
+	g_object_unref (result);
+
+	g_object_unref (wrapper);
+	g_object_unref (wrapped);
+	gp11_mechanism_unref (mech);
+}
+
+DEFINE_TEST(unwrap_key)
+{
+	GP11Mechanism *mech;
+	GError *error = NULL;
+	GAsyncResult *result = NULL;
+	GP11Object *wrapper, *unwrapped;
+	GP11Attributes *attrs;
+
+	mech = gp11_mechanism_new_with_param (CKM_WRAP, "wrap", 4);
+	wrapper = find_key (session, CKA_UNWRAP, 0);
+	attrs = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY, GP11_INVALID);
+
+	/* Simple One */
+	unwrapped = gp11_session_unwrap_key (session, wrapper, CKM_WRAP, "special", 7, &error,
+	                                     CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY, GP11_INVALID);
+	SUCCESS_RES (unwrapped, error);
+	g_assert (GP11_IS_OBJECT (unwrapped));
+	check_key_with_value (session, unwrapped, CKO_SECRET_KEY, "special");
+	g_object_unref (unwrapped);
+
+	/* Full One*/
+	unwrapped = gp11_session_unwrap_key_full (session, wrapper, mech, "special", 7, attrs, NULL, &error);
+	SUCCESS_RES (unwrapped, error);
+	g_assert (GP11_IS_OBJECT (unwrapped));
+	check_key_with_value (session, unwrapped, CKO_SECRET_KEY, "special");
+	g_object_unref (unwrapped);
+
+	/* Failure one */
+	mech->type = 0;
+	unwrapped = gp11_session_unwrap_key_full (session, wrapper, mech, "special", 7, attrs, NULL, &error);
+	FAIL_RES (unwrapped, error);
+
+	/* Asynchronous one */
+	mech->type = CKM_WRAP;
+	gp11_session_unwrap_key_async (session, wrapper, mech, "special", 7, attrs, NULL, fetch_async_result, &result);
+	WAIT_UNTIL (result);
+	g_assert (result != NULL);
+	unwrapped = gp11_session_unwrap_key_finish (session, result, &error);
+	SUCCESS_RES (unwrapped, error);
+	g_assert (GP11_IS_OBJECT (unwrapped));
+	check_key_with_value (session, unwrapped, CKO_SECRET_KEY, "special");
+	g_object_unref (unwrapped);
+	g_object_unref (result);
+
+	/* Asynchronous failure */
+	result = NULL;
+	mech->type = 0;
+	gp11_session_unwrap_key_async (session, wrapper, mech, "special", 6, attrs, NULL, fetch_async_result, &result);
+	WAIT_UNTIL (result);
+	g_assert (result != NULL);
+	unwrapped = gp11_session_unwrap_key_finish (session, result, &error);
+	FAIL_RES (unwrapped, error);
+	g_object_unref (result);
+
+	g_object_unref (wrapper);
+	gp11_attributes_unref (attrs);
+	gp11_mechanism_unref (mech);
+}
+
+DEFINE_TEST(derive_key)
+{
+	GP11Mechanism *mech;
+	GError *error = NULL;
+	GAsyncResult *result = NULL;
+	GP11Object *wrapper, *derived;
+	GP11Attributes *attrs;
+
+	mech = gp11_mechanism_new_with_param (CKM_DERIVE, "derive", 6);
+	wrapper = find_key (session, CKA_DERIVE, 0);
+	attrs = gp11_attributes_newv (CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY, GP11_INVALID);
+
+	/* Simple One */
+	derived = gp11_session_derive_key (session, wrapper, CKM_DERIVE, &error,
+	                                   CKA_CLASS, GP11_ULONG, CKO_SECRET_KEY, GP11_INVALID);
+	SUCCESS_RES (derived, error);
+	g_assert (GP11_IS_OBJECT (derived));
+g_printerr ("derived is: %lu", gp11_object_get_handle (derived));
+	check_key_with_value (session, derived, CKO_SECRET_KEY, "derived");
+	g_object_unref (derived);
+
+	/* Full One*/
+	derived = gp11_session_derive_key_full (session, wrapper, mech, attrs, NULL, &error);
+	SUCCESS_RES (derived, error);
+	g_assert (GP11_IS_OBJECT (derived));
+	check_key_with_value (session, derived, CKO_SECRET_KEY, "derived");
+	g_object_unref (derived);
+
+	/* Failure one */
+	mech->type = 0;
+	derived = gp11_session_derive_key_full (session, wrapper, mech, attrs, NULL, &error);
+	FAIL_RES (derived, error);
+
+	/* Asynchronous one */
+	mech->type = CKM_DERIVE;
+	gp11_session_derive_key_async (session, wrapper, mech, attrs, NULL, fetch_async_result, &result);
+	WAIT_UNTIL (result);
+	g_assert (result != NULL);
+	derived = gp11_session_derive_key_finish (session, result, &error);
+	SUCCESS_RES (derived, error);
+	g_assert (GP11_IS_OBJECT (derived));
+	check_key_with_value (session, derived, CKO_SECRET_KEY, "derived");
+	g_object_unref (derived);
+	g_object_unref (result);
+
+	/* Asynchronous failure */
+	result = NULL;
+	mech->type = 0;
+	gp11_session_derive_key_async (session, wrapper, mech, attrs, NULL, fetch_async_result, &result);
+	WAIT_UNTIL (result);
+	g_assert (result != NULL);
+	derived = gp11_session_derive_key_finish (session, result, &error);
+	FAIL_RES (derived, error);
+	g_object_unref (result);
+
+	g_object_unref (wrapper);
+	gp11_attributes_unref (attrs);
+	gp11_mechanism_unref (mech);
+}



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