[gnome-keyring: 5/10] [gck] Add authenticator objects for storing authenticated state.
- From: Stefan Walter <stefw src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnome-keyring: 5/10] [gck] Add authenticator objects for storing authenticated state.
- Date: Sun, 19 Jul 2009 19:33:33 +0000 (UTC)
commit 6a6d07aa2265ff842b37900faaf13b096c0fdd5a
Author: Stef Walter <stef memberwebs com>
Date: Sun Jul 19 03:44:53 2009 +0000
[gck] Add authenticator objects for storing authenticated state.
Authenticator objects are now used for PKCS#11 context specific
logins. In the future we'll use them for unlocking stuff on a
token, session, or timeout basis.
pkcs11/gck/Makefile.am | 1 +
pkcs11/gck/gck-authenticator.c | 402 ++++++++++++++++++++++++
pkcs11/gck/gck-authenticator.h | 77 +++++
pkcs11/gck/gck-key.c | 4 +-
pkcs11/gck/gck-key.h | 5 +-
pkcs11/gck/gck-login.c | 1 +
pkcs11/gck/gck-module.c | 12 +-
pkcs11/gck/gck-object.c | 50 +++-
pkcs11/gck/gck-object.h | 8 +-
pkcs11/gck/gck-private-key.c | 82 ++++--
pkcs11/gck/gck-private-key.h | 8 +-
pkcs11/gck/gck-public-key.c | 2 +-
pkcs11/gck/gck-session.c | 107 ++++++-
pkcs11/gck/gck-session.h | 8 +
pkcs11/gck/gck-sexp.c | 3 +-
pkcs11/gck/gck-sexp.h | 2 +-
pkcs11/gck/gck-types.h | 1 +
pkcs11/gck/gck-util.c | 11 +
pkcs11/gck/gck-util.h | 2 +
pkcs11/gck/tests/Makefile.am | 2 +
pkcs11/gck/tests/mock-locked-object.c | 88 +++++
pkcs11/gck/tests/mock-locked-object.h | 52 +++
pkcs11/gck/tests/test-module.c | 34 ++-
pkcs11/gck/tests/test-module.h | 10 +-
pkcs11/gck/tests/unit-test-authenticator.c | 254 +++++++++++++++
pkcs11/gck/tests/unit-test-memory-store.c | 6 +-
pkcs11/gck/tests/unit-test-object.c | 23 +--
pkcs11/gck/tests/unit-test-store.c | 7 +-
pkcs11/gck/tests/unit-test-timer.c | 6 +-
pkcs11/pkcs11g.h | 14 +-
pkcs11/ssh-store/gck-ssh-module.c | 8 +
pkcs11/ssh-store/gck-ssh-private-key.c | 40 ++-
pkcs11/ssh-store/tests/Makefile.am | 4 +-
pkcs11/ssh-store/tests/test-ssh-module.c | 105 ++++++
pkcs11/ssh-store/tests/test-ssh-module.h | 43 +++
pkcs11/ssh-store/tests/unit-test-private-key.c | 97 ++++++
pkcs11/user-store/gck-user-private-key.c | 4 +-
pkcs11/user-store/gck-user-storage.c | 10 +-
38 files changed, 1451 insertions(+), 142 deletions(-)
---
diff --git a/pkcs11/gck/Makefile.am b/pkcs11/gck/Makefile.am
index 730f416..37f532e 100644
--- a/pkcs11/gck/Makefile.am
+++ b/pkcs11/gck/Makefile.am
@@ -18,6 +18,7 @@ BUILT_SOURCES = \
libgck_la_SOURCES = \
gck-attributes.c gck-attributes.h \
+ gck-authenticator.c gck-authenticator.h \
gck-certificate.c gck-certificate.h \
gck-certificate-key.c gck-certificate-key.h \
gck-certificate-trust.c gck-certificate-trust.h \
diff --git a/pkcs11/gck/gck-authenticator.c b/pkcs11/gck/gck-authenticator.c
new file mode 100644
index 0000000..2f71c2a
--- /dev/null
+++ b/pkcs11/gck/gck-authenticator.c
@@ -0,0 +1,402 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-authenticator.h"
+#include "gck-login.h"
+#include "gck-session.h"
+#include "gck-transaction.h"
+
+#include "pkcs11/pkcs11.h"
+#include "pkcs11/pkcs11g.h"
+
+enum {
+ PROP_0,
+ PROP_OBJECT,
+ PROP_LOGIN,
+ PROP_USES_REMAINING
+};
+
+struct _GckAuthenticatorPrivate {
+
+ /* The object we authenticated */
+ GckObject *object;
+
+ /* Optional login */
+ GckLogin *login;
+
+ /* Can limit by number of uses remaining */
+ gint uses_remaining;
+};
+
+G_DEFINE_TYPE (GckAuthenticator, gck_authenticator, GCK_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+factory_create_authenticator (GckSession *session, GckTransaction *transaction,
+ CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **result)
+{
+ CK_OBJECT_HANDLE handle;
+ GckAuthenticator *auth;
+ CK_ATTRIBUTE *attr;
+ GckObject *object;
+ CK_RV rv;
+
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (attrs || !n_attrs);
+ g_return_if_fail (result);
+
+ /* The handle is required */
+ if (!gck_attributes_find_ulong (attrs, n_attrs, CKA_GNOME_OBJECT, &handle)) {
+ gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+ return;
+ }
+
+ /* Must be a valid object */
+ rv = gck_session_lookup_readable_object (session, handle, &object);
+ if (rv != CKR_OK) {
+ gck_transaction_fail (transaction, rv);
+ return;
+ }
+
+ /* The value is optional */
+ attr = gck_attributes_find (attrs, n_attrs, CKA_VALUE);
+
+ gck_attributes_consume (attrs, n_attrs, CKA_VALUE, CKA_GNOME_OBJECT, G_MAXULONG);
+
+ rv = gck_authenticator_create (object, attr ? attr->pValue : NULL,
+ attr ? attr->ulValueLen : 0, &auth);
+ if (rv == CKR_OK)
+ *result = GCK_OBJECT (auth);
+ else
+ gck_transaction_fail (transaction, rv);
+}
+
+static void
+self_destruct (GckAuthenticator *self)
+{
+ GckTransaction *transaction;
+ CK_RV rv;
+
+ g_assert (GCK_IS_AUTHENTICATOR (self));
+
+ transaction = gck_transaction_new ();
+
+ /* Destroy ourselves */
+ gck_object_destroy (GCK_OBJECT (self), transaction);
+
+ gck_transaction_complete (transaction);
+ rv = gck_transaction_get_result (transaction);
+ g_object_unref (transaction);
+
+ if (rv != CKR_OK)
+ g_warning ("Couldn't destroy authenticator object: (code %lu)", (gulong)rv);
+}
+
+static void
+object_went_away (gpointer data, GObject *old_object)
+{
+ GckAuthenticator *self = data;
+ g_return_if_fail (GCK_IS_AUTHENTICATOR (self));
+ self->pv->object = NULL;
+ self_destruct (self);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gck_authenticator_real_get_attribute (GckObject *base, CK_ATTRIBUTE *attr)
+{
+ GckAuthenticator *self = GCK_AUTHENTICATOR (base);
+
+ switch (attr->type) {
+
+ case CKA_CLASS:
+ return gck_attribute_set_ulong (attr, CKO_GNOME_AUTHENTICATOR);
+
+ case CKA_PRIVATE:
+ return gck_attribute_set_bool (attr, TRUE);
+
+ case CKA_GNOME_OBJECT:
+ g_return_val_if_fail (self->pv->object, CKR_GENERAL_ERROR);
+ return gck_attribute_set_ulong (attr, gck_object_get_handle (self->pv->object));
+
+ case CKA_GNOME_USES_REMAINING:
+ if (self->pv->uses_remaining < 0)
+ return gck_attribute_set_ulong (attr, (CK_ULONG)-1);
+ else
+ return gck_attribute_set_ulong (attr, self->pv->uses_remaining);
+
+ case CKA_VALUE:
+ return CKR_ATTRIBUTE_SENSITIVE;
+ };
+
+ return GCK_OBJECT_CLASS (gck_authenticator_parent_class)->get_attribute (base, attr);
+}
+
+static GObject*
+gck_authenticator_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+ GckAuthenticator *self = GCK_AUTHENTICATOR (G_OBJECT_CLASS (gck_authenticator_parent_class)->constructor(type, n_props, props));
+ g_return_val_if_fail (self, NULL);
+
+ g_return_val_if_fail (self->pv->object, NULL);
+
+ return G_OBJECT (self);
+}
+
+static void
+gck_authenticator_init (GckAuthenticator *self)
+{
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_AUTHENTICATOR, GckAuthenticatorPrivate);
+ self->pv->uses_remaining = -1;
+}
+
+static void
+gck_authenticator_dispose (GObject *obj)
+{
+ GckAuthenticator *self = GCK_AUTHENTICATOR (obj);
+
+ if (self->pv->object)
+ g_object_weak_unref (G_OBJECT (self->pv->object), object_went_away, self);
+ self->pv->object = NULL;
+
+ if (self->pv->login)
+ g_object_unref (self->pv->login);
+ self->pv->login = NULL;
+
+ G_OBJECT_CLASS (gck_authenticator_parent_class)->dispose (obj);
+}
+
+static void
+gck_authenticator_finalize (GObject *obj)
+{
+ GckAuthenticator *self = GCK_AUTHENTICATOR (obj);
+
+ g_assert (!self->pv->object);
+ g_assert (!self->pv->login);
+
+ G_OBJECT_CLASS (gck_authenticator_parent_class)->finalize (obj);
+}
+
+static void
+gck_authenticator_set_property (GObject *obj, guint prop_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ GckAuthenticator *self = GCK_AUTHENTICATOR (obj);
+
+ switch (prop_id) {
+ case PROP_OBJECT:
+ g_return_if_fail (!self->pv->object);
+ self->pv->object = g_value_get_object (value);
+ g_return_if_fail (GCK_IS_OBJECT (self->pv->object));
+ g_object_weak_ref (G_OBJECT (self->pv->object), object_went_away, self);
+ break;
+ case PROP_LOGIN:
+ gck_authenticator_set_login (self, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_authenticator_get_property (GObject *obj, guint prop_id, GValue *value,
+ GParamSpec *pspec)
+{
+ GckAuthenticator *self = GCK_AUTHENTICATOR (obj);
+
+ switch (prop_id) {
+ case PROP_OBJECT:
+ g_value_set_object (value, gck_authenticator_get_object (self));
+ break;
+ case PROP_LOGIN:
+ g_value_set_object (value, gck_authenticator_get_login (self));
+ break;
+ case PROP_USES_REMAINING:
+ g_value_set_int (value, gck_authenticator_get_uses_remaining (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_authenticator_class_init (GckAuthenticatorClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+
+ gck_authenticator_parent_class = g_type_class_peek_parent (klass);
+ g_type_class_add_private (klass, sizeof (GckAuthenticatorPrivate));
+
+ gobject_class->constructor = gck_authenticator_constructor;
+ gobject_class->dispose = gck_authenticator_dispose;
+ gobject_class->finalize = gck_authenticator_finalize;
+ gobject_class->set_property = gck_authenticator_set_property;
+ gobject_class->get_property = gck_authenticator_get_property;
+
+ gck_class->get_attribute = gck_authenticator_real_get_attribute;
+
+ g_object_class_install_property (gobject_class, PROP_OBJECT,
+ g_param_spec_object ("object", "Object", "Object authenticated",
+ GCK_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ g_object_class_install_property (gobject_class, PROP_LOGIN,
+ g_param_spec_object ("login", "Login", "Optiontal login",
+ GCK_TYPE_LOGIN, G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_USES_REMAINING,
+ g_param_spec_int ("uses-remaining", "Uses Remaining", "Uses remaining",
+ -1, G_MAXINT, -1, G_PARAM_READWRITE));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GckFactoryInfo*
+gck_authenticator_get_factory (void)
+{
+ static CK_OBJECT_CLASS klass = CKO_GNOME_AUTHENTICATOR;
+
+ static CK_ATTRIBUTE attributes[] = {
+ { CKA_CLASS, &klass, sizeof (klass) },
+ };
+
+ static GckFactoryInfo factory = {
+ attributes,
+ G_N_ELEMENTS (attributes),
+ factory_create_authenticator
+ };
+
+ return &factory;
+}
+
+CK_RV
+gck_authenticator_create (GckObject *object, CK_UTF8CHAR_PTR pin,
+ CK_ULONG n_pin, GckAuthenticator **result)
+{
+ GckAuthenticator *auth;
+ GckLogin *login = NULL;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_OBJECT (object), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (result, CKR_GENERAL_ERROR);
+
+ if (pin != NULL)
+ login = gck_login_new (pin, n_pin);
+
+ auth = g_object_new (GCK_TYPE_AUTHENTICATOR,
+ "module", gck_object_get_module (object),
+ "login", login, "object", object, NULL);
+
+ /* Now the unlock must work */
+ rv = gck_object_unlock (object, auth);
+ if (rv == CKR_OK)
+ *result = auth;
+ else
+ g_object_unref (auth);
+
+ return rv;
+}
+
+GckLogin*
+gck_authenticator_get_login (GckAuthenticator *self)
+{
+ g_return_val_if_fail (GCK_IS_AUTHENTICATOR (self), NULL);
+ return self->pv->login;
+}
+
+void
+gck_authenticator_set_login (GckAuthenticator *self, GckLogin *login)
+{
+ g_return_if_fail (GCK_IS_AUTHENTICATOR (self));
+
+ if (login) {
+ g_return_if_fail (GCK_IS_LOGIN (login));
+ g_object_ref (login);
+ }
+ if (self->pv->login)
+ g_object_unref (self->pv->login);
+ self->pv->login = login;
+
+ g_object_notify (G_OBJECT (self), "login");
+}
+
+const gchar*
+gck_authenticator_get_password (GckAuthenticator *self, gsize *n_password)
+{
+ g_return_val_if_fail (GCK_IS_AUTHENTICATOR (self), NULL);
+ g_return_val_if_fail (n_password, NULL);
+
+ if (!self->pv->login) {
+ *n_password = 0;
+ return NULL;
+ }
+
+ return gck_login_get_password (self->pv->login, n_password);
+}
+
+GckObject*
+gck_authenticator_get_object (GckAuthenticator *self)
+{
+ g_return_val_if_fail (GCK_IS_AUTHENTICATOR (self), NULL);
+ g_return_val_if_fail (GCK_IS_OBJECT (self->pv->object), NULL);
+ return self->pv->object;
+}
+
+gint
+gck_authenticator_get_uses_remaining (GckAuthenticator *self)
+{
+ g_return_val_if_fail (GCK_IS_AUTHENTICATOR (self), 0);
+ return self->pv->uses_remaining;
+}
+
+void
+gck_authenticator_set_uses_remaining (GckAuthenticator *self,
+ gint use_count)
+{
+ g_return_if_fail (GCK_IS_AUTHENTICATOR (self));
+ g_return_if_fail (use_count != 0);
+
+ self->pv->uses_remaining = use_count;
+ g_object_notify (G_OBJECT (self), "uses-remaining");
+}
+
+void
+gck_authenticator_throw_away_one_use (GckAuthenticator *self)
+{
+ g_return_if_fail (GCK_IS_AUTHENTICATOR (self));
+ if (self->pv->uses_remaining > 0)
+ --(self->pv->uses_remaining);
+ if (self->pv->uses_remaining == 0)
+ self_destruct (self);
+}
diff --git a/pkcs11/gck/gck-authenticator.h b/pkcs11/gck/gck-authenticator.h
new file mode 100644
index 0000000..e2d75a8
--- /dev/null
+++ b/pkcs11/gck/gck-authenticator.h
@@ -0,0 +1,77 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCK_AUTHENTICATOR_H__
+#define __GCK_AUTHENTICATOR_H__
+
+#include <glib-object.h>
+
+#include "gck-object.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_AUTHENTICATOR (gck_authenticator_get_factory ())
+
+#define GCK_TYPE_AUTHENTICATOR (gck_authenticator_get_type ())
+#define GCK_AUTHENTICATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_AUTHENTICATOR, GckAuthenticator))
+#define GCK_AUTHENTICATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_AUTHENTICATOR, GckAuthenticatorClass))
+#define GCK_IS_AUTHENTICATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_AUTHENTICATOR))
+#define GCK_IS_AUTHENTICATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_AUTHENTICATOR))
+#define GCK_AUTHENTICATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_AUTHENTICATOR, GckAuthenticatorClass))
+
+typedef struct _GckAuthenticatorClass GckAuthenticatorClass;
+typedef struct _GckAuthenticatorPrivate GckAuthenticatorPrivate;
+
+struct _GckAuthenticator {
+ GckObject parent;
+ GckAuthenticatorPrivate *pv;
+};
+
+struct _GckAuthenticatorClass {
+ GckObjectClass parent_class;
+};
+
+GType gck_authenticator_get_type (void);
+
+GckFactoryInfo* gck_authenticator_get_factory (void);
+
+CK_RV gck_authenticator_create (GckObject *object,
+ CK_UTF8CHAR_PTR pin,
+ CK_ULONG n_pin,
+ GckAuthenticator **result);
+
+GckLogin* gck_authenticator_get_login (GckAuthenticator *self);
+
+void gck_authenticator_set_login (GckAuthenticator *self,
+ GckLogin *login);
+
+const gchar* gck_authenticator_get_password (GckAuthenticator *self,
+ gsize *n_password);
+
+GckObject* gck_authenticator_get_object (GckAuthenticator *self);
+
+gint gck_authenticator_get_uses_remaining (GckAuthenticator *self);
+
+void gck_authenticator_set_uses_remaining (GckAuthenticator *self,
+ gint use_count);
+
+void gck_authenticator_throw_away_one_use (GckAuthenticator *self);
+
+#endif /* __GCK_AUTHENTICATOR_H__ */
diff --git a/pkcs11/gck/gck-key.c b/pkcs11/gck/gck-key.c
index 289fdbf..bc27704 100644
--- a/pkcs11/gck/gck-key.c
+++ b/pkcs11/gck/gck-key.c
@@ -283,10 +283,10 @@ gck_key_set_key_part (GckKey *self, int algo, const char *part,
}
GckSexp*
-gck_key_acquire_crypto_sexp (GckKey *self)
+gck_key_acquire_crypto_sexp (GckKey *self, GckSession *session)
{
g_return_val_if_fail (GCK_IS_KEY (self), NULL);
g_return_val_if_fail (GCK_KEY_GET_CLASS (self)->acquire_crypto_sexp, NULL);
- return GCK_KEY_GET_CLASS (self)->acquire_crypto_sexp (self);
+ return GCK_KEY_GET_CLASS (self)->acquire_crypto_sexp (self, session);
}
diff --git a/pkcs11/gck/gck-key.h b/pkcs11/gck/gck-key.h
index de73347..b2ab7f1 100644
--- a/pkcs11/gck/gck-key.h
+++ b/pkcs11/gck/gck-key.h
@@ -48,7 +48,7 @@ struct _GckKeyClass {
/* virtual methods */
- GckSexp* (*acquire_crypto_sexp) (GckKey *self);
+ GckSexp* (*acquire_crypto_sexp) (GckKey *self, GckSession *session);
};
GType gck_key_get_type (void);
@@ -65,6 +65,7 @@ CK_RV gck_key_set_key_part (GckKey *self,
const char *part,
CK_ATTRIBUTE_PTR attr);
-GckSexp* gck_key_acquire_crypto_sexp (GckKey *self);
+GckSexp* gck_key_acquire_crypto_sexp (GckKey *self,
+ GckSession *session);
#endif /* __GCK_KEY_H__ */
diff --git a/pkcs11/gck/gck-login.c b/pkcs11/gck/gck-login.c
index e197b49..43492b7 100644
--- a/pkcs11/gck/gck-login.c
+++ b/pkcs11/gck/gck-login.c
@@ -131,6 +131,7 @@ const gchar*
gck_login_get_password (GckLogin *self, gsize *n_password)
{
g_return_val_if_fail (GCK_IS_LOGIN (self), NULL);
+ g_return_val_if_fail (n_password, NULL);
*n_password = self->n_password;
return self->password;
}
diff --git a/pkcs11/gck/gck-module.c b/pkcs11/gck/gck-module.c
index f49fdac..5b2d1e9 100644
--- a/pkcs11/gck/gck-module.c
+++ b/pkcs11/gck/gck-module.c
@@ -26,6 +26,7 @@
#include "pkcs11/pkcs11i.h"
#include "gck-attributes.h"
+#include "gck-authenticator.h"
#include "gck-certificate.h"
#include "gck-factory.h"
#include "gck-manager.h"
@@ -412,14 +413,6 @@ add_transient_object (GckModule *self, GckTransaction *transaction, GckObject *o
}
}
-static void
-dispose_unref_object (gpointer obj)
-{
- g_assert (G_IS_OBJECT (obj));
- g_object_run_dispose (obj);
- g_object_unref (obj);
-}
-
/* -----------------------------------------------------------------------------
* OBJECT
*/
@@ -541,12 +534,13 @@ gck_module_init (GckModule *self)
/* Create the store for transient objects */
self->pv->transient_store = GCK_STORE (gck_memory_store_new ());
- self->pv->transient_objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, dispose_unref_object);
+ self->pv->transient_objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gck_util_dispose_unref);
/* Register session object factories */
gck_module_register_factory (self, GCK_FACTORY_PRIVATE_KEY);
gck_module_register_factory (self, GCK_FACTORY_CERTIFICATE);
gck_module_register_factory (self, GCK_FACTORY_PUBLIC_KEY);
+ gck_module_register_factory (self, GCK_FACTORY_AUTHENTICATOR);
}
static void
diff --git a/pkcs11/gck/gck-object.c b/pkcs11/gck/gck-object.c
index a210b53..e1188a9 100644
--- a/pkcs11/gck/gck-object.c
+++ b/pkcs11/gck/gck-object.c
@@ -75,7 +75,6 @@ kaboom_callback (GckTimer *timer, gpointer user_data)
GckObject *self = user_data;
GckTransaction *transaction;
GckObjectTransient *transient;
- GckSession *session;
CK_RV rv;
g_return_if_fail (GCK_IS_OBJECT (self));
@@ -89,9 +88,8 @@ kaboom_callback (GckTimer *timer, gpointer user_data)
transaction = gck_transaction_new ();
- session = gck_session_for_session_object (self);
- g_return_if_fail (session);
- gck_session_destroy_session_object (session, transaction, GCK_OBJECT (self));
+ /* Off we go */
+ gck_object_destroy (self, transaction);
gck_transaction_complete (transaction);
rv = gck_transaction_get_result (transaction);
@@ -100,7 +98,6 @@ kaboom_callback (GckTimer *timer, gpointer user_data)
if (rv != CKR_OK)
g_warning ("Unexpected failure to auto destruct object (code: %lu)", (gulong)rv);
- g_object_run_dispose (G_OBJECT (self));
g_object_unref (self);
}
@@ -130,6 +127,13 @@ module_went_away (gpointer data, GObject *old_module)
self->pv->module = NULL;
}
+static gboolean
+complete_destroy (GckTransaction *transaction, GObject *unused, gpointer user_data)
+{
+ gck_util_dispose_unref (user_data);
+ return TRUE;
+}
+
/* -----------------------------------------------------------------------------
* OBJECT
*/
@@ -264,7 +268,7 @@ gck_object_real_create_attributes (GckObject *self, GckTransaction *transaction,
}
static CK_RV
-gck_object_real_unlock (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
+gck_object_real_unlock (GckObject *self, GckAuthenticator *auth)
{
gboolean always_auth;
@@ -626,11 +630,11 @@ gck_object_get_transient (GckObject *self)
CK_RV
-gck_object_unlock (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
+gck_object_unlock (GckObject *self, GckAuthenticator *auth)
{
g_return_val_if_fail (GCK_IS_OBJECT (self), CKR_GENERAL_ERROR);
g_return_val_if_fail (GCK_OBJECT_GET_CLASS (self)->unlock, CKR_GENERAL_ERROR);
- return GCK_OBJECT_GET_CLASS (self)->unlock (self, pin, n_pin);
+ return GCK_OBJECT_GET_CLASS (self)->unlock (self, auth);
}
@@ -702,3 +706,33 @@ gck_object_get_attribute_data (GckObject *self, CK_ATTRIBUTE_TYPE type, gsize *n
*n_data = attr.ulValueLen;
return attr.pValue;
}
+
+void
+gck_object_destroy (GckObject *self, GckTransaction *transaction)
+{
+ GckSession *session;
+ GckManager *manager;
+ GckModule *module;
+
+ g_return_if_fail (GCK_IS_OBJECT (self));
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (!gck_transaction_get_failed (transaction));
+ g_return_if_fail (self->pv->module);
+
+ g_object_ref (self);
+
+ session = gck_session_for_session_object (self);
+ if (session != NULL) {
+ gck_session_destroy_session_object (session, transaction, self);
+ } else {
+ manager = gck_object_get_manager (self);
+ module = gck_object_get_module (self);
+ if (manager == gck_module_get_manager (module))
+ gck_module_remove_token_object (module, transaction, self);
+ }
+
+ /* Forcefully dispose of the object once the transaction completes */
+ gck_transaction_add (transaction, NULL, complete_destroy, g_object_ref (self));
+
+ g_object_unref (self);
+}
diff --git a/pkcs11/gck/gck-object.h b/pkcs11/gck/gck-object.h
index 44d79b8..10508e4 100644
--- a/pkcs11/gck/gck-object.h
+++ b/pkcs11/gck/gck-object.h
@@ -59,7 +59,7 @@ struct _GckObjectClass {
void (*create_attributes) (GckObject *object, GckTransaction *transaction, GckSession *session,
CK_ATTRIBUTE *attrs, CK_ULONG n_attrs);
- CK_RV (*unlock) (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin);
+ CK_RV (*unlock) (GckObject *self, GckAuthenticator *auth);
};
GType gck_object_get_type (void);
@@ -78,8 +78,10 @@ const gchar* gck_object_get_unique (GckObject *self);
gboolean gck_object_get_transient (GckObject *self);
CK_RV gck_object_unlock (GckObject *self,
- CK_UTF8CHAR_PTR pin,
- CK_ULONG n_pin);
+ GckAuthenticator *auth);
+
+void gck_object_destroy (GckObject *self,
+ GckTransaction *transaction);
gboolean gck_object_match (GckObject *self,
CK_ATTRIBUTE_PTR attr);
diff --git a/pkcs11/gck/gck-private-key.c b/pkcs11/gck/gck-private-key.c
index cd86093..ec19bcf 100644
--- a/pkcs11/gck/gck-private-key.c
+++ b/pkcs11/gck/gck-private-key.c
@@ -24,6 +24,7 @@
#include "pkcs11/pkcs11.h"
#include "gck-attributes.h"
+#include "gck-authenticator.h"
#include "gck-factory.h"
#include "gck-private-key.h"
#include "gck-session.h"
@@ -31,7 +32,6 @@
#include "gck-util.h"
struct _GckPrivateKeyPrivate {
- guint sexp_uses;
GckSexp *sexp;
};
@@ -147,6 +147,7 @@ static void
factory_create_private_key (GckSession *session, GckTransaction *transaction,
CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
{
+ GckPrivateKey *key;
GckSexp *sexp;
g_return_if_fail (GCK_IS_TRANSACTION (transaction));
@@ -157,10 +158,29 @@ factory_create_private_key (GckSession *session, GckTransaction *transaction,
if (sexp == NULL)
return;
- *object = g_object_new (GCK_TYPE_PRIVATE_KEY, "base-sexp", sexp,
- "module", gck_session_get_module (session), NULL);
- gck_private_key_store_private (GCK_PRIVATE_KEY (*object), sexp, G_MAXUINT);
- gck_sexp_unref (sexp);
+ key = g_object_new (GCK_TYPE_PRIVATE_KEY, "base-sexp", sexp,
+ "module", gck_session_get_module (session), NULL);
+ key->pv->sexp = sexp;
+ *object = GCK_OBJECT (key);
+}
+
+static gboolean
+acquire_from_authenticator (GckAuthenticator *auth, GckObject *object, gpointer user_data)
+{
+ GckSexp **result = user_data;
+
+ g_assert (result);
+ g_assert (!*result);
+
+ /* The sexp we stored on the authenticator */
+ *result = g_object_get_data (G_OBJECT (auth), "private-key-sexp");
+ if (*result != NULL) {
+ *result = gck_sexp_ref (*result);
+ gck_authenticator_throw_away_one_use (auth);
+ return TRUE;
+ }
+
+ return FALSE;
}
/* -----------------------------------------------------------------------------
@@ -210,7 +230,7 @@ gck_private_key_real_get_attribute (GckObject *base, CK_ATTRIBUTE* attr)
return CKR_ATTRIBUTE_TYPE_INVALID;
case CKA_ALWAYS_AUTHENTICATE:
- return gck_attribute_set_bool (attr, self->pv->sexp_uses <= 1);
+ return gck_attribute_set_bool (attr, self->pv->sexp == NULL);
case CKA_MODULUS:
return gck_key_set_key_part (GCK_KEY (self), GCRY_PK_RSA, "n", attr);
@@ -245,26 +265,20 @@ gck_private_key_real_get_attribute (GckObject *base, CK_ATTRIBUTE* attr)
}
static GckSexp*
-gck_private_key_real_acquire_crypto_sexp (GckKey *base)
+gck_private_key_real_acquire_crypto_sexp (GckKey *base, GckSession *session)
{
GckPrivateKey *self = GCK_PRIVATE_KEY (base);
- GckSexp *sexp;
+ GckSexp *sexp = NULL;
- if (self->pv->sexp_uses == 0) {
- g_return_val_if_fail (!self->pv->sexp, NULL);
- return NULL;
- }
+ /* We have an unlocked private key here */
+ if (self->pv->sexp)
+ sexp = gck_sexp_ref (self->pv->sexp);
+
+ /* Find an authenticator, with an unlocked copy */
+ else
+ gck_session_for_each_authenticator (session, GCK_OBJECT (self),
+ acquire_from_authenticator, &sexp);
- g_return_val_if_fail (self->pv->sexp, NULL);
-
- sexp = gck_sexp_ref (self->pv->sexp);
- --(self->pv->sexp_uses);
-
- if (self->pv->sexp_uses == 0) {
- gck_sexp_unref (self->pv->sexp);
- self->pv->sexp = NULL;
- }
-
return sexp;
}
@@ -356,19 +370,33 @@ gck_private_key_class_init (GckPrivateKeyClass *klass)
*/
void
-gck_private_key_store_private (GckPrivateKey *self, GckSexp *sexp, guint num_uses)
+gck_private_key_set_unlocked_private (GckPrivateKey *self, GckSexp *sexp)
{
g_return_if_fail (GCK_IS_PRIVATE_KEY (self));
- g_return_if_fail (!sexp || num_uses);
-
+ g_return_if_fail (sexp);
+
if (sexp)
gck_sexp_ref (sexp);
- if (self->pv->sexp)
+ if (self->pv->sexp)
gck_sexp_unref (self->pv->sexp);
self->pv->sexp = sexp;
- self->pv->sexp_uses = num_uses;
}
+void
+gck_private_key_set_locked_private (GckPrivateKey *self, GckAuthenticator *auth,
+ GckSexp *sexp, gint num_uses)
+{
+ g_return_if_fail (GCK_IS_PRIVATE_KEY (self));
+ g_return_if_fail (GCK_IS_AUTHENTICATOR (auth));
+ g_return_if_fail (!sexp || num_uses);
+
+ if (sexp == NULL)
+ g_object_set_data (G_OBJECT (auth), "private-key-sexp", NULL);
+ else
+ g_object_set_data_full (G_OBJECT (auth), "private-key-sexp",
+ gck_sexp_ref (sexp), gck_sexp_unref);
+ gck_authenticator_set_uses_remaining (auth, num_uses);
+}
GckSexp*
gck_private_key_create_sexp (GckSession *session, GckTransaction *transaction,
diff --git a/pkcs11/gck/gck-private-key.h b/pkcs11/gck/gck-private-key.h
index f68ec59..4a7a450 100644
--- a/pkcs11/gck/gck-private-key.h
+++ b/pkcs11/gck/gck-private-key.h
@@ -50,9 +50,13 @@ struct _GckPrivateKeyClass {
GType gck_private_key_get_type (void);
-void gck_private_key_store_private (GckPrivateKey *self,
+void gck_private_key_set_unlocked_private (GckPrivateKey *self,
+ GckSexp *sexp);
+
+void gck_private_key_set_locked_private (GckPrivateKey *self,
+ GckAuthenticator *auth,
GckSexp *sexp,
- guint num_uses);
+ gint num_uses);
GckFactoryInfo* gck_private_key_get_factory (void);
diff --git a/pkcs11/gck/gck-public-key.c b/pkcs11/gck/gck-public-key.c
index 404474c..ce2fe48 100644
--- a/pkcs11/gck/gck-public-key.c
+++ b/pkcs11/gck/gck-public-key.c
@@ -216,7 +216,7 @@ gck_public_key_real_get_attribute (GckObject *base, CK_ATTRIBUTE* attr)
}
static GckSexp*
-gck_public_key_acquire_crypto_sexp (GckKey *self)
+gck_public_key_acquire_crypto_sexp (GckKey *self, GckSession *session)
{
GckSexp* sexp;
diff --git a/pkcs11/gck/gck-session.c b/pkcs11/gck/gck-session.c
index dd4e70a..6c95535 100644
--- a/pkcs11/gck/gck-session.c
+++ b/pkcs11/gck/gck-session.c
@@ -25,6 +25,7 @@
#include "pkcs11/pkcs11i.h"
#include "gck-attributes.h"
+#include "gck-authenticator.h"
#include "gck-crypto.h"
#include "gck-key.h"
#include "gck-factory.h"
@@ -33,6 +34,7 @@
#include "gck-session.h"
#include "gck-sexp.h"
#include "gck-transaction.h"
+#include "gck-util.h"
enum {
PROP_0,
@@ -62,9 +64,10 @@ struct _GckSessionPrivate {
/* Objects owned by this session */
GHashTable *objects;
- /* Used for context specific logins */
+ /* Used for operations */
void (*current_operation) (GckSession *self);
GckObject *current_object;
+ GckAuthenticator *authenticator;
/* Used for find operations */
GArray *found_objects;
@@ -100,8 +103,14 @@ cleanup_crypto (GckSession *self)
g_assert (GCK_IS_KEY (self->pv->current_object));
if (self->pv->current_object)
g_object_unref (self->pv->current_object);
-
self->pv->current_object = NULL;
+
+ if (self->pv->authenticator) {
+ g_object_set_data (G_OBJECT (self->pv->authenticator), "owned-by-session", NULL);
+ g_object_unref (self->pv->authenticator);
+ self->pv->authenticator = NULL;
+ }
+
self->pv->current_operation = NULL;
}
@@ -186,7 +195,7 @@ process_crypto (GckSession *self, CK_ATTRIBUTE_TYPE method, CK_BYTE_PTR bufone,
/* Load up the actual sexp we're going to use */
if (!self->pv->crypto_sexp) {
g_return_val_if_fail (GCK_IS_KEY (self->pv->current_object), CKR_GENERAL_ERROR);
- self->pv->crypto_sexp = gck_key_acquire_crypto_sexp (GCK_KEY (self->pv->current_object));
+ self->pv->crypto_sexp = gck_key_acquire_crypto_sexp (GCK_KEY (self->pv->current_object), self);
if (!self->pv->crypto_sexp)
rv = CKR_USER_NOT_LOGGED_IN;
}
@@ -345,14 +354,6 @@ add_object (GckSession *self, GckTransaction *transaction, GckObject *object)
g_object_ref (object));
}
-static void
-dispose_unref_object (gpointer obj)
-{
- g_assert (G_IS_OBJECT (obj));
- g_object_run_dispose (obj);
- g_object_unref (obj);
-}
-
static gboolean
attributes_find_boolean (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs,
CK_ATTRIBUTE_TYPE type, CK_BBOOL *value)
@@ -400,7 +401,7 @@ static void
gck_session_init (GckSession *self)
{
self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_SESSION, GckSessionPrivate);
- self->pv->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, dispose_unref_object);
+ self->pv->objects = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, gck_util_dispose_unref);
self->pv->read_only = TRUE;
/* Create the store and register attributes */
@@ -421,6 +422,12 @@ gck_session_dispose (GObject *obj)
g_object_unref (self->pv->module);
self->pv->module = NULL;
+ if (self->pv->authenticator) {
+ g_object_set_data (G_OBJECT (self->pv->authenticator), "owned-by-session", NULL);
+ g_object_unref (self->pv->authenticator);
+ self->pv->authenticator = NULL;
+ }
+
if (self->pv->manager)
g_object_unref (self->pv->manager);
self->pv->manager = NULL;
@@ -635,9 +642,11 @@ gck_session_lookup_writable_object (GckSession *self, CK_OBJECT_HANDLE handle,
CK_RV
gck_session_login_context_specific (GckSession *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
{
+ GckAuthenticator *authenticator;
gboolean always_auth;
gboolean is_private;
GckObject *object;
+ CK_RV rv;
g_return_val_if_fail (GCK_IS_SESSION (self), CKR_GENERAL_ERROR);
@@ -658,8 +667,18 @@ gck_session_login_context_specific (GckSession *self, CK_UTF8CHAR_PTR pin, CK_UL
/* Double check that the object has what it takes */
g_return_val_if_fail (is_private == TRUE, CKR_GENERAL_ERROR);
-
- return gck_object_unlock (object, pin, n_pin);
+
+ /* Now create the strange object */
+ rv = gck_authenticator_create (self->pv->current_object, pin, n_pin, &authenticator);
+ if (rv != CKR_OK)
+ return rv;
+
+ if (self->pv->authenticator)
+ g_object_unref (self->pv->authenticator);
+ g_object_set_data (G_OBJECT (authenticator), "owned-by-session", self);
+ self->pv->authenticator = authenticator;
+
+ return CKR_OK;
}
void
@@ -671,9 +690,69 @@ gck_session_destroy_session_object (GckSession *self, GckTransaction *transactio
g_return_if_fail (GCK_IS_TRANSACTION (transaction));
g_return_if_fail (!gck_transaction_get_failed (transaction));
+ /* Don't actually destroy the authenticator */
+ if (self->pv->authenticator && GCK_OBJECT (self->pv->authenticator) == obj)
+ return;
+
remove_object (self, transaction, obj);
}
+void
+gck_session_for_each_authenticator (GckSession *self, GckObject *object,
+ GckAuthenticatorFunc func, gpointer user_data)
+{
+ CK_OBJECT_HANDLE handle;
+ CK_OBJECT_CLASS klass;
+ CK_ATTRIBUTE attrs[2];
+ GList *results, *l;
+
+ g_return_if_fail (GCK_IS_SESSION (self));
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_return_if_fail (func);
+
+ /* Do we have one right on the session */
+ if (self->pv->authenticator != NULL &&
+ gck_authenticator_get_object (self->pv->authenticator) == object) {
+ if ((func) (self->pv->authenticator, object, user_data))
+ return;
+ }
+
+ klass = CKO_GNOME_AUTHENTICATOR;
+ attrs[0].type = CKA_CLASS;
+ attrs[0].pValue = &klass;
+ attrs[0].ulValueLen = sizeof (klass);
+
+ handle = gck_object_get_handle (object);
+ attrs[1].type = CKA_GNOME_OBJECT;
+ attrs[1].pValue = &handle;
+ attrs[1].ulValueLen = sizeof (handle);
+
+ /* Find any on the session */
+ results = gck_manager_find_by_attributes (self->pv->manager,
+ attrs, G_N_ELEMENTS (attrs));
+
+ for (l = results; l; l = g_list_next (l)) {
+ if ((func) (l->data, object, user_data))
+ break;
+ }
+
+ g_list_free (results);
+
+ if (l != NULL)
+ return;
+
+ /* Find any in the token */
+ results = gck_manager_find_by_attributes (gck_module_get_manager (self->pv->module),
+ attrs, G_N_ELEMENTS (attrs));
+
+ for (l = results; l; l = g_list_next (l)) {
+ if ((func) (l->data, object, user_data))
+ break;
+ }
+
+ g_list_free (results);
+}
+
/* -----------------------------------------------------------------------------
* PKCS#11
*/
diff --git a/pkcs11/gck/gck-session.h b/pkcs11/gck/gck-session.h
index 815e62c..697e925 100644
--- a/pkcs11/gck/gck-session.h
+++ b/pkcs11/gck/gck-session.h
@@ -52,6 +52,10 @@ struct _GckSessionClass {
#endif
};
+typedef gboolean (*GckAuthenticatorFunc) (GckAuthenticator *auth,
+ GckObject *object,
+ gpointer user_data);
+
GType gck_session_get_type (void);
GckSession* gck_session_new (GckModule *module,
@@ -92,6 +96,10 @@ void gck_session_destroy_session_object (GckSess
GckTransaction *transaction,
GckObject *obj);
+void gck_session_for_each_authenticator (GckSession *self,
+ GckObject *object,
+ GckAuthenticatorFunc func,
+ gpointer user_data);
diff --git a/pkcs11/gck/gck-sexp.c b/pkcs11/gck/gck-sexp.c
index 70f275f..a15549d 100644
--- a/pkcs11/gck/gck-sexp.c
+++ b/pkcs11/gck/gck-sexp.c
@@ -48,8 +48,9 @@ gck_sexp_ref (GckSexp *sexp)
}
void
-gck_sexp_unref (GckSexp *sexp)
+gck_sexp_unref (gpointer data)
{
+ GckSexp *sexp = data;
g_return_if_fail (sexp);
if (--(sexp->refs) == 0) {
g_assert (sexp->real);
diff --git a/pkcs11/gck/gck-sexp.h b/pkcs11/gck/gck-sexp.h
index e338829..e3f9089 100644
--- a/pkcs11/gck/gck-sexp.h
+++ b/pkcs11/gck/gck-sexp.h
@@ -32,7 +32,7 @@ GckSexp* gck_sexp_new (gcry_sexp_t sexp);
GckSexp* gck_sexp_ref (GckSexp *sexp);
-void gck_sexp_unref (GckSexp *sexp);
+void gck_sexp_unref (gpointer sexp);
gcry_sexp_t gck_sexp_get (GckSexp *sexp);
diff --git a/pkcs11/gck/gck-types.h b/pkcs11/gck/gck-types.h
index 67ae9de..ea27e6d 100644
--- a/pkcs11/gck/gck-types.h
+++ b/pkcs11/gck/gck-types.h
@@ -22,6 +22,7 @@
#ifndef __GCK_TYPES_H__
#define __GCK_TYPES_H__
+typedef struct _GckAuthenticator GckAuthenticator;
typedef struct _GckCertificate GckCertificate;
typedef struct _GckCertificateKey GckCertificateKey;
typedef struct _GckCertificateTrust GckCertificateTrust;
diff --git a/pkcs11/gck/gck-util.c b/pkcs11/gck/gck-util.c
index 6e807fd..c6439b9 100644
--- a/pkcs11/gck/gck-util.c
+++ b/pkcs11/gck/gck-util.c
@@ -23,6 +23,9 @@
#include "gck-util.h"
+#include <glib.h>
+#include <glib-object.h>
+
#include <stdio.h>
#include <string.h>
@@ -87,3 +90,11 @@ gck_util_next_handle (void)
{
return (CK_ULONG)g_atomic_int_exchange_and_add (&next_handle, 1);
}
+
+void
+gck_util_dispose_unref (gpointer object)
+{
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_object_run_dispose (G_OBJECT (object));
+ g_object_unref (object);
+}
diff --git a/pkcs11/gck/gck-util.h b/pkcs11/gck/gck-util.h
index 97e3556..18be87e 100644
--- a/pkcs11/gck/gck-util.h
+++ b/pkcs11/gck/gck-util.h
@@ -47,4 +47,6 @@ CK_RV gck_attribute_set_mpi (CK_ATTRIBUTE_
CK_ULONG gck_util_next_handle (void);
+void gck_util_dispose_unref (gpointer object);
+
#endif /* GCKUTIL_H_ */
diff --git a/pkcs11/gck/tests/Makefile.am b/pkcs11/gck/tests/Makefile.am
index 4bd2b10..96fe68e 100644
--- a/pkcs11/gck/tests/Makefile.am
+++ b/pkcs11/gck/tests/Makefile.am
@@ -12,6 +12,7 @@ UNIT_AUTO = \
unit-test-data-asn1.c \
unit-test-data-der.c \
unit-test-object.c \
+ unit-test-authenticator.c \
unit-test-timer.c \
unit-test-transaction.c \
unit-test-store.c \
@@ -19,6 +20,7 @@ UNIT_AUTO = \
unit-test-login.c \
unit-test-data-file.c \
unit-test-file-tracker.c \
+ mock-locked-object.c mock-locked-object.h \
test-module.c test-module.h \
$(BUILT_SOURCES)
diff --git a/pkcs11/gck/tests/mock-locked-object.c b/pkcs11/gck/tests/mock-locked-object.c
new file mode 100644
index 0000000..882d100
--- /dev/null
+++ b/pkcs11/gck/tests/mock-locked-object.c
@@ -0,0 +1,88 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "mock-locked-object.h"
+
+#include "gck/gck-attributes.h"
+#include "gck/gck-authenticator.h"
+
+G_DEFINE_TYPE (MockLockedObject, mock_locked_object, GCK_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+/* -----------------------------------------------------------------------------
+ * KEY
+ */
+
+static CK_RV
+mock_locked_object_real_get_attribute (GckObject *base, CK_ATTRIBUTE* attr)
+{
+ switch (attr->type) {
+ case CKA_CLASS:
+ return gck_attribute_set_ulong (attr, CKO_DATA);
+ case CKA_ALWAYS_AUTHENTICATE:
+ return gck_attribute_set_bool (attr, TRUE);
+ };
+
+ return GCK_OBJECT_CLASS (mock_locked_object_parent_class)->get_attribute (base, attr);
+}
+
+static CK_RV
+mock_locked_object_real_unlock (GckObject *base, GckAuthenticator *auth)
+{
+ const gchar *password;
+ gsize n_password;
+
+ password = gck_authenticator_get_password (auth, &n_password);
+ if (n_password == 4 && memcmp (password, "mock", 4) == 0)
+ return CKR_OK;
+
+ return CKR_USER_NOT_LOGGED_IN;
+}
+
+static void
+mock_locked_object_init (MockLockedObject *self)
+{
+
+}
+
+static void
+mock_locked_object_class_init (MockLockedObjectClass *klass)
+{
+ GckObjectClass *gck_class = GCK_OBJECT_CLASS (klass);
+ mock_locked_object_parent_class = g_type_class_peek_parent (klass);
+ gck_class->get_attribute = mock_locked_object_real_get_attribute;
+ gck_class->unlock = mock_locked_object_real_unlock;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GckObject*
+mock_locked_object_new (GckModule *module)
+{
+ return g_object_new (MOCK_TYPE_LOCKED_OBJECT, "module", module, NULL);
+}
diff --git a/pkcs11/gck/tests/mock-locked-object.h b/pkcs11/gck/tests/mock-locked-object.h
new file mode 100644
index 0000000..0ed6080
--- /dev/null
+++ b/pkcs11/gck/tests/mock-locked-object.h
@@ -0,0 +1,52 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2009 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __MOCK_LOCKED_OBJECT_H__
+#define __MOCK_LOCKED_OBJECT_H__
+
+#include <glib-object.h>
+
+#include "gck-object.h"
+#include "gck-types.h"
+
+#define MOCK_TYPE_LOCKED_OBJECT (mock_locked_object_get_type ())
+#define MOCK_LOCKED_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MOCK_TYPE_LOCKED_OBJECT, MockLockedObject))
+#define MOCK_LOCKED_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MOCK_TYPE_LOCKED_OBJECT, MockLockedObjectClass))
+#define MOCK_IS_LOCKED_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MOCK_TYPE_LOCKED_OBJECT))
+#define MOCK_IS_LOCKED_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MOCK_TYPE_LOCKED_OBJECT))
+#define MOCK_LOCKED_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MOCK_TYPE_LOCKED_OBJECT, MockLockedObjectClass))
+
+typedef struct _MockLockedObject MockLockedObject;
+typedef struct _MockLockedObjectClass MockLockedObjectClass;
+
+struct _MockLockedObject {
+ GckObject parent;
+};
+
+struct _MockLockedObjectClass {
+ GckObjectClass parent_class;
+};
+
+GType mock_locked_object_get_type (void);
+
+GckObject* mock_locked_object_new (GckModule *module);
+
+#endif /* __MOCK_LOCKED_OBJECT_H__ */
diff --git a/pkcs11/gck/tests/test-module.c b/pkcs11/gck/tests/test-module.c
index cb2f395..e36071d 100644
--- a/pkcs11/gck/tests/test-module.c
+++ b/pkcs11/gck/tests/test-module.c
@@ -28,15 +28,8 @@
#include "gck/gck-module-ep.h"
GCK_DEFINE_MODULE (test_module, GCK_TYPE_MODULE);
-CK_FUNCTION_LIST_PTR
-test_module_get_functions (void)
-{
- gck_crypto_initialize ();
- return test_module_function_list;
-}
-
GckModule*
-test_module_initialize (void)
+test_module_initialize_and_enter (void)
{
CK_RV rv;
@@ -45,14 +38,17 @@ test_module_initialize (void)
g_return_val_if_fail (rv == CKR_OK, NULL);
g_return_val_if_fail (pkcs11_module, NULL);
+
+ test_module_enter ();
return pkcs11_module;
}
void
-test_module_finalize (void)
+test_module_leave_and_finalize (void)
{
CK_RV rv;
+ test_module_leave ();
rv = test_module_function_list->C_Finalize (NULL);
g_return_if_fail (rv == CKR_OK);
}
@@ -68,3 +64,23 @@ test_module_enter (void)
{
g_static_mutex_lock (&pkcs11_module_mutex);
}
+
+GckSession*
+test_module_open_session (gboolean writable)
+{
+ CK_ULONG flags = CKF_SERIAL_SESSION;
+ CK_SESSION_HANDLE handle;
+ GckSession *session;
+ CK_RV rv;
+
+ if (writable)
+ flags |= CKF_RW_SESSION;
+
+ rv = gck_module_C_OpenSession (pkcs11_module, 1, flags, NULL, NULL, &handle);
+ g_assert (rv == CKR_OK);
+
+ session = gck_module_lookup_session (pkcs11_module, handle);
+ g_assert (session);
+
+ return session;
+}
diff --git a/pkcs11/gck/tests/test-module.h b/pkcs11/gck/tests/test-module.h
index 8a8ba3f..631dd5b 100644
--- a/pkcs11/gck/tests/test-module.h
+++ b/pkcs11/gck/tests/test-module.h
@@ -24,18 +24,20 @@
#ifndef TESTMODULE_H_
#define TESTMODULE_H_
+#include <glib.h>
+
#include "gck-types.h"
#include "pkcs11.h"
-CK_FUNCTION_LIST_PTR test_module_get_functions (void);
-
void test_module_leave (void);
void test_module_enter (void);
-GckModule* test_module_initialize (void);
+GckModule* test_module_initialize_and_enter (void);
+
+void test_module_leave_and_finalize (void);
-void test_module_finalize (void);
+GckSession* test_module_open_session (gboolean writable);
#endif /* TESTMODULE_H_ */
diff --git a/pkcs11/gck/tests/unit-test-authenticator.c b/pkcs11/gck/tests/unit-test-authenticator.c
new file mode 100644
index 0000000..ff2fe14
--- /dev/null
+++ b/pkcs11/gck/tests/unit-test-authenticator.c
@@ -0,0 +1,254 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-timer.c: Test thread timer functionality
+
+ Copyright (C) 2009 Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "run-auto-test.h"
+#include "test-module.h"
+#include "mock-locked-object.h"
+
+#include "gck/gck-attributes.h"
+#include "gck/gck-authenticator.h"
+#include "gck/gck-login.h"
+#include "gck/gck-object.h"
+#include "gck/gck-session.h"
+#include "gck/gck-module.h"
+
+#include "pkcs11g.h"
+
+static GckModule *module = NULL;
+static GckSession *session = NULL;
+static GckObject *object = NULL;
+
+DEFINE_SETUP(authenticator_setup)
+{
+ CK_RV rv;
+ module = test_module_initialize_and_enter ();
+ session = test_module_open_session (TRUE);
+
+ rv = gck_module_C_Login (module, gck_session_get_handle (session), CKU_USER, NULL, 0);
+ g_assert (rv == CKR_OK);
+
+ object = mock_locked_object_new (module);
+ gck_manager_register_object (gck_module_get_manager (module), object);
+}
+
+DEFINE_TEARDOWN(authenticator_teardown)
+{
+ g_object_unref (object);
+ object = NULL;
+
+ test_module_leave_and_finalize ();
+ module = NULL;
+ session = NULL;
+}
+
+DEFINE_TEST(authenticator_create)
+{
+ CK_OBJECT_CLASS klass = CKO_GNOME_AUTHENTICATOR;
+ CK_OBJECT_HANDLE locked = gck_object_get_handle (object);
+
+ CK_ATTRIBUTE attrs[] = {
+ { CKA_CLASS, &klass, sizeof (klass) },
+ { CKA_GNOME_OBJECT, &locked, sizeof (locked) },
+ { CKA_VALUE, "mock", 4 },
+ };
+
+ CK_OBJECT_HANDLE handle;
+ CK_RV rv;
+
+ rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+ g_assert (rv == CKR_OK);
+ g_assert (handle != 0);
+
+ rv = gck_session_C_DestroyObject (session, handle);
+ g_assert (rv == CKR_OK);
+}
+
+DEFINE_TEST(authenticator_create_missing_pin)
+{
+ CK_OBJECT_CLASS klass = CKO_GNOME_AUTHENTICATOR;
+ CK_OBJECT_HANDLE locked = gck_object_get_handle (object);
+
+ CK_ATTRIBUTE attrs[] = {
+ { CKA_CLASS, &klass, sizeof (klass) },
+ { CKA_GNOME_OBJECT, &locked, sizeof (locked) },
+ };
+
+ CK_OBJECT_HANDLE handle;
+ CK_RV rv;
+
+ rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+ g_assert (rv == CKR_USER_NOT_LOGGED_IN);
+}
+
+DEFINE_TEST(authenticator_create_no_object)
+{
+ CK_OBJECT_CLASS klass = CKO_GNOME_AUTHENTICATOR;
+ CK_BBOOL token = CK_FALSE;
+
+ CK_ATTRIBUTE attrs[] = {
+ { CKA_TOKEN, &token, sizeof (token) },
+ { CKA_CLASS, &klass, sizeof (klass) },
+ };
+
+ CK_OBJECT_HANDLE handle;
+ CK_RV rv;
+
+ rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+ g_assert (rv == CKR_TEMPLATE_INCOMPLETE);
+}
+
+DEFINE_TEST(authenticator_create_invalid_object)
+{
+ CK_OBJECT_CLASS klass = CKO_GNOME_AUTHENTICATOR;
+ CK_OBJECT_HANDLE locked = 0;
+ CK_BBOOL token = CK_FALSE;
+
+ CK_ATTRIBUTE attrs[] = {
+ { CKA_TOKEN, &token, sizeof (token) },
+ { CKA_CLASS, &klass, sizeof (klass) },
+ { CKA_GNOME_OBJECT, &locked, sizeof (locked) },
+ };
+
+ CK_OBJECT_HANDLE handle;
+ CK_RV rv;
+
+ rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+ g_assert (rv == CKR_OBJECT_HANDLE_INVALID);
+}
+
+DEFINE_TEST(authenticator_get_attributes)
+{
+ CK_OBJECT_CLASS klass = CKO_GNOME_AUTHENTICATOR;
+ CK_OBJECT_HANDLE locked = gck_object_get_handle (object);
+
+ CK_ATTRIBUTE attrs[] = {
+ { CKA_CLASS, &klass, sizeof (klass) },
+ { CKA_GNOME_OBJECT, &locked, sizeof (locked) },
+ { CKA_VALUE, "mock", 4 },
+ };
+
+ CK_OBJECT_HANDLE handle;
+ CK_ATTRIBUTE check;
+ CK_ULONG value;
+ CK_RV rv;
+
+ rv = gck_session_C_CreateObject (session, attrs, G_N_ELEMENTS (attrs), &handle);
+ g_assert (rv == CKR_OK);
+ g_assert (handle != 0);
+
+ check.type = CKA_GNOME_OBJECT;
+ check.pValue = &value;
+ check.ulValueLen = sizeof (value);
+
+ rv = gck_session_C_GetAttributeValue (session, handle, &check, 1);
+ g_assert (rv == CKR_OK);
+ g_assert (check.ulValueLen == sizeof (value));
+ g_assert (value == locked);
+
+ check.type = CKA_GNOME_USES_REMAINING;
+ check.pValue = &value;
+ check.ulValueLen = sizeof (value);
+
+ rv = gck_session_C_GetAttributeValue (session, handle, &check, 1);
+ g_assert (rv == CKR_OK);
+ g_assert (check.ulValueLen == sizeof (value));
+ g_assert (value == (CK_ULONG)-1);
+}
+
+DEFINE_TEST(authenticator_uses_property)
+{
+ GckAuthenticator *auth;
+ gint uses;
+ CK_RV rv;
+
+ rv = gck_authenticator_create (object, (guchar*)"mock", 4, &auth);
+ g_assert (rv == CKR_OK);
+ g_assert (auth);
+
+ g_object_get (auth, "uses-remaining", &uses, NULL);
+ g_assert (uses == -1);
+
+ gck_authenticator_set_uses_remaining (auth, 5);
+
+ uses = gck_authenticator_get_uses_remaining (auth);
+ g_assert (uses == 5);
+
+ gck_authenticator_throw_away_one_use (auth);
+ uses = gck_authenticator_get_uses_remaining (auth);
+ g_assert (uses == 4);
+
+ g_object_unref (auth);
+}
+
+DEFINE_TEST(authenticator_object_property)
+{
+ GckAuthenticator *auth;
+ GckObject *check;
+ CK_RV rv;
+
+ rv = gck_authenticator_create (object, (guchar*)"mock", 4, &auth);
+ g_assert (rv == CKR_OK);
+ g_assert (auth);
+
+ g_object_get (auth, "object", &check, NULL);
+ g_assert (check == object);
+ g_object_unref (check);
+
+ check = gck_authenticator_get_object (auth);
+ g_assert (check == object);
+
+ g_object_unref (auth);
+}
+
+DEFINE_TEST(authenticator_login_property)
+{
+ GckAuthenticator *auth;
+ GckLogin *check, *login;
+ const gchar *password;
+ gsize n_password;
+ CK_RV rv;
+
+ rv = gck_authenticator_create (object, (guchar*)"mock", 4, &auth);
+ g_assert (rv == CKR_OK);
+ g_assert (auth);
+
+ g_object_get (auth, "login", &check, NULL);
+ g_assert (check);
+ password = gck_login_get_password (check, &n_password);
+ g_assert (n_password == 4);
+ g_assert (memcmp (password, "mock", 4) == 0);
+ g_object_unref (check);
+
+ check = gck_authenticator_get_login (auth);
+ g_assert (n_password == 4);
+ g_assert (memcmp (password, "mock", 4) == 0);
+
+ login = gck_login_new ((guchar*)"xxx", -1);
+ gck_authenticator_set_login (auth, login);
+ check = gck_authenticator_get_login (auth);
+ g_assert (n_password == 4);
+ g_assert (memcmp (password, "mock", 4) == 0);
+ g_object_unref (login);
+
+ g_object_unref (auth);
+}
diff --git a/pkcs11/gck/tests/unit-test-memory-store.c b/pkcs11/gck/tests/unit-test-memory-store.c
index 880e867..162a15f 100644
--- a/pkcs11/gck/tests/unit-test-memory-store.c
+++ b/pkcs11/gck/tests/unit-test-memory-store.c
@@ -64,8 +64,7 @@ DEFINE_SETUP(memory_store)
CK_ATTRIBUTE attr;
CK_ULONG twentyfour = 24;
- module = test_module_initialize ();
- test_module_enter ();
+ module = test_module_initialize_and_enter ();
attr.type = CKA_LABEL;
attr.pValue = "label";
@@ -105,8 +104,7 @@ DEFINE_TEARDOWN(memory_store)
g_object_unref (object);
object = NULL;
- test_module_leave ();
- test_module_finalize ();
+ test_module_leave_and_finalize ();
module = NULL;
}
diff --git a/pkcs11/gck/tests/unit-test-object.c b/pkcs11/gck/tests/unit-test-object.c
index d55f36d..3cb323a 100644
--- a/pkcs11/gck/tests/unit-test-object.c
+++ b/pkcs11/gck/tests/unit-test-object.c
@@ -38,35 +38,18 @@ static gsize certificate_n_data = 0;
DEFINE_SETUP(object_setup)
{
- CK_SESSION_HANDLE handle;
- CK_RV rv;
-
- module = test_module_initialize ();
- test_module_enter ();
-
- rv = gck_module_C_OpenSession (module, 1, CKF_SERIAL_SESSION | CKF_RW_SESSION,
- NULL, NULL, &handle);
- g_assert (rv == CKR_OK);
-
- session = gck_module_lookup_session (module, handle);
- g_assert (session);
-
+ module = test_module_initialize_and_enter ();
+ session = test_module_open_session (TRUE);
certificate_data = test_read_testdata ("test-certificate-1.der", &certificate_n_data);
}
DEFINE_TEARDOWN(object_teardown)
{
- CK_RV rv;
-
g_free (certificate_data);
certificate_data = NULL;
certificate_n_data = 0;
- rv = gck_module_C_CloseAllSessions (module, 1);
- g_assert (rv == CKR_OK);
-
- test_module_leave ();
- test_module_finalize ();
+ test_module_leave_and_finalize ();
module = NULL;
session = NULL;
}
diff --git a/pkcs11/gck/tests/unit-test-store.c b/pkcs11/gck/tests/unit-test-store.c
index a53fd14..5096677 100644
--- a/pkcs11/gck/tests/unit-test-store.c
+++ b/pkcs11/gck/tests/unit-test-store.c
@@ -36,9 +36,7 @@ static GckStore *store = NULL;
DEFINE_SETUP(store)
{
- module = test_module_initialize ();
- test_module_enter ();
-
+ module = test_module_initialize_and_enter ();
store = g_object_new (GCK_TYPE_STORE, NULL);
}
@@ -47,8 +45,7 @@ DEFINE_TEARDOWN(store)
g_object_unref (store);
store = NULL;
- test_module_leave ();
- test_module_finalize ();
+ test_module_leave_and_finalize ();
module = NULL;
}
diff --git a/pkcs11/gck/tests/unit-test-timer.c b/pkcs11/gck/tests/unit-test-timer.c
index d463041..f9b42cf 100644
--- a/pkcs11/gck/tests/unit-test-timer.c
+++ b/pkcs11/gck/tests/unit-test-timer.c
@@ -30,14 +30,12 @@ static GckModule *module = NULL;
DEFINE_SETUP(timer_setup)
{
- module = test_module_initialize ();
- test_module_enter ();
+ module = test_module_initialize_and_enter ();
}
DEFINE_TEARDOWN(timer_teardown)
{
- test_module_leave ();
- test_module_finalize ();
+ test_module_leave_and_finalize ();
}
DEFINE_TEST(timer_extra_initialize)
diff --git a/pkcs11/pkcs11g.h b/pkcs11/pkcs11g.h
index da84c40..4707a34 100644
--- a/pkcs11/pkcs11g.h
+++ b/pkcs11/pkcs11g.h
@@ -101,8 +101,18 @@
* AUTO-DESTRUCT
*/
-#define CKA_GNOME_AUTO_DESTRUCT (CKO_GNOME + 200)
+#define CKA_GNOME_AUTO_DESTRUCT (CKA_GNOME + 200)
-#define CKA_GNOME_TRANSIENT (CKO_GNOME + 201)
+#define CKA_GNOME_TRANSIENT (CKA_GNOME + 201)
+
+/* -------------------------------------------------------------------
+ * AUTHENTICATOR
+ */
+
+#define CKO_GNOME_AUTHENTICATOR (CKO_GNOME + 100)
+
+#define CKA_GNOME_OBJECT (CKA_GNOME + 202)
+
+#define CKA_GNOME_USES_REMAINING (CKA_GNOME + 203)
#endif /* PKCS11G_H */
diff --git a/pkcs11/ssh-store/gck-ssh-module.c b/pkcs11/ssh-store/gck-ssh-module.c
index f2fa2e6..2dbe909 100644
--- a/pkcs11/ssh-store/gck-ssh-module.c
+++ b/pkcs11/ssh-store/gck-ssh-module.c
@@ -68,6 +68,8 @@ static const CK_TOKEN_INFO gck_ssh_module_token_info = {
G_DEFINE_TYPE (GckSshModule, gck_ssh_module, GCK_TYPE_MODULE);
+GckModule* _gck_ssh_store_get_module_for_testing (void);
+
/* -----------------------------------------------------------------------------
* ACTUAL PKCS#11 Module Implementation
*/
@@ -265,3 +267,9 @@ gck_ssh_store_get_functions (void)
gck_crypto_initialize ();
return gck_ssh_module_function_list;
}
+
+GckModule*
+_gck_ssh_store_get_module_for_testing (void)
+{
+ return pkcs11_module;
+}
diff --git a/pkcs11/ssh-store/gck-ssh-private-key.c b/pkcs11/ssh-store/gck-ssh-private-key.c
index 60f1af3..b0b3d1b 100644
--- a/pkcs11/ssh-store/gck-ssh-private-key.c
+++ b/pkcs11/ssh-store/gck-ssh-private-key.c
@@ -25,6 +25,7 @@
#include "gck-ssh-private-key.h"
#include "gck/gck-attributes.h"
+#include "gck/gck-authenticator.h"
#include "gck/gck-manager.h"
#include "gck/gck-object.h"
#include "gck/gck-sexp.h"
@@ -48,7 +49,6 @@ struct _GckSshPrivateKey {
guchar *private_data;
gsize n_private_data;
- GckSexp *private_sexp;
gboolean is_encrypted;
};
@@ -59,7 +59,8 @@ G_DEFINE_TYPE (GckSshPrivateKey, gck_ssh_private_key, GCK_TYPE_PRIVATE_KEY);
*/
static CK_RV
-unlock_private_key (GckSshPrivateKey *self, const gchar *password, gssize n_password)
+unlock_private_key (GckSshPrivateKey *self, const gchar *password,
+ gssize n_password, GckSexp **result)
{
GckDataResult res;
gcry_sexp_t sexp;
@@ -89,11 +90,10 @@ unlock_private_key (GckSshPrivateKey *self, const gchar *password, gssize n_pass
if (!password || !password[0])
self->is_encrypted = FALSE;
-
- wrapper = gck_sexp_new (sexp);
- gck_private_key_store_private (GCK_PRIVATE_KEY (self), wrapper, self->is_encrypted ? 1 : G_MAXUINT);
- gck_sexp_unref (wrapper);
+ wrapper = gck_sexp_new (sexp);
+ *result = wrapper;
+
return CKR_OK;
}
@@ -121,13 +121,13 @@ realize_and_take_data (GckSshPrivateKey *self, gcry_sexp_t sexp, gchar *comment,
self->private_data = private_data;
self->n_private_data = n_private_data;
- /* Force parsing next time required */
- gck_private_key_store_private (GCK_PRIVATE_KEY (self), NULL, 0);
-
/* Try to parse the private data, and note if it's not actually encrypted */
self->is_encrypted = TRUE;
- if (unlock_private_key (self, "", 0) == CKR_OK)
+ if (unlock_private_key (self, "", 0, &wrapper) == CKR_OK) {
self->is_encrypted = FALSE;
+ gck_private_key_set_unlocked_private (GCK_PRIVATE_KEY (self), wrapper);
+ gck_sexp_unref (wrapper);
+ }
}
/* -----------------------------------------------------------------------------
@@ -159,10 +159,26 @@ gck_ssh_private_key_get_attribute (GckObject *base, CK_ATTRIBUTE_PTR attr)
}
static CK_RV
-gck_ssh_private_key_unlock (GckObject *base, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
+gck_ssh_private_key_unlock (GckObject *base, GckAuthenticator *auth)
{
GckSshPrivateKey *self = GCK_SSH_PRIVATE_KEY (base);
- return unlock_private_key (self, (const gchar*)pin, n_pin);
+ const gchar *password;
+ GckSexp *wrapper;
+ gsize n_password;
+ CK_RV rv;
+
+ if (!self->is_encrypted)
+ return CKR_OK;
+
+ password = gck_authenticator_get_password (auth, &n_password);
+ rv = unlock_private_key (self, password, n_password, &wrapper);
+
+ if (rv == CKR_OK) {
+ gck_private_key_set_locked_private (GCK_PRIVATE_KEY (self), auth, wrapper, 1);
+ gck_sexp_unref (wrapper);
+ }
+
+ return rv;
}
static GObject*
diff --git a/pkcs11/ssh-store/tests/Makefile.am b/pkcs11/ssh-store/tests/Makefile.am
index aae4b68..2a133bc 100644
--- a/pkcs11/ssh-store/tests/Makefile.am
+++ b/pkcs11/ssh-store/tests/Makefile.am
@@ -1,5 +1,7 @@
UNIT_AUTO = \
- unit-test-ssh-openssh.c
+ unit-test-ssh-openssh.c \
+ unit-test-private-key.c \
+ test-ssh-module.c test-ssh-module.h
UNIT_PROMPT =
diff --git a/pkcs11/ssh-store/tests/test-ssh-module.c b/pkcs11/ssh-store/tests/test-ssh-module.c
new file mode 100644
index 0000000..29cbb73
--- /dev/null
+++ b/pkcs11/ssh-store/tests/test-ssh-module.c
@@ -0,0 +1,105 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* test-module.c: A test PKCS#11 module implementation
+
+ Copyright (C) 2009 Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+#include "test-ssh-module.h"
+
+#include "gck/gck-module.h"
+
+#include "ssh-store/gck-ssh-store.h"
+
+static GMutex *mutex = NULL;
+
+GckModule* _gck_ssh_store_get_module_for_testing (void);
+GMutex* _gck_module_get_scary_mutex_that_you_should_not_touch (GckModule *module);
+
+GckModule*
+test_ssh_module_initialize_and_enter (void)
+{
+ CK_FUNCTION_LIST_PTR funcs;
+ GckModule *module;
+ CK_RV rv;
+
+ funcs = gck_ssh_store_get_functions ();
+ rv = (funcs->C_Initialize) (NULL);
+ g_return_val_if_fail (rv == CKR_OK, NULL);
+
+ module = _gck_ssh_store_get_module_for_testing ();
+ g_return_val_if_fail (module, NULL);
+
+ mutex = _gck_module_get_scary_mutex_that_you_should_not_touch (module);
+ test_ssh_module_enter ();
+
+ return module;
+}
+
+void
+test_ssh_module_leave_and_finalize (void)
+{
+ CK_FUNCTION_LIST_PTR funcs;
+ CK_RV rv;
+
+ test_ssh_module_leave ();
+
+ funcs = gck_ssh_store_get_functions ();
+ rv = (funcs->C_Finalize) (NULL);
+ g_return_if_fail (rv == CKR_OK);
+}
+
+void
+test_ssh_module_leave (void)
+{
+ g_assert (mutex);
+ g_mutex_unlock (mutex);
+}
+
+void
+test_ssh_module_enter (void)
+{
+ g_assert (mutex);
+ g_mutex_lock (mutex);
+}
+
+GckSession*
+test_ssh_module_open_session (gboolean writable)
+{
+ CK_ULONG flags = CKF_SERIAL_SESSION;
+ CK_SESSION_HANDLE handle;
+ GckModule *module;
+ GckSession *session;
+ CK_RV rv;
+
+ module = _gck_ssh_store_get_module_for_testing ();
+ g_return_val_if_fail (module, NULL);
+
+ if (writable)
+ flags |= CKF_RW_SESSION;
+
+ rv = gck_module_C_OpenSession (module, 1, flags, NULL, NULL, &handle);
+ g_assert (rv == CKR_OK);
+
+ session = gck_module_lookup_session (module, handle);
+ g_assert (session);
+
+ return session;
+}
diff --git a/pkcs11/ssh-store/tests/test-ssh-module.h b/pkcs11/ssh-store/tests/test-ssh-module.h
new file mode 100644
index 0000000..f0565dd
--- /dev/null
+++ b/pkcs11/ssh-store/tests/test-ssh-module.h
@@ -0,0 +1,43 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* test-module.h: A test PKCS#11 module implementation
+
+ Copyright (C) 2009 Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#ifndef TEST_SSH_MODULE_H_
+#define TEST_SSH_MODULE_H_
+
+#include <glib.h>
+
+#include "gck/gck-types.h"
+
+#include "pkcs11.h"
+
+void test_ssh_module_leave (void);
+
+void test_ssh_module_enter (void);
+
+GckModule* test_ssh_module_initialize_and_enter (void);
+
+void test_ssh_module_leave_and_finalize (void);
+
+GckSession* test_ssh_module_open_session (gboolean writable);
+
+#endif /* TEST_SSH_MODULE_H_ */
diff --git a/pkcs11/ssh-store/tests/unit-test-private-key.c b/pkcs11/ssh-store/tests/unit-test-private-key.c
new file mode 100644
index 0000000..fc26ea1
--- /dev/null
+++ b/pkcs11/ssh-store/tests/unit-test-private-key.c
@@ -0,0 +1,97 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-private-key.c: Test SSH Key Private key functionality
+
+ Copyright (C) 2009 Stefan Walter
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "run-auto-test.h"
+#include "test-ssh-module.h"
+
+#include "gck/gck-authenticator.h"
+#include "gck/gck-session.h"
+#include "gck/gck-module.h"
+
+#include "ssh-store/gck-ssh-private-key.h"
+
+#include "pkcs11g.h"
+
+static GckModule *module = NULL;
+static GckSession *session = NULL;
+
+DEFINE_SETUP(private_key_setup)
+{
+ module = test_ssh_module_initialize_and_enter ();
+ session = test_ssh_module_open_session (TRUE);
+}
+
+DEFINE_TEARDOWN(private_key_teardown)
+{
+ test_ssh_module_leave_and_finalize ();
+ module = NULL;
+ session = NULL;
+}
+
+DEFINE_TEST(private_key_parse_plain)
+{
+ GckSshPrivateKey *key;
+ gchar *pub_path, *priv_path;
+ gboolean ret;
+
+ key = gck_ssh_private_key_new (module, "my-unique");
+ g_assert (GCK_IS_SSH_PRIVATE_KEY (key));
+
+ pub_path = g_build_filename (test_dir_testdata (), "id_dsa_plain.pub", NULL);
+ priv_path = g_build_filename (test_dir_testdata (), "id_dsa_plain", NULL);
+
+ ret = gck_ssh_private_key_parse (key, pub_path, priv_path, NULL);
+ g_assert (ret == TRUE);
+
+ g_object_unref (key);
+ g_free (pub_path);
+ g_free (priv_path);
+}
+
+
+DEFINE_TEST(private_key_parse_and_unlock)
+{
+ GckSshPrivateKey *key;
+ GckAuthenticator *auth;
+ gchar *pub_path, *priv_path;
+ gboolean ret;
+ CK_RV rv;
+
+ key = gck_ssh_private_key_new (module, "my-unique");
+ g_assert (GCK_IS_SSH_PRIVATE_KEY (key));
+
+ pub_path = g_build_filename (test_dir_testdata (), "id_dsa_encrypted.pub", NULL);
+ priv_path = g_build_filename (test_dir_testdata (), "id_dsa_encrypted", NULL);
+
+ ret = gck_ssh_private_key_parse (key, pub_path, priv_path, NULL);
+ g_assert (ret == TRUE);
+
+ g_free (pub_path);
+ g_free (priv_path);
+
+ rv = gck_authenticator_create (GCK_OBJECT (key), (guchar*)"password", 8, &auth);
+ g_assert (rv == CKR_OK);
+
+ g_object_unref (auth);
+ g_object_unref (key);
+}
diff --git a/pkcs11/user-store/gck-user-private-key.c b/pkcs11/user-store/gck-user-private-key.c
index 60e7740..a699e65 100644
--- a/pkcs11/user-store/gck-user-private-key.c
+++ b/pkcs11/user-store/gck-user-private-key.c
@@ -100,7 +100,7 @@ gck_user_private_key_real_get_attribute (GckObject *base, CK_ATTRIBUTE_PTR attr)
}
static GckSexp*
-gck_user_private_key_real_acquire_crypto_sexp (GckKey *base)
+gck_user_private_key_real_acquire_crypto_sexp (GckKey *base, GckSession *unused)
{
GckUserPrivateKey *self = GCK_USER_PRIVATE_KEY (base);
gcry_sexp_t sexp;
@@ -295,7 +295,7 @@ gck_user_private_key_real_save (GckSerializable *base, GckLogin *login, guchar *
g_return_val_if_fail (data, FALSE);
g_return_val_if_fail (n_data, FALSE);
- sexp = gck_user_private_key_real_acquire_crypto_sexp (GCK_KEY (self));
+ sexp = gck_user_private_key_real_acquire_crypto_sexp (GCK_KEY (self), NULL);
g_return_val_if_fail (sexp, FALSE);
password = gck_login_get_password (login, &n_password);
diff --git a/pkcs11/user-store/gck-user-storage.c b/pkcs11/user-store/gck-user-storage.c
index 12c2263..687c1b3 100644
--- a/pkcs11/user-store/gck-user-storage.c
+++ b/pkcs11/user-store/gck-user-storage.c
@@ -90,14 +90,6 @@ G_DEFINE_TYPE (GckUserStorage, gck_user_storage, GCK_TYPE_STORE);
* HELPERS
*/
-static void
-dispose_unref_object (gpointer obj)
-{
- g_assert (G_IS_OBJECT (obj));
- g_object_run_dispose (obj);
- g_object_unref (obj);
-}
-
#ifndef HAVE_FLOCK
#define LOCK_SH 1
#define LOCK_EX 2
@@ -882,7 +874,7 @@ gck_user_storage_init (GckUserStorage *self)
g_signal_connect (self->file, "entry-removed", G_CALLBACK (data_file_entry_removed), self);
/* Each one owns the key and contains weak ref to other's key as its value */
- self->object_to_identifier = g_hash_table_new_full (g_direct_hash, g_direct_equal, dispose_unref_object, NULL);
+ self->object_to_identifier = g_hash_table_new_full (g_direct_hash, g_direct_equal, gck_util_dispose_unref, NULL);
self->identifier_to_object = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
self->read_fd = -1;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]