[gp11] Implement support for generate, wrap, unwrap, derive.
authorStef Walter <stef@memberwebs.com>
Fri, 20 Nov 2009 17:29:53 +0000 (17:29 +0000)
committerStef Walter <stef@memberwebs.com>
Fri, 20 Nov 2009 17:29:53 +0000 (17:29 +0000)
Implement gp11_session_generate_key_pair...(),
gp11_session_wrap_key...(), gp11_session_unwrap_key...(),
and gp11_session_derive_key...().

gp11/gp11-misc.c
gp11/gp11-session.c
gp11/gp11.h
gp11/tests/Makefile.am
gp11/tests/gp11-test-module.c
gp11/tests/gp11-test.h
gp11/tests/test-gp11-mechanism.c [new file with mode: 0644]
gp11/tests/unit-test-gp11-crypto.c

index 090246e..9b6293a 100644 (file)
@@ -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);
+       }
+}
index 2698eb8..06a49f5 100644 (file)
@@ -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,7 +2025,7 @@ 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);
 
@@ -1303,9 +2033,7 @@ crypt_sync (GP11Session *self, GP11Object *key, GP11Mechanism *mech_args, const
        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;
@@ -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,17 +2064,14 @@ 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,15 +2561,13 @@ 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;
@@ -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,15 +2608,12 @@ 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;
index 29dd565..87eaaa6 100644 (file)
@@ -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
  */
index 3175ecb..532bfd5 100644 (file)
@@ -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 \
index 5dfc987..f2713f2 100644 (file)
@@ -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);
 
@@ -614,9 +631,7 @@ test_C_DestroyObject (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 (); /* "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
index 4a12877..428060d 100644 (file)
  * 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 (file)
index 0000000..68543a2
--- /dev/null
@@ -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);
+}
index fefd548..6a1df15 100644 (file)
@@ -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,16 +244,14 @@ 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);
@@ -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,21 +288,20 @@ 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);
@@ -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);
+}