gnome-keyring r1417 - in trunk: . pkcs11/gck pkcs11/gck/tests pkcs11/gck/tests/test-data pkcs11/roots pkcs11/ssh-keys tests
- From: nnielsen svn gnome org
- To: svn-commits-list gnome org
- Subject: gnome-keyring r1417 - in trunk: . pkcs11/gck pkcs11/gck/tests pkcs11/gck/tests/test-data pkcs11/roots pkcs11/ssh-keys tests
- Date: Sat, 3 Jan 2009 19:30:08 +0000 (UTC)
Author: nnielsen
Date: Sat Jan 3 19:30:08 2009
New Revision: 1417
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1417&view=rev
Log:
* pkcs11/gck/gck-attributes.c: (added)
* pkcs11/gck/gck-attributes.h: (added)
* pkcs11/gck/gck-certificate.c:
* pkcs11/gck/gck-certificate.h:
* pkcs11/gck/gck-certificate-key.c:
* pkcs11/gck/gck-certificate-key.h:
* pkcs11/gck/gck-factory.c: (added)
* pkcs11/gck/gck-factory.h: (added)
* pkcs11/gck/gck-file-store.c: (added)
* pkcs11/gck/gck-file-store.h: (added)
* pkcs11/gck/gck-key.c:
* pkcs11/gck/gck-key.h:
* pkcs11/gck/gck-manager.c:
* pkcs11/gck/gck-manager.h:
* pkcs11/gck/gck-marshal.list: (added)
* pkcs11/gck/gck-memory-store.c: (added)
* pkcs11/gck/gck-memory-store.h: (added)
* pkcs11/gck/gck-module.c:
* pkcs11/gck/gck-module.h:
* pkcs11/gck/gck-object.c:
* pkcs11/gck/gck-object.h:
* pkcs11/gck/gck-private-key.c:
* pkcs11/gck/gck-private-key.h:
* pkcs11/gck/gck-public-key.c:
* pkcs11/gck/gck-public-key.h:
* pkcs11/gck/gck-session.c:
* pkcs11/gck/gck-sexp.h:
* pkcs11/gck/gck-store.c: (added)
* pkcs11/gck/gck-store.h: (added)
* pkcs11/gck/gck-transaction.c: (added)
* pkcs11/gck/gck-transaction.h: (added)
* pkcs11/gck/gck-types.h: (added)
* pkcs11/gck/gck-util.c:
* pkcs11/gck/gck-util.h:
* pkcs11/gck/Makefile.am:
* pkcs11/gck/tests/Makefile.am:
* pkcs11/gck/tests/unit-test-file-store.c: (added)
* pkcs11/gck/tests/unit-test-memory-store.c: (added)
* pkcs11/gck/tests/unit-test-store.c: (added)
* pkcs11/gck/tests/unit-test-transaction.c: (added)
* pkcs11/gck/tests/test-data/test-file-store.store: (added)
* pkcs11/roots/gck-roots-certificate.c:
* pkcs11/ssh-keys/gck-ssh-private-key.c:
* pkcs11/ssh-keys/gck-ssh-public-key.c:
* tests/gtest-helpers.c:
* tests/gtest-helpers.h: Added support for creating, deleting and setting
attributes on session objects. Framework for general modification of objects.
Added:
trunk/pkcs11/gck/gck-attributes.c
trunk/pkcs11/gck/gck-attributes.h
trunk/pkcs11/gck/gck-factory.c
trunk/pkcs11/gck/gck-factory.h
trunk/pkcs11/gck/gck-file-store.c
trunk/pkcs11/gck/gck-file-store.h
trunk/pkcs11/gck/gck-marshal.list
trunk/pkcs11/gck/gck-memory-store.c
trunk/pkcs11/gck/gck-memory-store.h
trunk/pkcs11/gck/gck-store.c
trunk/pkcs11/gck/gck-store.h
trunk/pkcs11/gck/gck-transaction.c
trunk/pkcs11/gck/gck-transaction.h
trunk/pkcs11/gck/gck-types.h
trunk/pkcs11/gck/tests/test-data/test-file-store.store (contents, props changed)
trunk/pkcs11/gck/tests/unit-test-file-store.c
trunk/pkcs11/gck/tests/unit-test-memory-store.c
trunk/pkcs11/gck/tests/unit-test-store.c
trunk/pkcs11/gck/tests/unit-test-transaction.c
Modified:
trunk/ChangeLog
trunk/pkcs11/gck/ (props changed)
trunk/pkcs11/gck/Makefile.am
trunk/pkcs11/gck/gck-certificate-key.c
trunk/pkcs11/gck/gck-certificate-key.h
trunk/pkcs11/gck/gck-certificate.c
trunk/pkcs11/gck/gck-certificate.h
trunk/pkcs11/gck/gck-key.c
trunk/pkcs11/gck/gck-key.h
trunk/pkcs11/gck/gck-manager.c
trunk/pkcs11/gck/gck-manager.h
trunk/pkcs11/gck/gck-module.c
trunk/pkcs11/gck/gck-module.h
trunk/pkcs11/gck/gck-object.c
trunk/pkcs11/gck/gck-object.h
trunk/pkcs11/gck/gck-private-key.c
trunk/pkcs11/gck/gck-private-key.h
trunk/pkcs11/gck/gck-public-key.c
trunk/pkcs11/gck/gck-public-key.h
trunk/pkcs11/gck/gck-session.c
trunk/pkcs11/gck/gck-sexp.h
trunk/pkcs11/gck/gck-util.c
trunk/pkcs11/gck/gck-util.h
trunk/pkcs11/gck/tests/Makefile.am
trunk/pkcs11/roots/gck-roots-certificate.c
trunk/pkcs11/ssh-keys/gck-ssh-private-key.c
trunk/pkcs11/ssh-keys/gck-ssh-public-key.c
trunk/tests/gtest-helpers.c
trunk/tests/gtest-helpers.h
Modified: trunk/pkcs11/gck/Makefile.am
==============================================================================
--- trunk/pkcs11/gck/Makefile.am (original)
+++ trunk/pkcs11/gck/Makefile.am Sat Jan 3 19:30:08 2009
@@ -13,9 +13,11 @@
libgck.la
BUILT_SOURCES = \
+ gck-marshal.c gck-marshal.h \
asn1-def-pk.h asn1-def-pkix.h
libgck_la_SOURCES = \
+ gck-attributes.c gck-attributes.h \
gck-certificate.c gck-certificate.h \
gck-certificate-key.c gck-certificate-key.h \
gck-crypto.c gck-crypto.h \
@@ -24,16 +26,23 @@
gck-data-openssl.c gck-data-openssl.h \
gck-data-pem.c gck-data-pem.h \
gck-data-types.h \
+ gck-factory.c gck-factory.h \
+ gck-file-store.c gck-file-store.h \
gck-file-tracker.c gck-file-tracker.h \
gck-key.c gck-key.h \
gck-manager.c gck-manager.h \
+ gck-memory-store.c gck-memory-store.h \
gck-module.c gck-module.h gck-module-ep.h \
gck-object.c gck-object.h \
gck-private-key.c gck-private-key.h \
gck-public-key.c gck-public-key.h \
gck-session.c gck-session.h \
gck-sexp.c gck-sexp.h \
- gck-util.c gck-util.h
+ gck-store.c gck-store.h \
+ gck-transaction.c gck-transaction.h \
+ gck-types.h \
+ gck-util.c gck-util.h \
+ $(BUILT_SOURCES)
libgck_la_CFLAGS = \
$(GOBJECT_CFLAGS) \
@@ -46,6 +55,13 @@
$(LIBGCRYPT_LIBS) \
$(GLIB_LIBS)
+gck-marshal.h: gck-marshal.list $(GLIB_GENMARSHAL)
+ $(GLIB_GENMARSHAL) $< --header --prefix=gck_marshal > $@
+
+gck-marshal.c: gck-marshal.list $(GLIB_GENMARSHAL)
+ echo "#include \"gck-marshal.h\"" > $@ && \
+ $(GLIB_GENMARSHAL) $< --body --prefix=gck_marshal >> $@
+
asn1-def-pk.h: pk.asn
asn1Parser -o asn1-def-pk.h pk.asn
@@ -53,6 +69,7 @@
asn1Parser -o asn1-def-pkix.h pkix.asn
EXTRA_DIST = \
+ gck-marshal.list \
pkix.asn \
pk.asn
Added: trunk/pkcs11/gck/gck-attributes.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-attributes.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,292 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-util.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+CK_RV
+gck_attribute_set_bool (CK_ATTRIBUTE_PTR attr, CK_BBOOL value)
+{
+ return gck_attribute_set_data (attr, &value, sizeof (CK_BBOOL));
+}
+
+CK_RV
+gck_attribute_set_ulong (CK_ATTRIBUTE_PTR attr, CK_ULONG value)
+{
+ return gck_attribute_set_data (attr, &value, sizeof (CK_ULONG));
+}
+
+CK_RV
+gck_attribute_set_string (CK_ATTRIBUTE_PTR attr, const gchar* string)
+{
+ g_return_val_if_fail (string, CKR_GENERAL_ERROR);
+ return gck_attribute_set_data (attr, (CK_VOID_PTR)string, strlen (string));
+}
+
+CK_RV
+gck_attribute_set_date (CK_ATTRIBUTE_PTR attr, time_t time)
+{
+ CK_DATE date;
+ struct tm tm;
+ gchar buf[16];
+
+ /* 'Empty' date as defined in PKCS#11 */
+ if (time == (time_t)-1)
+ return gck_attribute_set_data (attr, NULL, 0);
+
+ if (!attr->pValue) {
+ attr->ulValueLen = sizeof (CK_DATE);
+ return CKR_OK;
+ }
+
+ if (!gmtime_r (&time, &tm))
+ g_return_val_if_reached (CKR_GENERAL_ERROR);
+
+ g_assert (sizeof (date.year) == 4);
+ snprintf ((char*)buf, 5, "%04d", 1900 + tm.tm_year);
+ memcpy (date.year, buf, 4);
+
+ g_assert (sizeof (date.month) == 2);
+ snprintf ((char*)buf, 3, "%02d", tm.tm_mon + 1);
+ memcpy (date.month, buf, 2);
+
+ g_assert (sizeof (date.day) == 2);
+ snprintf ((char*)buf, 3, "%02d", tm.tm_mday);
+ memcpy (date.day, buf, 2);
+
+ return gck_attribute_set_data (attr, &date, sizeof (date));
+}
+CK_RV
+gck_attribute_set_data (CK_ATTRIBUTE_PTR attr, gconstpointer value, gsize n_value)
+{
+ return gck_util_return_data (attr->pValue, &(attr->ulValueLen), value, n_value);
+}
+
+CK_RV
+gck_attribute_set_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t mpi)
+{
+ gsize len;
+ gcry_error_t gcry;
+
+ g_assert (attr);
+ g_assert (mpi);
+
+ /* Get the size */
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+ if (!attr->pValue) {
+ attr->ulValueLen = len;
+ return CKR_OK;
+ }
+
+ if (len > attr->ulValueLen) {
+ attr->ulValueLen = len;
+ return CKR_BUFFER_TOO_SMALL;
+ }
+
+ /* Write in directly to attribute */
+ gcry = gcry_mpi_print (GCRYMPI_FMT_USG, attr->pValue, len, &len, mpi);
+ g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
+
+ attr->ulValueLen = len;
+ return CKR_OK;
+}
+
+gboolean
+gck_attribute_equal (gconstpointer v1, gconstpointer v2)
+{
+ const CK_ATTRIBUTE *a1 = v1;
+ const CK_ATTRIBUTE *a2 = v2;
+
+ g_assert (a1);
+ g_assert (a2);
+
+ if (a1 == a2)
+ return TRUE;
+ if (a1->type != a2->type)
+ return FALSE;
+ if (a1->ulValueLen != a2->ulValueLen)
+ return FALSE;
+ if (a1->pValue == a2->pValue)
+ return TRUE;
+
+ g_assert (a1->pValue);
+ g_assert (a2->pValue);
+
+ return memcmp (a1->pValue, a2->pValue, a1->ulValueLen) == 0;
+}
+
+guint
+gck_attribute_hash (gconstpointer v)
+{
+ const CK_ATTRIBUTE *a = v;
+ const signed char *p;
+ guint i, h;
+
+ g_assert (a);
+
+ p = (const signed char*)&(a->type);
+ h = *p;
+ for(i = 0; i < sizeof (CK_ATTRIBUTE_PTR); ++i)
+ h = (h << 5) - h + *(p++);
+
+ p = a->pValue;
+ for(i = 0; i < a->ulValueLen; ++i)
+ h = (h << 5) - h + *(p++);
+
+ return h;
+}
+
+gboolean
+gck_attribute_consumed (CK_ATTRIBUTE_PTR attr)
+{
+ g_return_val_if_fail (attr, FALSE);
+ return attr->type == (CK_ULONG)-1;
+}
+
+void
+gck_attributes_consume (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, ...)
+{
+ CK_ATTRIBUTE_TYPE type;
+ GArray *types;
+ guint i, j;
+ va_list va;
+
+ /* Convert the var args into an array */
+ types = g_array_new (FALSE, TRUE, sizeof (CK_ATTRIBUTE_TYPE));
+ va_start (va, n_attrs);
+ while ((type = va_arg (va, CK_ATTRIBUTE_TYPE)) != (CK_ULONG)-1)
+ g_array_append_val (types, type);
+ va_end (va);
+
+ /* Consume each attribute whose type was in the var args */
+ for (i = 0; i < n_attrs; ++i) {
+ if (gck_attribute_consumed (&attrs[i]))
+ continue;
+ for (j = 0; j < types->len; ++j) {
+ if (attrs[i].type == g_array_index (types, CK_ATTRIBUTE_TYPE, j)) {
+ attrs[i].type = (CK_ULONG)-1;
+ break;
+ }
+ }
+ }
+
+ g_array_free (types, TRUE);
+}
+
+gboolean
+gck_attributes_contains (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_PTR attr)
+{
+ CK_ULONG i;
+
+ g_assert (attrs || !n_attrs);
+ g_assert (attr);
+
+ for (i = 0; i < n_attrs; ++i) {
+ if (gck_attribute_equal (attr, &attrs[i]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+CK_ATTRIBUTE_PTR
+gck_attributes_find (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type)
+{
+ CK_ULONG i;
+
+ g_assert (attrs || !n_attrs);
+
+ for (i = 0; i < n_attrs; ++i) {
+ if(attrs[i].type == type)
+ return &attrs[i];
+ }
+
+ return NULL;
+}
+
+gboolean
+gck_attributes_find_boolean (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type, gboolean *value)
+{
+ CK_ATTRIBUTE_PTR attr;
+
+ g_assert (attrs || !n_attrs);
+
+ attr = gck_attributes_find (attrs, n_attrs, type);
+ if (attr == NULL)
+ return FALSE;
+
+ if (attr->ulValueLen != sizeof (CK_BBOOL))
+ return FALSE;
+
+ if (value != NULL)
+ *value = *((CK_BBOOL*)attr->pValue) == CK_TRUE ? TRUE : FALSE;
+
+ return TRUE;
+}
+
+gboolean
+gck_attributes_find_ulong (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type, gulong *value)
+{
+ CK_ATTRIBUTE_PTR attr;
+
+ g_assert (attrs || !n_attrs);
+
+ attr = gck_attributes_find (attrs, n_attrs, type);
+ if (attr == NULL)
+ return FALSE;
+
+ if (attr->ulValueLen != sizeof (CK_ULONG))
+ return FALSE;
+
+ if (value != NULL)
+ *value = *((CK_ULONG*)attr->pValue);
+
+ return TRUE;
+}
+
+gboolean
+gck_attributes_find_mpi (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, CK_ATTRIBUTE_TYPE type, gcry_mpi_t *value)
+{
+ CK_ATTRIBUTE_PTR attr;
+ gcry_error_t gcry;
+
+ g_assert (attrs || !n_attrs);
+
+ attr = gck_attributes_find (attrs, n_attrs, type);
+ if (attr == NULL)
+ return FALSE;
+
+ if (value != NULL) {
+ gcry = gcry_mpi_scan (value, GCRYMPI_FMT_USG, attr->pValue, attr->ulValueLen, NULL);
+ if (gcry != 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
Added: trunk/pkcs11/gck/gck-attributes.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-attributes.h Sat Jan 3 19:30:08 2009
@@ -0,0 +1,90 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef GCK_ATTRIBUTE_H_
+#define GCK_ATTRIBUTE_H_
+
+#include <glib.h>
+
+#include <gcrypt.h>
+
+#include "pkcs11/pkcs11.h"
+
+CK_RV gck_attribute_set_bool (CK_ATTRIBUTE_PTR attr,
+ CK_BBOOL value);
+
+CK_RV gck_attribute_set_ulong (CK_ATTRIBUTE_PTR attr,
+ CK_ULONG value);
+
+CK_RV gck_attribute_set_string (CK_ATTRIBUTE_PTR attr,
+ const gchar* string);
+
+CK_RV gck_attribute_set_date (CK_ATTRIBUTE_PTR attr,
+ time_t when);
+
+CK_RV gck_attribute_set_data (CK_ATTRIBUTE_PTR attr,
+ gconstpointer value,
+ gsize n_value);
+
+CK_RV gck_attribute_return_data (CK_VOID_PTR output,
+ CK_ULONG_PTR n_output,
+ gconstpointer input,
+ gsize n_input);
+
+CK_RV gck_attribute_set_mpi (CK_ATTRIBUTE_PTR attr,
+ gcry_mpi_t mpi);
+
+guint gck_attribute_hash (gconstpointer v);
+
+gboolean gck_attribute_equal (gconstpointer a,
+ gconstpointer b);
+
+gboolean gck_attribute_consumed (CK_ATTRIBUTE_PTR attr);
+
+
+
+gboolean gck_attributes_contains (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ CK_ATTRIBUTE_PTR attr);
+
+void gck_attributes_consume (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs, ...);
+
+CK_ATTRIBUTE_PTR gck_attributes_find (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type);
+
+gboolean gck_attributes_find_boolean (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type,
+ gboolean *value);
+
+gboolean gck_attributes_find_ulong (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type,
+ gulong *value);
+
+gboolean gck_attributes_find_mpi (CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ CK_ATTRIBUTE_TYPE type,
+ gcry_mpi_t *mpi);
+
+#endif /* GCK_ATTRIBUTE_H_ */
Modified: trunk/pkcs11/gck/gck-certificate-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-certificate-key.c (original)
+++ trunk/pkcs11/gck/gck-certificate-key.c Sat Jan 3 19:30:08 2009
@@ -21,6 +21,8 @@
#include "config.h"
+#include "gck-attributes.h"
+#include "gck-certificate.h"
#include "gck-certificate-key.h"
#include "gck-object.h"
@@ -52,7 +54,7 @@
case CKA_LABEL:
if (self->pv->certificate)
return gck_object_get_attribute (GCK_OBJECT (self->pv->certificate), attr);
- return gck_util_set_string (attr, "");
+ return gck_attribute_set_string (attr, "");
}
return GCK_OBJECT_CLASS (gck_certificate_key_parent_class)->get_attribute (base, attr);
Modified: trunk/pkcs11/gck/gck-certificate-key.h
==============================================================================
--- trunk/pkcs11/gck/gck-certificate-key.h (original)
+++ trunk/pkcs11/gck/gck-certificate-key.h Sat Jan 3 19:30:08 2009
@@ -25,7 +25,7 @@
#include <glib-object.h>
#include "gck-public-key.h"
-#include "gck-certificate.h"
+#include "gck-types.h"
#define GCK_TYPE_CERTIFICATE_KEY (gck_certificate_key_get_type ())
#define GCK_CERTIFICATE_KEY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_CERTIFICATE_KEY, GckCertificateKey))
Modified: trunk/pkcs11/gck/gck-certificate.c
==============================================================================
--- trunk/pkcs11/gck/gck-certificate.c (original)
+++ trunk/pkcs11/gck/gck-certificate.c Sat Jan 3 19:30:08 2009
@@ -23,6 +23,8 @@
#include "pkcs11/pkcs11.h"
+#include "gck-attributes.h"
+#include "gck-certificate.h"
#include "gck-certificate-key.h"
#include "gck-crypto.h"
#include "gck-data-asn1.h"
@@ -127,24 +129,24 @@
switch (attr->type) {
case CKA_CLASS:
- return gck_util_set_ulong (attr, CKO_CERTIFICATE);
+ return gck_attribute_set_ulong (attr, CKO_CERTIFICATE);
case CKA_PRIVATE:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_LABEL:
- return gck_util_set_string (attr, gck_certificate_get_label (self));
+ return gck_attribute_set_string (attr, gck_certificate_get_label (self));
case CKA_CERTIFICATE_TYPE:
- return gck_util_set_ulong (attr, CKC_X_509);
+ return gck_attribute_set_ulong (attr, CKC_X_509);
case CKA_TRUSTED:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_CERTIFICATE_CATEGORY:
if (!gck_certificate_calc_category (self, &category))
return CKR_FUNCTION_FAILED;
- return gck_util_set_ulong (attr, category);
+ return gck_attribute_set_ulong (attr, category);
case CKA_CHECK_VALUE:
g_return_val_if_fail (self->pv->data, CKR_GENERAL_ERROR);
@@ -152,7 +154,7 @@
g_return_val_if_fail (n_data && n_data > 3, CKR_GENERAL_ERROR);
data = g_new0 (guchar, n_data);
gcry_md_hash_buffer (GCRY_MD_SHA1, data, self->pv->data, self->pv->n_data);
- rv = gck_util_set_data (attr, data, 3);
+ rv = gck_attribute_set_data (attr, data, 3);
g_free (data);
return rv;
@@ -165,14 +167,14 @@
"tbsCertificate.validity.notAfter",
&when))
return CKR_FUNCTION_FAILED;
- return gck_util_set_date (attr, when);
+ return gck_attribute_set_date (attr, when);
case CKA_SUBJECT:
g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
cdata = gck_data_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data,
"tbsCertificate.subject", &n_data);
g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
- return gck_util_set_data (attr, cdata, n_data);
+ return gck_attribute_set_data (attr, cdata, n_data);
case CKA_ID:
g_return_val_if_fail (self->pv->key, CKR_GENERAL_ERROR);
@@ -183,28 +185,28 @@
cdata = gck_data_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data,
"tbsCertificate.issuer", &n_data);
g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
- return gck_util_set_data (attr, cdata, n_data);
+ return gck_attribute_set_data (attr, cdata, n_data);
case CKA_SERIAL_NUMBER:
g_return_val_if_fail (self->pv->asn1, CKR_GENERAL_ERROR);
cdata = gck_data_asn1_read_element (self->pv->asn1, self->pv->data, self->pv->n_data,
"tbsCertificate.serialNumber", &n_data);
g_return_val_if_fail (cdata, CKR_GENERAL_ERROR);
- return gck_util_set_data (attr, cdata, n_data);
+ return gck_attribute_set_data (attr, cdata, n_data);
case CKA_VALUE:
g_return_val_if_fail (self->pv->data, CKR_GENERAL_ERROR);
- return gck_util_set_data (attr, self->pv->data, self->pv->n_data);
+ return gck_attribute_set_data (attr, self->pv->data, self->pv->n_data);
/* These are only used for strange online certificates which we don't support */
case CKA_URL:
case CKA_HASH_OF_SUBJECT_PUBLIC_KEY:
case CKA_HASH_OF_ISSUER_PUBLIC_KEY:
- return gck_util_set_data (attr, "", 0);
+ return gck_attribute_set_data (attr, "", 0);
/* What in the world is this doing in the spec? */
case CKA_JAVA_MIDP_SECURITY_DOMAIN:
- return gck_util_set_ulong (attr, 0); /* 0 = unspecified */
+ return gck_attribute_set_ulong (attr, 0); /* 0 = unspecified */
};
return GCK_OBJECT_CLASS (gck_certificate_parent_class)->get_attribute (base, attr);
Modified: trunk/pkcs11/gck/gck-certificate.h
==============================================================================
--- trunk/pkcs11/gck/gck-certificate.h (original)
+++ trunk/pkcs11/gck/gck-certificate.h Sat Jan 3 19:30:08 2009
@@ -25,6 +25,7 @@
#include <glib-object.h>
#include "gck-object.h"
+#include "gck-types.h"
#define GCK_TYPE_CERTIFICATE (gck_certificate_get_type ())
#define GCK_CERTIFICATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_CERTIFICATE, GckCertificate))
@@ -33,8 +34,6 @@
#define GCK_IS_CERTIFICATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_CERTIFICATE))
#define GCK_CERTIFICATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_CERTIFICATE, GckCertificateClass))
-typedef struct _GckCertificate GckCertificate;
-typedef struct _GckCertificateKey GckCertificateKey;
typedef struct _GckCertificateClass GckCertificateClass;
typedef struct _GckCertificatePrivate GckCertificatePrivate;
Added: trunk/pkcs11/gck/gck-factory.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-factory.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,25 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-factory.h"
+
Added: trunk/pkcs11/gck/gck-factory.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-factory.h Sat Jan 3 19:30:08 2009
@@ -0,0 +1,40 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCK_FACTORY_H__
+#define __GCK_FACTORY_H__
+
+#include <glib-object.h>
+
+#include "pkcs11/pkcs11.h"
+
+#include "gck-types.h"
+
+typedef void (*GckFactory) (GckSession *session, GckTransaction *transaction,
+ CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object);
+
+struct _GckFactoryInfo {
+ CK_ATTRIBUTE_PTR attrs;
+ CK_ULONG n_attrs;
+ GckFactory factory;
+};
+
+#endif /* __GCK_FACTORY_H__ */
Added: trunk/pkcs11/gck/gck-file-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-file-store.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,1513 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-crypto.h"
+#include "gck-file-store.h"
+#include "gck-object.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-secure-memory.h"
+
+#include <glib/gstdio.h>
+
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <gcrypt.h>
+
+enum {
+ PROP_0,
+ PROP_FILENAME,
+ PROP_LOCKED
+};
+
+
+enum {
+ ENTRY_CREATED,
+ ENTRY_DESTROYED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _GckFileStore {
+ GckStore parent;
+
+ GHashTable *privates;
+ GHashTable *publics;
+ GHashTable *object_by_unique;
+ GHashTable *unique_by_object;
+
+ gchar *filename;
+ time_t last_mtime;
+ gboolean locked;
+ guchar *password;
+ gsize n_password;
+ gboolean unlock_failures;
+
+ /* Valid when in a transaction */
+ GckTransaction *transaction;
+ int previous_fd;
+ int transaction_fd;
+ gchar *transaction_path;
+};
+
+G_DEFINE_TYPE (GckFileStore, gck_file_store, GCK_TYPE_STORE);
+
+#define PUBLIC_ALLOC (GkrBufferAllocator)g_realloc
+#define PRIVATE_ALLOC (GkrBufferAllocator)gkr_secure_realloc
+
+typedef gboolean (*BlockFunc) (guint block, GkrBuffer *buffer, gpointer user_data);
+
+#define FILE_HEADER ((const guchar*)"Gnome Keyring Store 2\n\r\0")
+#define FILE_HEADER_LEN 24
+
+#define FILE_BLOCK_PRIVATE 0x70727632 /* ie: "prv2" */
+#define FILE_BLOCK_PUBLIC 0x70756232 /* ie: "pub2" */
+
+#define MAX_LOCK_TRIES 20
+
+/* -----------------------------------------------------------------------------
+ * HELPERS
+ */
+
+static void
+attribute_free (gpointer data)
+{
+ CK_ATTRIBUTE_PTR attr = data;
+ if (attr) {
+ g_free (attr->pValue);
+ g_slice_free (CK_ATTRIBUTE, attr);
+ }
+}
+
+static CK_ATTRIBUTE_PTR
+attribute_dup (CK_ATTRIBUTE_PTR attr)
+{
+ CK_ATTRIBUTE_PTR copy;
+ g_assert (attr);
+ copy = g_slice_new (CK_ATTRIBUTE);
+ copy->ulValueLen = attr->ulValueLen;
+ copy->pValue = g_memdup (attr->pValue, copy->ulValueLen);
+ copy->type = attr->type;
+ return copy;
+}
+
+static gboolean
+read_all_bytes (int fd, guchar *buf, gsize len)
+{
+ gsize all = len;
+ int res;
+
+ while (len > 0) {
+
+ res = read (fd, buf, len);
+ if (res <= 0) {
+ if (errno == EAGAIN && errno == EINTR)
+ continue;
+ if (res < 0 || len != all)
+ g_warning ("couldn't read %u bytes from store file: %s", all,
+ g_strerror (errno));
+ return FALSE;
+ } else {
+ len -= res;
+ buf += res;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+write_all_bytes (int fd, const guchar *buf, gsize len)
+{
+ gsize all = len;
+ int res;
+
+ while (len > 0) {
+
+ res = write (fd, buf, len);
+
+ if (res <= 0) {
+ if (errno == EAGAIN && errno == EINTR)
+ continue;
+ g_warning ("couldn't write %u bytes to store file: %s", all,
+ res < 0 ? g_strerror (errno) : "");
+ return FALSE;
+ } else {
+ len -= res;
+ buf += res;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+parse_file_blocks (int file, BlockFunc block_func, gpointer user_data)
+{
+ gchar header[FILE_HEADER_LEN];
+ GkrBuffer buffer;
+ gboolean ret;
+ guint32 block;
+ guint32 length;
+ gsize offset;
+
+ g_assert (file != -1);
+ g_assert (block_func);
+
+ /* Zero length file is valid */
+ if (!read_all_bytes (file, (guchar*)header, FILE_HEADER_LEN))
+ return TRUE;
+
+ /* Check the header */
+ if (memcmp (header, FILE_HEADER, FILE_HEADER_LEN) != 0) {
+ g_message ("invalid header in store file");
+ return FALSE;
+ }
+
+ gkr_buffer_init_full (&buffer, 1024, (GkrBufferAllocator)g_realloc);
+
+ ret = FALSE;
+ for (;;) {
+
+ gkr_buffer_reset (&buffer);
+ gkr_buffer_resize (&buffer, 8);
+ offset = 0;
+
+ /* Read in a set of bytes */
+ if (!read_all_bytes (file, buffer.buf, 8)) {
+ ret = TRUE;
+ break;
+ }
+
+ /* Decode it as the number of bytes in the next section */
+ if (!gkr_buffer_get_uint32 (&buffer, offset, &offset, &length) ||
+ !gkr_buffer_get_uint32 (&buffer, offset, &offset, &block) ||
+ length < 8) {
+ g_message ("invalid block size or length in store file");
+ break;
+ }
+
+ /* Read in that amount of bytes */
+ gkr_buffer_resize (&buffer, length - 8);
+ if (!read_all_bytes (file, buffer.buf, length - 8))
+ break;
+
+ if (!(block_func) (block, &buffer, user_data))
+ break;
+ }
+
+ gkr_buffer_uninit (&buffer);
+ return ret;
+}
+
+static gboolean
+write_file_block (int file, guint block, GkrBuffer *buffer)
+{
+ GkrBuffer header;
+ gboolean ret;
+
+ g_assert (file != -1);
+ g_assert (buffer);
+
+ /* Write out the 8 bytes of header */
+ gkr_buffer_init_full (&header, 8, (GkrBufferAllocator)g_realloc);
+ gkr_buffer_add_uint32 (&header, buffer->len + 8);
+ gkr_buffer_add_uint32 (&header, block);
+ g_assert (!gkr_buffer_has_error (&header));
+ g_assert (header.len == 8);
+ ret = write_all_bytes (file, header.buf, header.len);
+ gkr_buffer_uninit (&header);
+
+ if (ret != TRUE)
+ return FALSE;
+
+ /* Now write out the remainder of the data */
+ return write_all_bytes (file, buffer->buf, buffer->len);
+}
+
+static gboolean
+hash_buffer (GkrBuffer *buffer)
+{
+ const gchar *salgo;
+ gsize length;
+ guchar *hash;
+ gsize n_hash;
+ int algo;
+
+ /* The length needs to be the first thing in the buffer */
+ g_assert (buffer->len > 4);
+ g_assert (gkr_buffer_decode_uint32 (buffer->buf) == buffer->len);
+
+ length = buffer->len;
+
+ algo = GCRY_MD_SHA256;
+ salgo = gcry_md_algo_name (algo);
+ g_return_val_if_fail (salgo, FALSE);
+ n_hash = gcry_md_get_algo_dlen (algo);
+ g_return_val_if_fail (n_hash > 0, FALSE);
+
+ gkr_buffer_add_string (buffer, salgo);
+ hash = gkr_buffer_add_byte_array_empty (buffer, n_hash);
+ g_return_val_if_fail (hash, FALSE);
+
+ gcry_md_hash_buffer (algo, hash, buffer->buf, length);
+ return TRUE;
+}
+
+static gboolean
+validate_buffer (GkrBuffer *buffer, gsize *offset)
+{
+ const guchar *hash;
+ gchar *salgo, *check;
+ gsize n_hash, hash_offset;
+ guint32 length;
+ int algo;
+
+ g_assert (buffer);
+ g_assert (offset);
+
+ *offset = 0;
+
+ if (!gkr_buffer_get_uint32 (buffer, *offset, offset, &length) ||
+ !gkr_buffer_get_string (buffer, length, &hash_offset, &salgo, PUBLIC_ALLOC))
+ return FALSE;
+
+ algo = gcry_md_map_name (salgo);
+ if (algo == 0) {
+ g_warning ("unsupported hash algorithm: %s", salgo);
+ g_free (salgo);
+ return FALSE;
+ }
+ g_free (salgo);
+
+ if (!gkr_buffer_get_byte_array (buffer, hash_offset, &hash_offset, &hash, &n_hash))
+ return FALSE;
+
+ if (n_hash != gcry_md_get_algo_dlen (algo)) {
+ g_warning ("invalid hash length in store file");
+ return FALSE;
+ }
+
+ check = g_malloc0 (n_hash);
+ gcry_md_hash_buffer (algo, check, buffer->buf, length);
+ if (memcmp (check, hash, n_hash) != 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+create_cipher (int calgo, int halgo, const guchar *password, gsize n_password,
+ const guchar *salt, gsize n_salt, guint iterations, gcry_cipher_hd_t *cipher)
+{
+ gsize n_key, n_block;
+ guchar *key, *iv;
+ gcry_error_t gcry;
+
+ g_assert (salt);
+ g_assert (cipher);
+
+ n_key = gcry_cipher_get_algo_keylen (calgo);
+ g_return_val_if_fail (n_key, FALSE);
+ n_block = gcry_cipher_get_algo_blklen (calgo);
+ g_return_val_if_fail (n_block, FALSE);
+
+ /* Allocate memory for the keys */
+ key = gcry_malloc_secure (n_key);
+ g_return_val_if_fail (key, FALSE);
+ iv = g_malloc0 (n_block);
+
+ if (!gck_crypto_symkey_generate_simple (calgo, halgo, (const gchar*)password,
+ n_password, salt, n_salt, iterations, &key, &iv)) {
+ gcry_free (key);
+ g_free (iv);
+ return FALSE;
+ }
+
+ gcry = gcry_cipher_open (cipher, calgo, GCRY_CIPHER_MODE_CBC, 0);
+ if (gcry) {
+ g_warning ("couldn't create cipher context: %s", gcry_strerror (gcry));
+ gcry_free (key);
+ g_free (iv);
+ return FALSE;
+ }
+
+ gcry = gcry_cipher_setkey (*cipher, key, n_key);
+ g_return_val_if_fail (!gcry, FALSE);
+ gcry_free (key);
+
+ gcry = gcry_cipher_setiv (*cipher, iv, n_block);
+ g_return_val_if_fail (!gcry, FALSE);
+ g_free (iv);
+
+ return TRUE;
+}
+
+static gboolean
+encrypt_buffer (GkrBuffer *input, const guchar *password,
+ gsize n_password, GkrBuffer *output)
+{
+ gcry_cipher_hd_t cipher;
+ gcry_error_t gcry;
+ guchar salt[8];
+ guint32 iterations;
+ int calgo, halgo;
+ const gchar *salgo;
+ guchar *dest;
+ gsize n_block;
+
+ g_assert (input);
+ g_assert (output);
+
+ /* The algorithms we're going to use */
+ calgo = GCRY_CIPHER_AES128;
+ halgo = GCRY_MD_SHA256;
+
+ /* Prepare us some salt */
+ gcry_create_nonce (salt, sizeof (salt));
+
+ /* Prepare us the iterations */
+ iterations = 1000 + (int) (1000.0 * rand() / (RAND_MAX + 1.0));
+
+ /* Write out crypto algorithm */
+ salgo = gcry_cipher_algo_name (calgo);
+ g_return_val_if_fail (salgo, FALSE);
+ gkr_buffer_add_string (output, salgo);
+
+ /* Write out the hash algorithm */
+ salgo = gcry_md_algo_name (halgo);
+ g_return_val_if_fail (halgo, FALSE);
+ gkr_buffer_add_string (output, salgo);
+
+ /* Write out the iterations */
+ gkr_buffer_add_uint32 (output, iterations);
+
+ /* And write out the salt */
+ gkr_buffer_add_byte_array (output, salt, sizeof (salt));
+
+ /* Okay now use the above info to create our cipher context */
+ if (!create_cipher (calgo, halgo, password, n_password, salt,
+ sizeof (salt), iterations, &cipher))
+ return FALSE;
+
+ /* Significant block sizes */
+ n_block = gcry_cipher_get_algo_blklen (calgo);
+ g_return_val_if_fail (n_block, FALSE);
+
+ /* Pad the buffer to a multiple of block length */
+ while (input->len % n_block != 0)
+ gkr_buffer_add_byte (input, 0);
+
+ /* Now reserve space for it in the output block, and encrypt */
+ dest = gkr_buffer_add_byte_array_empty (output, input->len);
+ g_return_val_if_fail (dest, FALSE);
+
+ gcry = gcry_cipher_encrypt (cipher, dest, input->len, input->buf, input->len);
+ g_return_val_if_fail (!gcry, FALSE);
+
+ gcry_cipher_close (cipher);
+
+ return TRUE;
+}
+
+static gboolean
+decrypt_buffer (GkrBuffer *input, gsize *offset, const guchar *password,
+ gsize n_password, GkrBuffer *output)
+{
+ gcry_cipher_hd_t cipher;
+ gcry_error_t gcry;
+ const guchar *salt, *data;
+ gsize n_block, n_salt, n_data;
+ guint32 iterations;
+ int calgo, halgo;
+ gchar *salgo;
+
+ g_assert (input);
+ g_assert (output);
+ g_assert (offset);
+
+ /* Read in and interpret the cipher algorithm */
+ if (!gkr_buffer_get_string (input, *offset, offset, &salgo, NULL))
+ return FALSE;
+ calgo = gcry_cipher_map_name (salgo);
+ if (!calgo) {
+ g_warning ("unsupported crypto algorithm: %s", salgo);
+ g_free (salgo);
+ return FALSE;
+ }
+ g_free (salgo);
+
+ /* Read in and interpret the hash algorithm */
+ if (!gkr_buffer_get_string (input, *offset, offset, &salgo, NULL))
+ return FALSE;
+ halgo = gcry_md_map_name (salgo);
+ if (!halgo) {
+ g_warning ("unsupported crypto algorithm: %s", salgo);
+ g_free (salgo);
+ return FALSE;
+ }
+ g_free (salgo);
+
+ /* Read in the iterations, salt, and encrypted data */
+ if (!gkr_buffer_get_uint32 (input, *offset, offset, &iterations) ||
+ !gkr_buffer_get_byte_array (input, *offset, offset, &salt, &n_salt) ||
+ !gkr_buffer_get_byte_array (input, *offset, offset, &data, &n_data))
+ return FALSE;
+
+ /* Significant block sizes */
+ n_block = gcry_cipher_get_algo_blklen (calgo);
+ g_return_val_if_fail (n_block, FALSE);
+
+ /* Make sure the encrypted data is of a good length */
+ if (n_data % n_block != 0) {
+ g_warning ("encrypted data in file store is of an invalid length for algorithm");
+ return FALSE;
+ }
+
+ /* Create the cipher context */
+ if (!create_cipher (calgo, halgo, password, n_password,
+ salt, n_salt, iterations, &cipher))
+ return FALSE;
+
+ /* Now reserve space for it in the output block, and encrypt */
+ gkr_buffer_reset (output);
+ gkr_buffer_resize (output, n_data);
+
+ gcry = gcry_cipher_decrypt (cipher, output->buf, output->len, data, n_data);
+ g_return_val_if_fail (!gcry, FALSE);
+
+ gcry_cipher_close (cipher);
+
+ return TRUE;
+}
+
+/* ----------------------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static GHashTable*
+add_entry (GHashTable *entries, gchar *unique)
+{
+ GHashTable *attributes;
+
+ g_assert (entries);
+ g_assert (unique);
+
+ attributes = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal, NULL, attribute_free);
+ g_hash_table_replace (entries, unique, attributes);
+
+ return attributes;
+}
+
+static const gchar*
+read_entry (GckFileStore *self, GHashTable *entries,
+ GkrBuffer *buffer, gsize *offset)
+{
+ gboolean added = FALSE;
+ CK_ATTRIBUTE attr;
+ CK_ATTRIBUTE_PTR at;
+ gpointer key, value;
+ GHashTable *attributes;
+ gchar *unique, *str;
+ const guchar *data;
+ GckObject *object;
+ gsize n_data;
+ guint64 type;
+ guint32 count, i;
+
+ g_assert (GCK_IS_FILE_STORE (self));
+ g_assert (buffer);
+ g_assert (offset);
+ g_assert (attributes);
+
+ if (!gkr_buffer_get_string (buffer, *offset, offset, &str, (GkrBufferAllocator)g_realloc))
+ return NULL;
+
+ if (g_hash_table_lookup_extended (entries, str, &key, &value)) {
+ unique = key;
+ attributes = value;
+ g_free (str);
+
+ /* Any object that's associated with this */
+ object = g_hash_table_lookup (self->object_by_unique, unique);
+ added = FALSE;
+
+ } else {
+ unique = str;
+ attributes = add_entry (entries, unique);
+
+ /* No object should yet be associated */
+ object = NULL;
+ added = TRUE;
+ }
+
+ if (!gkr_buffer_get_uint32 (buffer, *offset, offset, &count))
+ return NULL;
+
+ for (i = 0; i < count; ++i) {
+ if (!gkr_buffer_get_uint64 (buffer, *offset, offset, &type) ||
+ !gkr_buffer_get_byte_array (buffer, *offset, offset, &data, &n_data))
+ return NULL;
+
+ attr.type = type;
+ attr.pValue = (CK_VOID_PTR)data;
+ attr.ulValueLen = n_data;
+
+ at = g_hash_table_lookup (attributes, &attr.type);
+ if (at != NULL && gck_attribute_equal (&attr, at))
+ continue;
+
+ at = attribute_dup (&attr);
+ g_hash_table_replace (attributes, &(at->type), at);
+
+ if (object != NULL)
+ gck_object_notify_attribute (object, at->type);
+ }
+
+ if (added) {
+ g_assert (!object);
+ g_signal_emit (self, signals[ENTRY_CREATED], 0, unique);
+ }
+
+ g_assert (unique);
+ return unique;
+}
+
+static void
+clear_each_entry (gpointer key, gpointer value, gpointer data)
+{
+ GHashTable *attributes = value;
+ g_hash_table_remove_all (attributes);
+}
+
+static void
+copy_each_unique_id (gpointer key, gpointer value, gpointer data)
+{
+ g_hash_table_insert (data, g_strdup (key), GUINT_TO_POINTER (1));
+}
+
+static void
+destroy_each_unique_id (gpointer key, gpointer value, gpointer data)
+{
+ /* Our default handler does the actual remove */
+ g_signal_emit (data, signals[ENTRY_DESTROYED], 0, key);
+}
+
+static gboolean
+read_entries (GckFileStore *self, GHashTable *entries, GkrBuffer *buffer, gsize *offset)
+{
+ GHashTable *checks;
+ const gchar *unique;
+ guint32 count, i;
+
+ g_assert (GCK_IS_FILE_STORE (self));
+ g_assert (entries);
+ g_assert (buffer);
+ g_assert (offset);
+
+ /* The number of entries */
+ if (!gkr_buffer_get_uint32 (buffer, *offset, offset, &count))
+ return FALSE;
+
+ checks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ g_hash_table_foreach (entries, copy_each_unique_id, checks);
+
+ for (i = 0; i < count; ++i) {
+ unique = read_entry (self, entries, buffer, offset);
+ if (!unique) {
+ g_hash_table_destroy (checks);
+ return FALSE;
+ }
+
+ g_hash_table_remove (checks, unique);
+ }
+
+ g_hash_table_foreach (checks, destroy_each_unique_id, self);
+ g_hash_table_destroy (checks);
+ return TRUE;
+}
+
+static gboolean
+read_from_block (guint block, GkrBuffer *buffer, gpointer user_data)
+{
+ GckFileStore *self;
+ gsize offset;
+ GkrBuffer custom;
+ GHashTable *attributes;
+ gboolean ret = FALSE;
+
+ g_assert (GCK_IS_FILE_STORE (user_data));
+ g_assert (buffer);
+
+ self = GCK_FILE_STORE (user_data);
+
+ switch (block) {
+ case FILE_BLOCK_PRIVATE:
+ /* Skip private blocks when not unlocked */
+ if (self->locked)
+ return TRUE;
+
+ attributes = self->privates;
+ gkr_buffer_init_full (&custom, 1024, gkr_secure_realloc);
+
+ offset = 0;
+ if (!decrypt_buffer (buffer, &offset, self->password, self->n_password, &custom)) {
+ g_warning ("couldn't decrypt private attributes in store file");
+ gkr_buffer_uninit (&custom);
+ return FALSE;
+ }
+
+ buffer = &custom;
+ break;
+
+ case FILE_BLOCK_PUBLIC:
+ attributes = self->publics;
+ gkr_buffer_init_static (&custom, NULL, 0);
+ break;
+
+ default:
+ return TRUE;
+ }
+
+ offset = 0;
+
+ /* Validate the buffer hash, failure is usually a bad password */
+ if (!validate_buffer (buffer, &offset)) {
+ if (block == FILE_BLOCK_PRIVATE)
+ ++self->unlock_failures;
+ ret = FALSE;
+ } else {
+ ret = read_entries (self, attributes, buffer, &offset);
+ }
+
+ gkr_buffer_uninit (&custom);
+ return ret;
+}
+
+static void
+write_each_attribute (gpointer key, gpointer value, gpointer data)
+{
+ CK_ATTRIBUTE_PTR attr = value;
+ GkrBuffer *buffer = data;
+ gkr_buffer_add_uint64 (buffer, attr->type);
+ g_assert (attr->ulValueLen != (gulong)-1);
+ gkr_buffer_add_byte_array (buffer, attr->pValue, attr->ulValueLen);
+}
+
+static void
+write_each_entry (gpointer key, gpointer value, gpointer data)
+{
+ GkrBuffer *buffer = data;
+ const gchar *unique = key;
+ GHashTable *attributes = value;
+
+ gkr_buffer_add_string (buffer, unique);
+ gkr_buffer_add_uint32 (buffer, g_hash_table_size (attributes));
+ g_hash_table_foreach (attributes, write_each_attribute, buffer);
+}
+
+static gboolean
+write_entries (GckFileStore *self, GkrBuffer *output, GHashTable *entries, gboolean is_private)
+{
+ GkrBuffer secure;
+ GkrBuffer *buffer;
+ gsize offset;
+
+ g_assert (GCK_FILE_STORE (self));
+ g_assert (output);
+
+ if (is_private) {
+ gkr_buffer_init_full (&secure, 1024, PRIVATE_ALLOC);
+ buffer = &secure;
+ } else {
+ gkr_buffer_init_static (&secure, NULL, 0);
+ buffer = output;
+ }
+
+ /* Reserve space for the length */
+ offset = buffer->len;
+ gkr_buffer_add_uint32 (buffer, 0);
+
+ /* The number of attributes we'll be encountering */
+ gkr_buffer_add_uint32 (buffer, g_hash_table_size (entries));
+
+ /* Fill in the attributes */
+ g_hash_table_foreach (entries, write_each_entry, buffer);
+
+ g_return_val_if_fail (!gkr_buffer_has_error (buffer), FALSE);
+
+ /* Fill in the length */
+ gkr_buffer_set_uint32 (buffer, offset, buffer->len);
+
+ /* Hash the entire dealio */
+ if (!hash_buffer (buffer)) {
+ gkr_buffer_uninit (&secure);
+ return FALSE;
+ }
+
+ if (is_private) {
+ if (!encrypt_buffer (buffer, self->password, self->n_password, output)) {
+ gkr_buffer_uninit (&secure);
+ return FALSE;
+ }
+ }
+
+ gkr_buffer_uninit (&secure);
+ return TRUE;
+}
+
+static gboolean
+write_entries_block (GckFileStore *self, GHashTable *entries)
+{
+ GkrBuffer buffer;
+ gboolean is_private;
+ gboolean ret;
+ guint32 block;
+
+ g_assert (GCK_IS_FILE_STORE (self));
+ g_assert (self->transaction_fd != -1);
+ g_assert (entries);
+
+ if (entries == self->privates) {
+ is_private = TRUE;
+ block = FILE_BLOCK_PRIVATE;
+ } else {
+ is_private = FALSE;
+ block = FILE_BLOCK_PUBLIC;
+ }
+
+ g_assert (!is_private || !self->locked);
+ gkr_buffer_init_full (&buffer, 1024, PUBLIC_ALLOC);
+
+ ret = write_entries (self, &buffer, entries, is_private);
+ if (ret == TRUE && gkr_buffer_has_error (&buffer)) {
+ g_warning ("couldn't prepare file store buffer for writing");
+ g_return_val_if_reached (FALSE);
+ }
+
+ ret = write_file_block (self->transaction_fd, block, &buffer);
+ gkr_buffer_uninit (&buffer);
+ return ret;
+}
+
+static gboolean
+write_extraneous_block (guint block, GkrBuffer *buffer, gpointer user_data)
+{
+ GckFileStore *self = GCK_FILE_STORE (user_data);
+
+ g_assert (GCK_IS_FILE_STORE (user_data));
+ g_assert (self->transaction_fd != -1);
+ g_assert (buffer);
+
+ self = GCK_FILE_STORE (user_data);
+
+ switch (block) {
+
+ /* We can always write public attribute blocks, skip. */
+ case FILE_BLOCK_PUBLIC:
+ return TRUE;
+
+ /* We can write private attribute blocks when not locked, skip. */
+ case FILE_BLOCK_PRIVATE:
+ if (!self->locked)
+ return TRUE;
+ break;
+
+ default:
+ break;
+ };
+
+ /* Write out the block we don't or can't write */
+ if (!write_file_block (self->transaction_fd, block, buffer))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+cleanup_transaction (GckFileStore *self, GckTransaction *transaction)
+{
+ g_assert (GCK_IS_FILE_STORE (self));
+ g_assert (GCK_IS_TRANSACTION (transaction));
+ g_assert (self->transaction == transaction);
+
+ if (self->previous_fd != -1)
+ close (self->previous_fd);
+ self->previous_fd = -1;
+
+ if (self->transaction_fd != -1)
+ close (self->transaction_fd);
+ self->transaction_fd = -1;
+
+ if (self->transaction_path) {
+ g_unlink (self->transaction_path);
+ g_free (self->transaction_path);
+ self->transaction_path = NULL;
+ }
+
+ g_object_unref (self->transaction);
+ self->transaction = NULL;
+}
+
+static void
+fail_transaction (GckFileStore *self, GckTransaction *transaction)
+{
+ gck_transaction_fail (transaction, CKR_FUNCTION_FAILED);
+ cleanup_transaction (self, transaction);
+}
+
+static gboolean
+complete_transaction (GckTransaction *transaction, GckFileStore *self, gpointer unused)
+{
+ struct stat sb;
+
+ g_return_val_if_fail (GCK_IS_FILE_STORE (self), FALSE);
+ g_return_val_if_fail (GCK_IS_TRANSACTION (transaction), FALSE);
+ g_return_val_if_fail (self->transaction == transaction, FALSE);
+
+ if (!gck_transaction_get_failed (transaction)) {
+
+ if (!self->locked) {
+ if (!write_entries_block (self, self->privates))
+ return FALSE;
+ }
+
+ if (!write_entries_block (self, self->publics))
+ return FALSE;
+
+ /* Move the file into place */
+ if (g_rename (self->transaction_path, self->filename) == -1) {
+ g_warning ("couldn't rename temporary store file: %s", self->transaction_path);
+ return FALSE;
+ }
+
+ /* Stat the file and save away the last mtime */
+ if (stat (self->filename, &sb) >= 0)
+ self->last_mtime = sb.st_mtime;
+
+ } else {
+
+ /* Transaction failed, load the old stuff again */
+ gck_file_store_refresh (self);
+ }
+
+ /* And we're all done */
+ cleanup_transaction (self, transaction);
+ return TRUE;
+}
+
+#ifndef HAVE_FLOCK
+#define LOCK_SH 1
+#define LOCK_EX 2
+#define LOCK_NB 4
+#define LOCK_UN 8
+
+static int flock(int fd, int operation)
+{
+ struct flock flock;
+
+ switch (operation & ~LOCK_NB) {
+ case LOCK_SH:
+ flock.l_type = F_RDLCK;
+ break;
+ case LOCK_EX:
+ flock.l_type = F_WRLCK;
+ break;
+ case LOCK_UN:
+ flock.l_type = F_UNLCK;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ flock.l_whence = 0;
+ flock.l_start = 0;
+ flock.l_len = 0;
+
+ return fcntl (fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &flock);
+}
+#endif /* !HAVE_FLOCK */
+
+static gboolean
+prepare_transaction (GckFileStore *self, GckTransaction *transaction)
+{
+ struct stat sb;
+ guint tries = 0;
+
+ g_assert (GCK_IS_FILE_STORE (self));
+ g_assert (GCK_IS_TRANSACTION (transaction));
+
+ if (self->transaction) {
+ g_return_val_if_fail (self->transaction == transaction, FALSE);
+ return TRUE;
+ }
+
+ g_return_val_if_fail (self->filename, FALSE);
+ g_assert (self->previous_fd == -1);
+
+ self->transaction = g_object_ref (transaction);
+
+ /* File lock retry loop */
+ for (tries = 0; TRUE; ++tries) {
+ if (tries > MAX_LOCK_TRIES) {
+ g_message ("couldn't write to store file: %s: file is locked", self->filename);
+ fail_transaction (self, transaction);
+ return FALSE;
+ }
+
+ self->previous_fd = open (self->filename, O_RDONLY | O_CREAT, S_IRUSR | S_IWUSR);
+ if (self->previous_fd == -1) {
+ g_message ("couldn't open store file: %s: %s", self->filename, g_strerror (errno));
+ fail_transaction (self, transaction);
+ return FALSE;
+ }
+
+ if (flock (self->previous_fd, LOCK_EX | LOCK_NB) < 0) {
+
+ if (errno != EWOULDBLOCK) {
+ g_message ("couldn't lock store file: %s: %s", self->filename, g_strerror (errno));
+ fail_transaction (self, transaction);
+ return FALSE;
+ }
+
+ close (self->previous_fd);
+ self->previous_fd = -1;
+ g_usleep (200000);
+ continue;
+ }
+
+ /* Successfully opened file */;
+ break;
+ }
+
+ /* See if file needs updating */
+ if (fstat (self->previous_fd, &sb) >= 0 && sb.st_mtime != self->last_mtime) {
+ if (!parse_file_blocks (self->previous_fd, read_from_block, self) ||
+ lseek (self->previous_fd, 0, SEEK_SET) != 0) {
+ g_message ("couldn't update store from file: %s", self->filename);
+ fail_transaction (self, transaction);
+ return FALSE;
+ }
+
+ self->last_mtime = sb.st_mtime;
+ }
+
+ /* Open the new file */
+ g_assert (self->transaction_fd == -1);
+ self->transaction_path = g_strdup_printf ("%s.XXXXXX", self->filename);
+ self->transaction_fd = g_mkstemp (self->transaction_path);
+ if (self->transaction_fd == -1) {
+ g_message ("couldn't open new temporary store file: %s: %s", self->filename, g_strerror (errno));
+ fail_transaction (self, transaction);
+ return FALSE;
+ }
+
+ /* Now write out everything that we don't understand from previous one into the new */
+ if (!write_all_bytes (self->transaction_fd, FILE_HEADER, FILE_HEADER_LEN) ||
+ !parse_file_blocks (self->previous_fd, write_extraneous_block, self)) {
+ fail_transaction (self, transaction);
+ return FALSE;
+ }
+
+ /* And we're ready for changes. */
+ gck_transaction_add (transaction, self, (GckTransactionFunc)complete_transaction, NULL);
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gck_file_store_real_entry_created (GckFileStore *self, const gchar *unique_id)
+{
+ /* Actual action happens elsewhere */
+ g_return_if_fail (g_hash_table_lookup (self->publics, unique_id) ||
+ g_hash_table_lookup (self->privates, unique_id));
+}
+
+static void
+gck_file_store_real_entry_destroyed (GckFileStore *self, const gchar *unique_id)
+{
+ /*
+ * Note we don't remove the object -> unique mapping, we
+ * keep that unrelated.
+ */
+
+ /* Actual action happens here */
+ if (!g_hash_table_remove (self->publics, unique_id)) {
+ g_return_if_fail (self->locked);
+ if (!g_hash_table_remove (self->privates, unique_id))
+ g_return_if_reached ();
+ }
+}
+
+static CK_RV
+gck_file_store_real_read_value (GckStore *base, GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+ GckFileStore *self = GCK_FILE_STORE (base);
+ CK_ATTRIBUTE_PTR at;
+ GHashTable *attributes;
+ const gchar *unique;
+
+ g_return_val_if_fail (GCK_IS_FILE_STORE (self), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (GCK_IS_OBJECT (object), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+
+ unique = g_hash_table_lookup (self->unique_by_object, object);
+ if (!unique)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ if (self->last_mtime == 0) {
+ if (!gck_file_store_refresh (self))
+ return CKR_FUNCTION_FAILED;
+ }
+
+ attributes = g_hash_table_lookup (self->publics, unique);
+ if (attributes == NULL) {
+ attributes = g_hash_table_lookup (self->privates, unique);
+ if (attributes && self->locked)
+ return CKR_USER_NOT_LOGGED_IN;
+ }
+
+ if (!attributes)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ at = g_hash_table_lookup (attributes, &(attr->type));
+ if (at == NULL)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ g_assert (at->type == attr->type);
+
+ /* Yes, we don't fill a buffer, just return pointer */
+ attr->pValue = at->pValue;
+ attr->ulValueLen = at->ulValueLen;
+
+ return CKR_OK;
+}
+
+static void
+gck_file_store_real_write_value (GckStore *base, GckTransaction *transaction,
+ GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+ GckFileStore *self = GCK_FILE_STORE (base);
+ CK_ATTRIBUTE_PTR at;
+ GHashTable *attributes;
+ const gchar *unique;
+
+ g_return_if_fail (GCK_IS_FILE_STORE (self));
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (!gck_transaction_get_failed (transaction));
+ g_return_if_fail (attr);
+
+ unique = g_hash_table_lookup (self->unique_by_object, object);
+ if (!unique) {
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
+ return;
+ }
+
+ if (self->last_mtime == 0) {
+ if (!gck_file_store_refresh (self))
+ gck_transaction_fail (transaction, CKR_FUNCTION_FAILED);
+ }
+
+ attributes = g_hash_table_lookup (self->publics, unique);
+ if (attributes == NULL) {
+ attributes = g_hash_table_lookup (self->privates, unique);
+ if (attributes && self->locked) {
+ gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
+ return;
+ }
+ }
+
+ if (!attributes) {
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
+ return;
+ }
+
+ /* No need to go any further if no change */
+ at = g_hash_table_lookup (attributes, &(attr->type));
+ if (at != NULL && gck_attribute_equal (at, attr))
+ return;
+
+ if (!prepare_transaction (self, transaction))
+ return;
+
+ attr = attribute_dup (attr);
+ g_hash_table_replace (attributes, &(attr->type), attr);
+ gck_object_notify_attribute (object, attr->type);
+}
+
+static GObject*
+gck_file_store_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+ GckFileStore *self = GCK_FILE_STORE (G_OBJECT_CLASS (gck_file_store_parent_class)->constructor(type, n_props, props));
+ g_return_val_if_fail (self, NULL);
+
+ g_return_val_if_fail (self->filename, NULL);
+
+ return G_OBJECT (self);
+}
+
+static void
+gck_file_store_init (GckFileStore *self)
+{
+ self->object_by_unique = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ self->unique_by_object = g_hash_table_new (g_direct_hash, g_direct_equal);
+ self->publics = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify)g_hash_table_unref);
+ self->privates = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL, (GDestroyNotify)g_hash_table_unref);
+ self->previous_fd = -1;
+ self->transaction_fd = -1;
+ self->locked = TRUE;
+}
+
+static void
+gck_file_store_dispose (GObject *obj)
+{
+ GckFileStore *self = GCK_FILE_STORE (obj);
+
+ g_hash_table_remove_all (self->unique_by_object);
+ g_hash_table_remove_all (self->object_by_unique);
+
+ G_OBJECT_CLASS (gck_file_store_parent_class)->dispose (obj);
+}
+
+static void
+gck_file_store_finalize (GObject *obj)
+{
+ GckFileStore *self = GCK_FILE_STORE (obj);
+
+ g_free (self->filename);
+ self->filename = NULL;
+
+ g_hash_table_destroy (self->object_by_unique);
+ self->object_by_unique = NULL;
+ g_hash_table_destroy (self->unique_by_object);
+ self->unique_by_object = NULL;
+
+ g_hash_table_destroy (self->publics);
+ g_hash_table_destroy (self->privates);
+
+ gkr_secure_free (self->password);
+ self->password = NULL;
+ self->n_password = 0;
+
+ G_OBJECT_CLASS (gck_file_store_parent_class)->finalize (obj);
+}
+
+static void
+gck_file_store_set_property (GObject *obj, guint prop_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ GckFileStore *self = GCK_FILE_STORE (obj);
+
+ switch (prop_id) {
+ case PROP_FILENAME:
+ g_return_if_fail (!self->filename);
+ self->filename = g_value_dup_string (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_file_store_get_property (GObject *obj, guint prop_id, GValue *value,
+ GParamSpec *pspec)
+{
+ GckFileStore *self = GCK_FILE_STORE (obj);
+
+ switch (prop_id) {
+ case PROP_FILENAME:
+ g_value_set_string (value, gck_file_store_get_filename (self));
+ break;
+ case PROP_LOCKED:
+ g_value_set_boolean (value, gck_file_store_get_locked (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_file_store_class_init (GckFileStoreClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GckStoreClass *store_class = GCK_STORE_CLASS (klass);
+
+ gobject_class->constructor = gck_file_store_constructor;
+ gobject_class->dispose = gck_file_store_dispose;
+ gobject_class->finalize = gck_file_store_finalize;
+ gobject_class->set_property = gck_file_store_set_property;
+ gobject_class->get_property = gck_file_store_get_property;
+
+ store_class->read_value = gck_file_store_real_read_value;
+ store_class->write_value = gck_file_store_real_write_value;
+
+ klass->entry_created = gck_file_store_real_entry_created;
+ klass->entry_destroyed = gck_file_store_real_entry_destroyed;
+
+ g_object_class_install_property (gobject_class, PROP_FILENAME,
+ g_param_spec_string ("filename", "File Name", "File name of the store",
+ NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_LOCKED,
+ g_param_spec_boolean ("locked", "Locked", "Whether store is locked",
+ TRUE, G_PARAM_READABLE));
+
+ signals[ENTRY_CREATED] = g_signal_new ("entry-created", GCK_TYPE_FILE_STORE,
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckFileStoreClass, entry_created),
+ NULL, NULL, g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+
+ signals[ENTRY_DESTROYED] = g_signal_new ("entry-destroyed", GCK_TYPE_FILE_STORE,
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckFileStoreClass, entry_destroyed),
+ NULL, NULL, g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GckFileStore*
+gck_file_store_new (const gchar *filename)
+{
+ g_return_val_if_fail (filename, NULL);
+ g_return_val_if_fail (filename[0], NULL);
+ return g_object_new (GCK_TYPE_FILE_STORE, "filename", filename, NULL);
+}
+
+gboolean
+gck_file_store_have_entry (GckFileStore *self, const gchar *unique_id)
+{
+ g_return_val_if_fail (GCK_IS_FILE_STORE (self), FALSE);
+ g_return_val_if_fail (unique_id, FALSE);
+
+ return (g_hash_table_lookup (self->publics, unique_id) ||
+ g_hash_table_lookup (self->privates, unique_id));
+}
+
+void
+gck_file_store_create_entry (GckFileStore *self, GckTransaction *transaction,
+ const gchar *unique_id, gboolean is_private)
+{
+ GHashTable *entries;
+ gchar *unique;
+
+ g_return_if_fail (GCK_IS_FILE_STORE (self));
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (unique_id);
+
+ /* We can't add an entry twice */
+ if (is_private) {
+ g_return_if_fail (!self->locked);
+ entries = self->privates;
+ } else {
+ entries = self->publics;
+ }
+
+ g_return_if_fail (g_hash_table_lookup (entries, unique_id) == NULL);
+
+ if (!prepare_transaction (self, transaction))
+ return;
+
+ unique = g_strdup (unique_id);
+ add_entry (entries, unique);
+ g_signal_emit (self, signals[ENTRY_CREATED], 0, unique);
+}
+
+void
+gck_file_store_connect_entry (GckFileStore *self, const gchar *unique_id, GckObject *object)
+{
+ gchar *unique;
+
+ g_return_if_fail (GCK_IS_FILE_STORE (self));
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_return_if_fail (unique_id);
+
+ g_return_if_fail (g_hash_table_lookup (self->object_by_unique, unique_id) == NULL);
+ g_return_if_fail (g_hash_table_lookup (self->unique_by_object, object) == NULL);
+
+ unique = g_strdup (unique_id);
+ g_hash_table_replace (self->object_by_unique, unique, object);
+ g_hash_table_replace (self->unique_by_object, object, unique);
+}
+
+void
+gck_file_store_disconnect_entry (GckFileStore *self, const gchar *unique_id, GckObject *object)
+{
+ const gchar *unique;
+ g_return_if_fail (GCK_IS_FILE_STORE (self));
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_return_if_fail (unique_id);
+
+ g_return_if_fail (g_hash_table_lookup (self->object_by_unique, unique_id) == object);
+ unique = g_hash_table_lookup (self->unique_by_object, object);
+ g_return_if_fail (unique && g_str_equal (unique, unique_id));
+
+ g_hash_table_remove (self->unique_by_object, object);
+ g_hash_table_remove (self->object_by_unique, unique);
+}
+
+void
+gck_file_store_destroy_entry (GckFileStore *self, GckTransaction *transaction,
+ const gchar *unique_id)
+{
+ g_return_if_fail (GCK_IS_FILE_STORE (self));
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (unique_id);
+
+ /* Can't destroy something that doesn't exist */
+ if (!g_hash_table_lookup (self->publics, unique_id) &&
+ !g_hash_table_lookup (self->privates, unique_id)) {
+ g_return_if_reached ();
+ }
+
+ if (!prepare_transaction (self, transaction))
+ return;
+
+ /* The default handler actually does the deed */
+ g_signal_emit (self, signals[ENTRY_DESTROYED], 0, unique_id);
+}
+
+const gchar*
+gck_file_store_get_filename (GckFileStore *self)
+{
+ g_return_val_if_fail (GCK_IS_FILE_STORE (self), NULL);
+ return self->filename;
+}
+
+gboolean
+gck_file_store_refresh (GckFileStore *self)
+{
+ struct stat sb;
+ gboolean ret;
+ int file;
+
+ g_return_val_if_fail (GCK_IS_FILE_STORE (self), FALSE);
+
+ /* Open the file for reading */
+ file = open (self->filename, O_RDONLY, 0);
+ if (file == -1) {
+ /* No file, no worries */
+ if (errno == ENOENT)
+ return TRUE;
+ g_message ("couldn't open store file: %s: %s", self->filename, g_strerror (errno));
+ return FALSE;
+ }
+
+ /* Try and update the last read time */
+ if (fstat (file, &sb) >= 0)
+ self->last_mtime = sb.st_mtime;
+
+ ret = parse_file_blocks (file, read_from_block, self);
+
+ /* Force a reread on next write */
+ if (ret == FALSE)
+ self->last_mtime = 0;
+
+ close (file);
+ return ret;
+}
+
+CK_RV
+gck_file_store_unlock (GckFileStore *self, guchar *password,
+ gsize n_password)
+{
+ g_return_val_if_fail (GCK_IS_FILE_STORE (self), CKR_GENERAL_ERROR);
+
+ if (!self->locked)
+ return CKR_USER_ALREADY_LOGGED_IN;
+
+ /* Don't copy until we're sure it worked */
+ g_assert (!self->password);
+ self->password = password;
+ self->n_password = n_password;
+ self->unlock_failures = 0;
+ self->locked = FALSE;
+
+ if (!gck_file_store_refresh (self)) {
+ self->locked = TRUE;
+ self->password = NULL;
+ self->n_password = 0;
+ if (self->unlock_failures)
+ return CKR_PIN_INCORRECT;
+ else
+ return CKR_FUNCTION_FAILED;
+ }
+
+ if (self->password) {
+ self->password = gkr_secure_alloc (n_password);
+ memcpy (self->password, password, n_password);
+ self->n_password = n_password;
+ }
+
+ self->locked = FALSE;
+ g_object_notify (G_OBJECT (self), "locked");
+ return CKR_OK;
+}
+
+CK_RV
+gck_file_store_lock (GckFileStore *self)
+{
+ g_return_val_if_fail (GCK_IS_FILE_STORE (self), CKR_GENERAL_ERROR);
+
+ if (self->locked)
+ return CKR_USER_NOT_LOGGED_IN;
+
+ /* Remove all data for each private one */
+ g_hash_table_foreach (self->privates, clear_each_entry, NULL);
+
+ gkr_secure_free (self->password);
+ self->password = NULL;
+ self->n_password = 0;
+ self->locked = TRUE;
+ g_object_notify (G_OBJECT (self), "locked");
+
+ return CKR_OK;
+}
+
+gboolean
+gck_file_store_get_locked (GckFileStore *self)
+{
+ g_return_val_if_fail (GCK_IS_FILE_STORE (self), TRUE);
+ return self->locked;
+}
Added: trunk/pkcs11/gck/gck-file-store.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-file-store.h Sat Jan 3 19:30:08 2009
@@ -0,0 +1,86 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCK_FILE_STORE_H__
+#define __GCK_FILE_STORE_H__
+
+#include <glib-object.h>
+
+#include "gck-store.h"
+#include "gck-types.h"
+
+#define GCK_TYPE_FILE_STORE (gck_file_store_get_type ())
+#define GCK_FILE_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_FILE_STORE, GckFileStore))
+#define GCK_FILE_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_FILE_STORE, GckFileStoreClass))
+#define GCK_IS_FILE_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_FILE_STORE))
+#define GCK_IS_FILE_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_FILE_STORE))
+#define GCK_FILE_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_FILE_STORE, GckFileStoreClass))
+
+typedef struct _GckFileStore GckFileStore;
+typedef struct _GckFileStoreClass GckFileStoreClass;
+
+struct _GckFileStoreClass {
+ GckStoreClass parent_class;
+
+ /* signals */
+
+ void (*entry_created) (GckFileStore *store, const gchar *unique_id);
+
+ void (*entry_destroyed) (GckFileStore *store, const gchar *unique_id);
+};
+
+GType gck_file_store_get_type (void);
+
+GckFileStore* gck_file_store_new (const gchar *filename);
+
+const gchar* gck_file_store_get_filename (GckFileStore *self);
+
+gboolean gck_file_store_refresh (GckFileStore *self);
+
+CK_RV gck_file_store_unlock (GckFileStore *self,
+ guchar *password,
+ gsize n_password);
+
+CK_RV gck_file_store_lock (GckFileStore *self);
+
+gboolean gck_file_store_get_locked (GckFileStore *self);
+
+gboolean gck_file_store_have_entry (GckFileStore *self,
+ const gchar *unique_id);
+
+void gck_file_store_create_entry (GckFileStore *self,
+ GckTransaction *transaction,
+ const gchar *unique_id,
+ gboolean is_private);
+
+void gck_file_store_connect_entry (GckFileStore *self,
+ const gchar *unique_id,
+ GckObject *object);
+
+void gck_file_store_disconnect_entry (GckFileStore *self,
+ const gchar *unique_id,
+ GckObject *object);
+
+void gck_file_store_destroy_entry (GckFileStore *self,
+ GckTransaction *transaction,
+ const gchar *unique_id);
+
+#endif /* __GCK_FILE_STORE_H__ */
Modified: trunk/pkcs11/gck/gck-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-key.c (original)
+++ trunk/pkcs11/gck/gck-key.c Sat Jan 3 19:30:08 2009
@@ -23,6 +23,7 @@
#include "pkcs11/pkcs11.h"
+#include "gck-attributes.h"
#include "gck-crypto.h"
#include "gck-key.h"
#include "gck-util.h"
@@ -57,9 +58,9 @@
{
switch (gck_key_get_algorithm (self)) {
case GCRY_PK_RSA:
- return gck_util_set_ulong (attr, CKK_RSA);
+ return gck_attribute_set_ulong (attr, CKK_RSA);
case GCRY_PK_DSA:
- return gck_util_set_ulong (attr, CKK_DSA);
+ return gck_attribute_set_ulong (attr, CKK_DSA);
default:
g_return_val_if_reached (CKR_GENERAL_ERROR);
};
@@ -72,30 +73,30 @@
g_return_val_if_fail (self->pv->base_sexp, CKR_GENERAL_ERROR);
if (!gcry_pk_get_keygrip (gck_sexp_get (self->pv->base_sexp), hash))
g_return_val_if_reached (CKR_GENERAL_ERROR);
- return gck_util_set_data (attr, hash, sizeof (hash));
+ return gck_attribute_set_data (attr, hash, sizeof (hash));
}
break;
case CKA_START_DATE:
case CKA_END_DATE:
- return gck_util_set_data (attr, "", 0);
+ return gck_attribute_set_data (attr, "", 0);
case CKA_DERIVE:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_LOCAL:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_KEY_GEN_MECHANISM:
- return gck_util_set_ulong (attr, CK_UNAVAILABLE_INFORMATION);
+ return gck_attribute_set_ulong (attr, CK_UNAVAILABLE_INFORMATION);
case CKA_ALLOWED_MECHANISMS:
switch (gck_key_get_algorithm (self)) {
case GCRY_PK_RSA:
- return gck_util_set_data (attr, (CK_VOID_PTR)GCK_CRYPTO_RSA_MECHANISMS,
+ return gck_attribute_set_data (attr, (CK_VOID_PTR)GCK_CRYPTO_RSA_MECHANISMS,
sizeof (GCK_CRYPTO_RSA_MECHANISMS));
case GCRY_PK_DSA:
- return gck_util_set_data (attr, (CK_VOID_PTR)GCK_CRYPTO_DSA_MECHANISMS,
+ return gck_attribute_set_data (attr, (CK_VOID_PTR)GCK_CRYPTO_DSA_MECHANISMS,
sizeof (GCK_CRYPTO_DSA_MECHANISMS));
default:
g_return_val_if_reached (CKR_GENERAL_ERROR);
@@ -104,7 +105,7 @@
/* Lookup the certificate subject */
case CKA_SUBJECT:
/* TODO: When we have certificates, implement this */
- return gck_util_set_data (attr, "", 0);
+ return gck_attribute_set_data (attr, "", 0);
};
return GCK_OBJECT_CLASS (gck_key_parent_class)->get_attribute (base, attr);
@@ -274,7 +275,7 @@
if (!gck_crypto_sexp_extract_mpi (numbers, &mpi, part, NULL))
g_return_val_if_reached (CKR_GENERAL_ERROR);
- rv = gck_util_set_mpi (attr, mpi);
+ rv = gck_attribute_set_mpi (attr, mpi);
gcry_sexp_release (numbers);
gcry_mpi_release (mpi);
Modified: trunk/pkcs11/gck/gck-key.h
==============================================================================
--- trunk/pkcs11/gck/gck-key.h (original)
+++ trunk/pkcs11/gck/gck-key.h Sat Jan 3 19:30:08 2009
@@ -26,6 +26,7 @@
#include "gck-sexp.h"
#include "gck-object.h"
+#include "gck-types.h"
#define GCK_TYPE_KEY (gck_key_get_type ())
#define GCK_KEY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_KEY, GckKey))
@@ -34,7 +35,6 @@
#define GCK_IS_KEY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_KEY))
#define GCK_KEY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_KEY, GckKeyClass))
-typedef struct _GckKey GckKey;
typedef struct _GckKeyClass GckKeyClass;
typedef struct _GckKeyPrivate GckKeyPrivate;
Modified: trunk/pkcs11/gck/gck-manager.c
==============================================================================
--- trunk/pkcs11/gck/gck-manager.c (original)
+++ trunk/pkcs11/gck/gck-manager.c Sat Jan 3 19:30:08 2009
@@ -21,6 +21,7 @@
#include "config.h"
+#include "gck-attributes.h"
#include "gck-manager.h"
#include "gck-util.h"
@@ -73,51 +74,6 @@
}
}
-static gboolean
-attribute_equal (gconstpointer v1, gconstpointer v2)
-{
- const CK_ATTRIBUTE *a1 = v1;
- const CK_ATTRIBUTE *a2 = v2;
-
- g_assert (a1);
- g_assert (a2);
-
- if (a1 == a2)
- return TRUE;
- if (a1->type != a2->type)
- return FALSE;
- if (a1->ulValueLen != a2->ulValueLen)
- return FALSE;
- if (a1->pValue == a2->pValue)
- return TRUE;
-
- g_assert (a1->pValue);
- g_assert (a2->pValue);
-
- return memcmp (a1->pValue, a2->pValue, a1->ulValueLen) == 0;
-}
-
-static guint
-attribute_hash (gconstpointer v)
-{
- const CK_ATTRIBUTE *a = v;
- const signed char *p;
- guint i, h;
-
- g_assert (a);
-
- p = (const signed char*)&(a->type);
- h = *p;
- for(i = 0; i < sizeof (CK_ATTRIBUTE_PTR); ++i)
- h = (h << 5) - h + *(p++);
-
- p = a->pValue;
- for(i = 0; i < a->ulValueLen; ++i)
- h = (h << 5) - h + *(p++);
-
- return h;
-}
-
static Index*
index_new (gboolean unique)
{
@@ -125,9 +81,9 @@
index->unique = unique;
if (unique)
- index->values = g_hash_table_new_full (attribute_hash, attribute_equal, attribute_free, NULL);
+ index->values = g_hash_table_new_full (gck_attribute_hash, gck_attribute_equal, attribute_free, NULL);
else
- index->values = g_hash_table_new_full (attribute_hash, attribute_equal, attribute_free,
+ index->values = g_hash_table_new_full (gck_attribute_hash, gck_attribute_equal, attribute_free,
(GDestroyNotify)g_hash_table_destroy);
index->objects = g_hash_table_new (g_direct_hash, g_direct_equal);
@@ -267,9 +223,58 @@
}
static void
-index_update (Index *index, GckObject *object)
+index_remove_attr (Index *index, gpointer object, CK_ATTRIBUTE_PTR attr)
+{
+ GHashTable *objects;
+
+ g_assert (index);
+ g_assert (object);
+ g_assert (attr);
+
+ if (index->unique) {
+ if (!g_hash_table_remove (index->values, attr))
+ g_assert_not_reached ();
+ } else {
+ objects = g_hash_table_lookup (index->values, attr);
+ g_assert (objects);
+ if (!g_hash_table_remove (objects, object))
+ g_assert_not_reached ();
+ if (g_hash_table_size (objects) == 0)
+ if (!g_hash_table_remove (index->values, attr))
+ g_assert_not_reached ();
+ }
+}
+
+static void
+index_remove (Index *index, gpointer object)
{
CK_ATTRIBUTE_PTR attr;
+
+ /*
+ * We don't actually access the object. We want to be able to
+ * handle objects that have been destroyed as well.
+ */
+
+ g_assert (object);
+ g_assert (index);
+
+ attr = g_hash_table_lookup (index->objects, object);
+
+ /* Object not in this index */
+ if (attr == NULL)
+ return;
+
+ /* Remove the actual value */
+ index_remove_attr (index, object, attr);
+
+ if (!g_hash_table_remove (index->objects, object))
+ g_assert_not_reached ();
+}
+
+static void
+index_update (Index *index, GckObject *object)
+{
+ CK_ATTRIBUTE_PTR attr, prev;
GHashTable *objects;
gboolean ret;
@@ -286,7 +291,20 @@
/* No such attribute/property on object */
if (attr == NULL)
return;
-
+
+ prev = g_hash_table_lookup (index->objects, object);
+ if (prev != NULL) {
+
+ /* The previous one is same, ignore */
+ if (gck_attribute_equal (prev, attr)) {
+ attribute_free (attr);
+ return;
+ }
+
+ /* Remove the previous one */
+ index_remove_attr (index, object, prev);
+ }
+
/* In this case values is a direct pointer to the object */
if (index->unique) {
g_return_if_fail (g_hash_table_lookup (index->values, attr) == NULL);
@@ -310,43 +328,6 @@
}
}
-static void
-index_remove (Index *index, gpointer object)
-{
- CK_ATTRIBUTE_PTR attr;
- GHashTable *objects;
-
- /*
- * We don't actually access the object. We want to be able to
- * handle objects that have been destroyed as well.
- */
-
- g_assert (object);
- g_assert (index);
-
- attr = g_hash_table_lookup (index->objects, object);
-
- /* Object not in this index */
- if (attr == NULL)
- return;
-
- if (index->unique) {
- if (!g_hash_table_remove (index->values, attr))
- g_assert_not_reached ();
- } else {
- objects = g_hash_table_lookup (index->values, attr);
- g_assert (objects);
- if (!g_hash_table_remove (objects, object))
- g_assert_not_reached ();
- if (g_hash_table_size (objects) == 0)
- if (!g_hash_table_remove (index->values, attr))
- g_assert_not_reached ();
- }
-
- if (!g_hash_table_remove (index->objects, object))
- g_assert_not_reached ();
-}
-
static gboolean
index_contains (Index *index, GckObject *object, CK_ATTRIBUTE_PTR attr)
{
@@ -377,6 +358,34 @@
}
static void
+notify_attribute (GckObject *object, CK_ATTRIBUTE_TYPE attr_type, GckManager *self)
+{
+ Index *index;
+
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_return_if_fail (GCK_IS_MANAGER (self));
+ g_return_if_fail (gck_object_get_manager (object) == self);
+
+ index = g_hash_table_lookup (self->pv->index_by_attribute, &attr_type);
+ if (index != NULL)
+ index_update (index, object);
+}
+
+static void
+notify_property (GckObject *object, GParamSpec *spec, GckManager *self)
+{
+ Index *index;
+
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_return_if_fail (GCK_IS_MANAGER (self));
+ g_return_if_fail (gck_object_get_manager (object) == self);
+
+ index = g_hash_table_lookup (self->pv->index_by_property, spec->name);
+ if (index != NULL)
+ index_update (index, object);
+}
+
+static void
add_object (GckManager *self, GckObject *object)
{
CK_OBJECT_HANDLE handle;
@@ -406,6 +415,8 @@
/* Now index the object properly */
g_hash_table_foreach (self->pv->index_by_attribute, index_object_each, object);
g_hash_table_foreach (self->pv->index_by_property, index_object_each, object);
+ g_signal_connect (object, "notify-attribute", G_CALLBACK (notify_attribute), self);
+ g_signal_connect (object, "notify", G_CALLBACK (notify_property), self);
}
static void
@@ -420,16 +431,17 @@
handle = gck_object_get_handle (object);
g_assert (handle);
- /* Release object management */
- self->pv->objects = g_list_remove (self->pv->objects, object);
- g_object_set (object, "manager", NULL, NULL);
-
/* Remove from all indexes */
+ g_signal_handlers_disconnect_by_func (object, G_CALLBACK (notify_attribute), self);
+ g_signal_handlers_disconnect_by_func (object, G_CALLBACK (notify_property), self);
g_hash_table_foreach (self->pv->index_by_attribute, index_remove_each, object);
g_hash_table_foreach (self->pv->index_by_property, index_remove_each, object);
+
+ /* Release object management */
+ self->pv->objects = g_list_remove (self->pv->objects, object);
+ g_object_set (object, "manager", NULL, NULL);
}
-
static void
find_each_object (gpointer unused, gpointer object, gpointer user_data)
{
Modified: trunk/pkcs11/gck/gck-manager.h
==============================================================================
--- trunk/pkcs11/gck/gck-manager.h (original)
+++ trunk/pkcs11/gck/gck-manager.h Sat Jan 3 19:30:08 2009
@@ -48,7 +48,9 @@
G_BEGIN_DECLS
-#include "gck-object.h"
+#include <glib-object.h>
+
+#include "gck-types.h"
#include "pkcs11/pkcs11.h"
Added: trunk/pkcs11/gck/gck-marshal.list
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-marshal.list Sat Jan 3 19:30:08 2009
@@ -0,0 +1 @@
+BOOLEAN:VOID
Added: trunk/pkcs11/gck/gck-memory-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-memory-store.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,261 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-object.h"
+#include "gck-memory-store.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+struct _GckMemoryStore {
+ GckStore parent;
+ GHashTable *entries;
+};
+
+typedef struct _Revert {
+ GHashTable *attributes;
+ CK_ATTRIBUTE_TYPE type;
+ CK_ATTRIBUTE_PTR attr;
+} Revert;
+
+G_DEFINE_TYPE (GckMemoryStore, gck_memory_store, GCK_TYPE_STORE);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+attribute_free (gpointer data)
+{
+ CK_ATTRIBUTE_PTR attr = data;
+ if (attr) {
+ g_free (attr->pValue);
+ g_slice_free (CK_ATTRIBUTE, attr);
+ }
+}
+
+static CK_ATTRIBUTE_PTR
+attribute_dup (CK_ATTRIBUTE_PTR attr)
+{
+ CK_ATTRIBUTE_PTR copy;
+ g_assert (attr);
+ copy = g_slice_new (CK_ATTRIBUTE);
+ copy->ulValueLen = attr->ulValueLen;
+ copy->pValue = g_memdup (attr->pValue, copy->ulValueLen);
+ copy->type = attr->type;
+ return copy;
+}
+
+static void
+object_gone (gpointer data, GObject *was_object)
+{
+ GckMemoryStore *self;
+
+ g_assert (GCK_IS_MEMORY_STORE (data));
+ self = GCK_MEMORY_STORE (data);
+
+ if (!g_hash_table_remove (self->entries, was_object))
+ g_return_if_reached ();
+}
+
+static gboolean
+remove_each_object (gpointer key, gpointer value, gpointer user_data)
+{
+ g_assert (GCK_IS_OBJECT (key));
+ g_assert (GCK_IS_MEMORY_STORE (user_data));
+
+ g_object_weak_unref (key, object_gone, user_data);
+ return TRUE;
+}
+
+static gboolean
+complete_set (GckTransaction *transaction, GckObject *object, Revert *revert)
+{
+ g_assert (GCK_IS_OBJECT (object));
+
+ if (gck_transaction_get_failed (transaction)) {
+ if (revert->attr)
+ g_hash_table_replace (revert->attributes, &(revert->attr->type), revert->attr);
+ else
+ g_hash_table_remove (revert->attributes, &(revert->type));
+
+ gck_object_notify_attribute (object, revert->type);
+
+ revert->attr = NULL;
+ revert->type = 0;
+ }
+
+ g_hash_table_unref (revert->attributes);
+ attribute_free (revert->attr);
+ g_slice_free (Revert, revert);
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static CK_RV
+gck_memory_store_real_read_value (GckStore *base, GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+ GckMemoryStore *self = GCK_MEMORY_STORE (base);
+ GHashTable *attributes;
+ CK_ATTRIBUTE_PTR at;
+
+ attributes = g_hash_table_lookup (self->entries, object);
+ if (attributes == NULL)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ at = g_hash_table_lookup (attributes, &(attr->type));
+ if (at == NULL)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ g_assert (at->type == attr->type);
+
+ /* Yes, we don't fill a buffer, just return pointer */
+ attr->pValue = at->pValue;
+ attr->ulValueLen = at->ulValueLen;
+
+ return CKR_OK;
+}
+
+static void
+gck_memory_store_real_write_value (GckStore *base, GckTransaction *transaction,
+ GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+ GckMemoryStore *self = GCK_MEMORY_STORE (base);
+ GHashTable *attributes;
+ CK_ATTRIBUTE_PTR at;
+ Revert *revert;
+
+ g_return_if_fail (!gck_transaction_get_failed (transaction));
+
+ attributes = g_hash_table_lookup (self->entries, object);
+ if (attributes == NULL) {
+ g_object_weak_ref (G_OBJECT (object), object_gone, self);
+ attributes = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal,
+ NULL, attribute_free);
+ g_hash_table_replace (self->entries, object, attributes);
+ }
+
+ /* No need to go any further if no change */
+ at = g_hash_table_lookup (attributes, &(attr->type));
+ if (at != NULL && gck_attribute_equal (at, attr))
+ return;
+
+ revert = g_new0 (Revert, 1);
+ revert->attributes = g_hash_table_ref (attributes);
+ revert->type = attr->type;
+ revert->attr = at;
+ g_hash_table_steal (attributes, &(attr->type));
+ gck_transaction_add (transaction, object, (GckTransactionFunc)complete_set, revert);
+
+ attr = attribute_dup (attr);
+ g_hash_table_replace (attributes, &(attr->type), attr);
+ gck_object_notify_attribute (object, attr->type);
+}
+
+static GObject*
+gck_memory_store_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+ GckMemoryStore *self = GCK_MEMORY_STORE (G_OBJECT_CLASS (gck_memory_store_parent_class)->constructor(type, n_props, props));
+ g_return_val_if_fail (self, NULL);
+
+ return G_OBJECT (self);
+}
+
+static void
+gck_memory_store_init (GckMemoryStore *self)
+{
+ self->entries = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)g_hash_table_unref);
+}
+
+static void
+gck_memory_store_dispose (GObject *obj)
+{
+ GckMemoryStore *self = GCK_MEMORY_STORE (obj);
+
+ g_hash_table_foreach_remove (self->entries, remove_each_object, self);
+
+ G_OBJECT_CLASS (gck_memory_store_parent_class)->dispose (obj);
+}
+
+static void
+gck_memory_store_finalize (GObject *obj)
+{
+ GckMemoryStore *self = GCK_MEMORY_STORE (obj);
+
+ g_assert (g_hash_table_size (self->entries) == 0);
+ g_hash_table_destroy (self->entries);
+ self->entries = NULL;
+
+ G_OBJECT_CLASS (gck_memory_store_parent_class)->finalize (obj);
+}
+
+static void
+gck_memory_store_set_property (GObject *obj, guint prop_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_memory_store_get_property (GObject *obj, guint prop_id, GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_memory_store_class_init (GckMemoryStoreClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GckStoreClass *store_class = GCK_STORE_CLASS (klass);
+
+ gobject_class->constructor = gck_memory_store_constructor;
+ gobject_class->dispose = gck_memory_store_dispose;
+ gobject_class->finalize = gck_memory_store_finalize;
+ gobject_class->set_property = gck_memory_store_set_property;
+ gobject_class->get_property = gck_memory_store_get_property;
+
+ store_class->read_value = gck_memory_store_real_read_value;
+ store_class->write_value = gck_memory_store_real_write_value;
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GckMemoryStore*
+gck_memory_store_new (void)
+{
+ return g_object_new (GCK_TYPE_MEMORY_STORE, NULL);
+}
Added: trunk/pkcs11/gck/gck-memory-store.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-memory-store.h Sat Jan 3 19:30:08 2009
@@ -0,0 +1,48 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCK_MEMORY_STORE_H__
+#define __GCK_MEMORY_STORE_H__
+
+#include <glib-object.h>
+
+#include "gck-store.h"
+#include "gck-types.h"
+
+#define GCK_TYPE_MEMORY_STORE (gck_memory_store_get_type ())
+#define GCK_MEMORY_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_MEMORY_STORE, GckMemoryStore))
+#define GCK_MEMORY_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_MEMORY_STORE, GckMemoryStoreClass))
+#define GCK_IS_MEMORY_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_MEMORY_STORE))
+#define GCK_IS_MEMORY_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_MEMORY_STORE))
+#define GCK_MEMORY_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_MEMORY_STORE, GckMemoryStoreClass))
+
+typedef struct _GckMemoryStore GckMemoryStore;
+typedef struct _GckMemoryStoreClass GckMemoryStoreClass;
+
+struct _GckMemoryStoreClass {
+ GckStoreClass parent_class;
+};
+
+GType gck_memory_store_get_type (void);
+
+GckMemoryStore* gck_memory_store_new (void);
+
+#endif /* __GCK_MEMORY_STORE_H__ */
Modified: trunk/pkcs11/gck/gck-module.c
==============================================================================
--- trunk/pkcs11/gck/gck-module.c (original)
+++ trunk/pkcs11/gck/gck-module.c Sat Jan 3 19:30:08 2009
@@ -23,12 +23,16 @@
#include "pkcs11/pkcs11.h"
+#include "gck-attributes.h"
+#include "gck-factory.h"
#include "gck-manager.h"
#include "gck-module.h"
+#include "gck-private-key.h"
+#include "gck-public-key.h"
#include "gck-session.h"
+#include "gck-transaction.h"
#include "gck-util.h"
-
enum {
PROP_0,
PROP_MANAGER,
@@ -41,6 +45,8 @@
GHashTable *virtual_slots_by_id; /* Various slot partitions by their ID */
GHashTable *sessions_by_handle; /* Mapping of handle to all open sessions */
gint handle_counter; /* Constantly incrementing counter for handles and the like */
+ GArray *factories; /* Various registered object factories */
+ gboolean factories_sorted; /* Whether we need to sort the object factories */
};
typedef struct _VirtualSlot {
@@ -120,6 +126,21 @@
* INTERNAL
*/
+static gint
+sort_factory_by_n_attrs (gconstpointer a, gconstpointer b)
+{
+ const GckFactoryInfo *fa = a;
+ const GckFactoryInfo *fb = b;
+
+ g_assert (a);
+ g_assert (b);
+
+ /* Note we're sorting in reverse order */
+ if (fa->n_attrs < fb->n_attrs)
+ return 1;
+ return (fa->n_attrs == fb->n_attrs) ? 0 : -1;
+}
+
static void
extend_space_string (CK_UTF8CHAR_PTR string, gsize length)
{
@@ -310,6 +331,20 @@
return CKR_OK;
}
+static void
+gck_module_real_store_token_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+ /* Derived classes should do something interesting */
+ gck_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
+}
+
+static void
+gck_module_real_remove_token_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+ /* Derived classes should do something interesting */
+ gck_transaction_fail (transaction, CKR_FUNCTION_NOT_SUPPORTED);
+}
+
static CK_RV
gck_module_real_login_user (GckModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
{
@@ -366,8 +401,13 @@
gck_util_ulong_free, g_object_unref);
self->pv->virtual_slots_by_id = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal,
gck_util_ulong_free, virtual_slot_free);
+ self->pv->factories = g_array_new (FALSE, TRUE, sizeof (GckFactoryInfo));
g_atomic_int_set (&(self->pv->handle_counter), 1);
+
+ /* Register session object factories */
+ gck_module_register_factory (self, GCK_FACTORY_PRIVATE_KEY);
+ gck_module_register_factory (self, GCK_FACTORY_PUBLIC_KEY);
}
static void
@@ -381,6 +421,8 @@
g_hash_table_remove_all (self->pv->virtual_slots_by_id);
g_hash_table_remove_all (self->pv->sessions_by_handle);
+
+ g_array_set_size (self->pv->factories, 0);
G_OBJECT_CLASS (gck_module_parent_class)->dispose (obj);
}
@@ -399,6 +441,9 @@
g_assert (g_hash_table_size (self->pv->sessions_by_handle) == 0);
g_hash_table_destroy (self->pv->sessions_by_handle);
self->pv->sessions_by_handle = NULL;
+
+ g_array_free (self->pv->factories, TRUE);
+ self->pv->factories = NULL;
G_OBJECT_CLASS (gck_module_parent_class)->finalize (obj);
}
@@ -463,6 +508,8 @@
klass->parse_argument = gck_module_real_parse_argument;
klass->refresh_token = gck_module_real_refresh_token;
+ klass->store_token_object = gck_module_real_store_token_object;
+ klass->remove_token_object = gck_module_real_remove_token_object;
klass->login_user = gck_module_real_login_user;
klass->logout_user = gck_module_real_logout_user;
@@ -477,13 +524,6 @@
g_object_class_install_property (gobject_class, PROP_INITIALIZE_ARGS,
g_param_spec_pointer ("initialize-args", "Initialize Args", "Arguments passed to C_Initialize",
G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
-
-#if 0
- signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_MODULE,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckModuleClass, signal),
- NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 0);
-#endif
}
/* -----------------------------------------------------------------------------
@@ -553,6 +593,70 @@
return GCK_MODULE_GET_CLASS (self)->refresh_token (self);
}
+void
+gck_module_store_token_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+ g_return_if_fail (GCK_IS_MODULE (self));
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_assert (GCK_MODULE_GET_CLASS (self)->store_token_object);
+ GCK_MODULE_GET_CLASS (self)->store_token_object (self, transaction, object);
+}
+
+void
+gck_module_remove_token_object (GckModule *self, GckTransaction *transaction, GckObject *object)
+{
+ g_return_if_fail (GCK_IS_MODULE (self));
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_assert (GCK_MODULE_GET_CLASS (self)->remove_token_object);
+ GCK_MODULE_GET_CLASS (self)->remove_token_object (self, transaction, object);
+}
+
+void
+gck_module_register_factory (GckModule *self, GckFactoryInfo *factory)
+{
+ g_return_if_fail (GCK_IS_MODULE (self));
+ g_return_if_fail (factory);
+ g_return_if_fail (factory->attrs || !factory->n_attrs);
+ g_return_if_fail (factory->factory);
+
+ g_array_append_val (self->pv->factories, *factory);
+ self->pv->factories_sorted = FALSE;
+}
+
+GckFactory
+gck_module_find_factory (GckModule *self, CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs)
+{
+ GckFactoryInfo *factory;
+ gboolean matched;
+ gulong j;
+ gsize i;
+
+ g_return_val_if_fail (GCK_IS_MODULE (self), NULL);
+ g_return_val_if_fail (attrs || !n_attrs, NULL);
+
+ if (!self->pv->factories_sorted) {
+ g_array_sort (self->pv->factories, sort_factory_by_n_attrs);
+ self->pv->factories_sorted = TRUE;
+ }
+
+ for (i = 0; i < self->pv->factories->len; ++i) {
+ factory = &(g_array_index (self->pv->factories, GckFactoryInfo, i));
+
+ matched = TRUE;
+ for (j = 0; j < factory->n_attrs; ++j) {
+ if (!gck_attributes_contains (attrs, n_attrs, &factory->attrs[j])) {
+ matched = FALSE;
+ break;
+ }
+ }
+
+ if (matched)
+ return factory->factory;
+ }
+
+ return NULL;
+}
+
/* -----------------------------------------------------------------------------
* PKCS#11
*/
Modified: trunk/pkcs11/gck/gck-module.h
==============================================================================
--- trunk/pkcs11/gck/gck-module.h (original)
+++ trunk/pkcs11/gck/gck-module.h Sat Jan 3 19:30:08 2009
@@ -26,9 +26,8 @@
#include "pkcs11/pkcs11.h"
-#include "gck-manager.h"
-
-typedef struct _GckSession GckSession;
+#include "gck-factory.h"
+#include "gck-types.h"
#define GCK_TYPE_MODULE (gck_module_get_type ())
#define GCK_MODULE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_MODULE, GckModule))
@@ -37,7 +36,6 @@
#define GCK_IS_MODULE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_MODULE))
#define GCK_MODULE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_MODULE, GckModuleClass))
-typedef struct _GckModule GckModule;
typedef struct _GckModuleClass GckModuleClass;
typedef struct _GckModulePrivate GckModulePrivate;
@@ -63,6 +61,10 @@
CK_RV (*refresh_token) (GckModule *self);
+ void (*store_token_object) (GckModule *self, GckTransaction *transaction, GckObject *object);
+
+ void (*remove_token_object) (GckModule *self, GckTransaction *transaction, GckObject *object);
+
CK_RV (*login_user) (GckModule *self, CK_SLOT_ID slot_id,
CK_UTF8CHAR_PTR pin, CK_ULONG n_pin);
@@ -111,7 +113,20 @@
CK_RV gck_module_refresh_token (GckModule *self);
+void gck_module_store_token_object (GckModule *self,
+ GckTransaction *transaction,
+ GckObject *object);
+
+void gck_module_remove_token_object (GckModule *self,
+ GckTransaction *transaction,
+ GckObject *object);
+
+GckFactory gck_module_find_factory (GckModule *self,
+ CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs);
+void gck_module_register_factory (GckModule *self,
+ GckFactoryInfo *factory);
CK_RV gck_module_C_GetInfo (GckModule *self,
CK_INFO_PTR info);
Modified: trunk/pkcs11/gck/gck-object.c
==============================================================================
--- trunk/pkcs11/gck/gck-object.c (original)
+++ trunk/pkcs11/gck/gck-object.c Sat Jan 3 19:30:08 2009
@@ -23,19 +23,31 @@
#include "pkcs11/pkcs11.h"
+#include "gck-attributes.h"
#include "gck-manager.h"
#include "gck-object.h"
+#include "gck-transaction.h"
+#include "gck-store.h"
#include "gck-util.h"
enum {
PROP_0,
PROP_HANDLE,
- PROP_MANAGER
+ PROP_MANAGER,
+ PROP_STORE
};
+enum {
+ NOTIFY_ATTRIBUTE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
struct _GckObjectPrivate {
CK_OBJECT_HANDLE handle;
GckManager *manager;
+ GckStore *store;
};
G_DEFINE_TYPE (GckObject, gck_object, G_TYPE_OBJECT);
@@ -51,44 +63,64 @@
static CK_RV
gck_object_real_get_attribute (GckObject *self, CK_ATTRIBUTE* attr)
{
+ CK_RV rv;
+
switch (attr->type)
{
case CKA_CLASS:
g_warning ("Derived class should have overridden CKA_CLASS");
return CKR_GENERAL_ERROR;
- case CKA_LABEL:
- g_warning ("Derived class should have overridden CKA_LABEL");
- return gck_util_set_data (attr, "", 0);
case CKA_MODIFIABLE:
+ return gck_attribute_set_bool (attr, self->pv->store ? TRUE : FALSE);
case CKA_PRIVATE:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_TOKEN:
- return gck_util_set_bool (attr, (self->pv->handle & GCK_OBJECT_IS_PERMANENT) ? TRUE : FALSE);
+ return gck_attribute_set_bool (attr, (self->pv->handle & GCK_OBJECT_IS_PERMANENT) ? TRUE : FALSE);
};
+
+ /* Give store a shot */
+ if (self->pv->store) {
+ rv = gck_store_get_attribute (self->pv->store, self, attr);
+ if (rv != CKR_ATTRIBUTE_TYPE_INVALID)
+ return rv;
+ }
+
+ /* Now some more defaults */
+ switch (attr->type) {
+ case CKA_LABEL:
+ return gck_attribute_set_data (attr, "", 0);
+ }
return CKR_ATTRIBUTE_TYPE_INVALID;
}
-#if 0
-static CK_RV
-gck_object_real_set_attribute (GckObject *self, const CK_ATTRIBUTE* attr)
+static void
+gck_object_real_set_attribute (GckObject *self, GckTransaction* transaction, CK_ATTRIBUTE* attr)
{
switch (attr->type) {
- case CKA_LABEL:
- g_warning ("Derived class should have overridden CKA_LABEL");
- return CKR_ATTRIBUTE_READ_ONLY;
case CKA_TOKEN:
case CKA_PRIVATE:
case CKA_MODIFIABLE:
- return CKR_ATTRIBUTE_READ_ONLY;
-
case CKA_CLASS:
- return CKR_ATTRIBUTE_READ_ONLY;
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
+ return;
};
-
- return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ /* Give store a shot */
+ if (self->pv->store) {
+ gck_store_set_attribute (self->pv->store, transaction, self, attr);
+ return;
+ }
+
+ /* Now some more defaults */
+ switch (attr->type) {
+ case CKA_LABEL:
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_READ_ONLY);
+ return;
+ }
+
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_TYPE_INVALID);
}
-#endif
static CK_RV
gck_object_real_unlock (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
@@ -152,6 +184,7 @@
{
GckObject *self = GCK_OBJECT (obj);
GckManager *manager;
+ GckStore *store;
switch (prop_id) {
case PROP_HANDLE:
@@ -171,6 +204,20 @@
g_object_notify (G_OBJECT (self), "manager");
break;
+ case PROP_STORE:
+ store = g_value_get_object (value);
+ if (self->pv->store) {
+ g_return_if_fail (!store);
+ g_object_remove_weak_pointer (G_OBJECT (self->pv->store),
+ (gpointer*)&(self->pv->store));
+ }
+ self->pv->store = store;
+ if (self->pv->store)
+ g_object_add_weak_pointer (G_OBJECT (self->pv->store),
+ (gpointer*)&(self->pv->store));
+
+ g_object_notify (G_OBJECT (self), "store");
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
@@ -190,6 +237,9 @@
case PROP_MANAGER:
g_value_set_object (value, gck_object_get_manager (self));
break;
+ case PROP_STORE:
+ g_value_set_object (value, self->pv->store);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
break;
@@ -212,9 +262,7 @@
klass->unlock = gck_object_real_unlock;
klass->get_attribute = gck_object_real_get_attribute;
-#if 0
klass->set_attribute = gck_object_real_set_attribute;
-#endif
g_object_class_install_property (gobject_class, PROP_HANDLE,
g_param_spec_ulong ("handle", "Handle", "Object handle",
@@ -224,12 +272,14 @@
g_param_spec_object ("manager", "Manager", "Object manager",
GCK_TYPE_MANAGER, G_PARAM_READWRITE));
-#if 0
- signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_OBJECT,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckObjectClass, signal),
- NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 0);
-#endif
+ g_object_class_install_property (gobject_class, PROP_STORE,
+ g_param_spec_object ("store", "Store", "Object store",
+ GCK_TYPE_STORE, G_PARAM_READWRITE));
+
+ signals[NOTIFY_ATTRIBUTE] = g_signal_new ("notify-attribute", GCK_TYPE_OBJECT,
+ G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckObjectClass, notify_attribute),
+ NULL, NULL, g_cclosure_marshal_VOID__ULONG,
+ G_TYPE_NONE, 1, G_TYPE_ULONG);
}
/* -----------------------------------------------------------------------------
@@ -245,6 +295,42 @@
return GCK_OBJECT_GET_CLASS (self)->get_attribute (self, attr);
}
+void
+gck_object_set_attribute (GckObject *self, GckTransaction *transaction,
+ CK_ATTRIBUTE_PTR attr)
+{
+ CK_ATTRIBUTE check;
+ CK_RV rv;
+
+ 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 (attr);
+
+ g_assert (GCK_OBJECT_GET_CLASS (self)->set_attribute);
+
+ /* Check if this attribute exists */
+ check.type = attr->type;
+ check.pValue = 0;
+ check.ulValueLen = 0;
+ rv = gck_object_get_attribute (self, &check);
+ if (rv != CKR_OK && rv != CKR_ATTRIBUTE_SENSITIVE) {
+ gck_transaction_fail (transaction, rv);
+ return;
+ }
+
+ /* Check that the value will actually change */
+ if (rv == CKR_ATTRIBUTE_SENSITIVE || !gck_object_match (self, attr))
+ GCK_OBJECT_GET_CLASS (self)->set_attribute (self, transaction, attr);
+}
+
+void
+gck_object_notify_attribute (GckObject *self, CK_ATTRIBUTE_TYPE attr_type)
+{
+ g_return_if_fail (GCK_IS_OBJECT (self));
+ g_signal_emit (self, signals[NOTIFY_ATTRIBUTE], 0, attr_type);
+}
+
gboolean
gck_object_match (GckObject *self, CK_ATTRIBUTE_PTR match)
{
Modified: trunk/pkcs11/gck/gck-object.h
==============================================================================
--- trunk/pkcs11/gck/gck-object.h (original)
+++ trunk/pkcs11/gck/gck-object.h Sat Jan 3 19:30:08 2009
@@ -26,6 +26,8 @@
#include "pkcs11/pkcs11.h"
+#include "gck-types.h"
+
#define GCK_OBJECT_HANDLE_MASK 0x0FFFFFFF
#define GCK_OBJECT_IS_PERMANENT 0x10000000
#define GCK_OBJECT_IS_TEMPORARY 0x00000000
@@ -37,12 +39,9 @@
#define GCK_IS_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_OBJECT))
#define GCK_OBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_OBJECT, GckObjectClass))
-typedef struct _GckObject GckObject;
typedef struct _GckObjectClass GckObjectClass;
typedef struct _GckObjectPrivate GckObjectPrivate;
-typedef struct _GckManager GckManager;
-
struct _GckObject {
GObject parent;
GckObjectPrivate *pv;
@@ -51,12 +50,15 @@
struct _GckObjectClass {
GObjectClass parent_class;
- /* properties --------------------------------------------------------------- */
+ /* signals ------------------------------------------------------------------ */
+ void (*notify_attribute) (GckObject *object, CK_ATTRIBUTE_TYPE attr_type);
/* virtual methods --------------------------------------------------------- */
- CK_RV (*get_attribute) (GckObject *object, CK_ATTRIBUTE* attr);
+ CK_RV (*get_attribute) (GckObject *object, CK_ATTRIBUTE *attr);
+
+ void (*set_attribute) (GckObject *object, GckTransaction *transaction, CK_ATTRIBUTE *attr);
CK_RV (*unlock) (GckObject *self, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin);
};
@@ -84,9 +86,13 @@
CK_RV gck_object_get_attribute (GckObject *self,
CK_ATTRIBUTE_PTR attr);
-void gck_object_cache_attribute (GckObject *self,
+void gck_object_set_attribute (GckObject *self,
+ GckTransaction *transaction,
CK_ATTRIBUTE_PTR attr);
+void gck_object_notify_attribute (GckObject *self,
+ CK_ATTRIBUTE_TYPE attr_type);
+
gboolean gck_object_get_attribute_boolean (GckObject *self,
CK_ATTRIBUTE_TYPE type,
gboolean *value);
Modified: trunk/pkcs11/gck/gck-private-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-private-key.c (original)
+++ trunk/pkcs11/gck/gck-private-key.c Sat Jan 3 19:30:08 2009
@@ -23,15 +23,12 @@
#include "pkcs11/pkcs11.h"
+#include "gck-attributes.h"
+#include "gck-factory.h"
#include "gck-private-key.h"
+#include "gck-transaction.h"
#include "gck-util.h"
-#if 0
-enum {
- PROP_0
-};
-#endif
-
struct _GckPrivateKeyPrivate {
guint sexp_uses;
GckSexp *sexp;
@@ -43,6 +40,108 @@
* INTERNAL
*/
+
+static CK_RV
+create_rsa_private (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+ gcry_error_t gcry;
+ gcry_mpi_t n = NULL;
+ gcry_mpi_t e = NULL;
+ gcry_mpi_t d = NULL;
+ gcry_mpi_t p = NULL;
+ gcry_mpi_t q = NULL;
+ gcry_mpi_t u = NULL;
+ CK_RV ret;
+
+ if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_MODULUS, &n) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_PUBLIC_EXPONENT, &e) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIVATE_EXPONENT, &d) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME_1, &p) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME_2, &q)) {
+ ret = CKR_TEMPLATE_INCOMPLETE;
+ goto done;
+ }
+
+ /* Fix up the incoming key so gcrypt likes it */
+ if (gcry_mpi_cmp (p, q) > 0)
+ gcry_mpi_swap (p, q);
+
+ /* Compute U. */
+ u = gcry_mpi_snew (gcry_mpi_get_nbits (n));
+ gcry_mpi_invm (u, p, q);
+
+ gcry = gcry_sexp_build (skey, NULL,
+ "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))",
+ n, e, d, p, q, u);
+
+ if (gcry != 0) {
+ g_message ("couldn't create RSA key from passed attributes: %s", gcry_strerror (gcry));
+ ret = CKR_FUNCTION_FAILED;
+ goto done;
+ }
+
+ gck_attributes_consume (attrs, n_attrs, CKA_MODULUS, CKA_PUBLIC_EXPONENT,
+ CKA_PRIVATE_EXPONENT, CKA_PRIME_1, CKA_PRIME_2,
+ CKA_EXPONENT_1, CKA_EXPONENT_2, CKA_COEFFICIENT, -1);
+ ret = CKR_OK;
+
+done:
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ gcry_mpi_release (d);
+ gcry_mpi_release (p);
+ gcry_mpi_release (q);
+ gcry_mpi_release (u);
+ return ret;
+}
+
+static CK_RV
+create_dsa_private (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+ gcry_error_t gcry;
+ gcry_mpi_t p = NULL;
+ gcry_mpi_t q = NULL;
+ gcry_mpi_t g = NULL;
+ gcry_mpi_t y = NULL;
+ gcry_mpi_t value = NULL;
+ CK_RV ret;
+
+ if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &p) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_SUBPRIME, &q) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &g) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_VALUE, &value)) {
+ ret = CKR_TEMPLATE_INCOMPLETE;
+ goto done;
+ }
+
+ /* Calculate the public part from the private */
+ y = gcry_mpi_snew (gcry_mpi_get_nbits (value));
+ g_return_val_if_fail (y, CKR_GENERAL_ERROR);
+ gcry_mpi_powm (y, g, value, p);
+
+ gcry = gcry_sexp_build (skey, NULL,
+ "(private-key (dsa (p %m) (q %m) (g %m) (y %m) (x %m)))",
+ p, q, g, y, value);
+
+ if (gcry != 0) {
+ g_message ("couldn't create DSA key from passed attributes: %s", gcry_strerror (gcry));
+ ret = CKR_FUNCTION_FAILED;
+ goto done;
+ }
+
+ gck_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_SUBPRIME,
+ CKA_BASE, CKA_VALUE, -1);
+ ret = CKR_OK;
+
+done:
+ gcry_mpi_release (p);
+ gcry_mpi_release (q);
+ gcry_mpi_release (g);
+ gcry_mpi_release (y);
+ gcry_mpi_release (value);
+ return ret;
+}
+
/* -----------------------------------------------------------------------------
* PRIVATE_KEY
*/
@@ -54,43 +153,43 @@
switch (attr->type) {
case CKA_CLASS:
- return gck_util_set_ulong (attr, CKO_PRIVATE_KEY);
+ return gck_attribute_set_ulong (attr, CKO_PRIVATE_KEY);
case CKA_PRIVATE:
- return gck_util_set_bool (attr, TRUE);
+ return gck_attribute_set_bool (attr, TRUE);
case CKA_SENSITIVE:
- return gck_util_set_bool (attr, TRUE);
+ return gck_attribute_set_bool (attr, TRUE);
case CKA_DECRYPT:
- return gck_util_set_bool (attr, gck_key_get_algorithm (GCK_KEY (self)) == GCRY_PK_RSA);
+ return gck_attribute_set_bool (attr, gck_key_get_algorithm (GCK_KEY (self)) == GCRY_PK_RSA);
case CKA_SIGN:
- return gck_util_set_bool (attr, TRUE);
+ return gck_attribute_set_bool (attr, TRUE);
case CKA_SIGN_RECOVER:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_UNWRAP:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_EXTRACTABLE:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_ALWAYS_SENSITIVE:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_NEVER_EXTRACTABLE:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_WRAP_WITH_TRUSTED:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_UNWRAP_TEMPLATE:
return CKR_ATTRIBUTE_TYPE_INVALID;
case CKA_ALWAYS_AUTHENTICATE:
- return gck_util_set_bool (attr, self->pv->sexp_uses <= 1);
+ return gck_attribute_set_bool (attr, self->pv->sexp_uses <= 1);
case CKA_MODULUS:
return gck_key_set_key_part (GCK_KEY (self), GCRY_PK_RSA, "n", attr);
@@ -124,26 +223,6 @@
return GCK_OBJECT_CLASS (gck_private_key_parent_class)->get_attribute (base, attr);
}
-#if 0
-static CK_RV
-gck_private_key_real_set_attribute (GckPrivateKey *private_key, const CK_ATTRIBUTE* attr)
-{
- switch (attr->type) {
- /* TODO: CKA_LABEL */
-
- case CKA_TOKEN:
- case CKA_PRIVATE:
- case CKA_MODIFIABLE:
- return CKR_ATTRIBUTE_READ_ONLY;
-
- case CKA_CLASS:
- return CKR_ATTRIBUTE_READ_ONLY;
- };
-
-xxx
-}
-#endif
-
static GckSexp*
gck_private_key_real_acquire_crypto_sexp (GckKey *base)
{
@@ -212,10 +291,6 @@
gck_private_key_set_property (GObject *obj, guint prop_id, const GValue *value,
GParamSpec *pspec)
{
-#if 0
- GckPrivateKey *self = GCK_PRIVATE_KEY (obj);
-#endif
-
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -227,10 +302,6 @@
gck_private_key_get_property (GObject *obj, guint prop_id, GValue *value,
GParamSpec *pspec)
{
-#if 0
- GckPrivateKey *self = GCK_PRIVATE_KEY (obj);
-#endif
-
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -255,21 +326,8 @@
gobject_class->get_property = gck_private_key_get_property;
gck_class->get_attribute = gck_private_key_real_get_attribute;
-#if 0
- gck_class->set_attribute = gck_private_key_real_set_attribute;
-#endif
-
+
key_class->acquire_crypto_sexp = gck_private_key_real_acquire_crypto_sexp;
-
-#if 0
- g_private_key_class_install_property (gprivate_key_class, PROP_PRIVATE_KEY,
- g_param_spec_pointer ("private_key", "PrivateKey", "PrivateKey.", G_PARAM_READWRITE));
-
- signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_PRIVATE_KEY,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckPrivateKeyClass, signal),
- NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 0);
-#endif
}
/* -----------------------------------------------------------------------------
@@ -289,3 +347,71 @@
self->pv->sexp = sexp;
self->pv->sexp_uses = num_uses;
}
+
+
+void
+gck_private_key_create (GckSession *session, GckTransaction *transaction,
+ CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+{
+ CK_KEY_TYPE type;
+ GckSexp *wrapper;
+ gcry_sexp_t sexp;
+ CK_RV ret;
+
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (attrs || !n_attrs);
+ g_return_if_fail (object);
+
+ *object = NULL;
+
+ if (!gck_attributes_find_ulong (attrs, n_attrs, CKA_KEY_TYPE, &type)) {
+ gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+ return;
+ }
+
+ gck_attributes_consume (attrs, n_attrs, CKA_KEY_TYPE, CKA_CLASS, -1);
+
+ switch (type) {
+ case CKK_RSA:
+ ret = create_rsa_private (attrs, n_attrs, &sexp);
+ break;
+ case CKK_DSA:
+ ret = create_dsa_private (attrs, n_attrs, &sexp);
+ break;
+ default:
+ ret = CKR_ATTRIBUTE_VALUE_INVALID;
+ break;
+ };
+
+
+ if (ret != CKR_OK) {
+ gck_transaction_fail (transaction, ret);
+ return;
+ }
+
+ g_return_if_fail (sexp);
+ wrapper = gck_sexp_new (sexp);
+ *object = g_object_new (GCK_TYPE_PRIVATE_KEY, "base-sexp", wrapper, NULL);
+ gck_private_key_store_private (GCK_PRIVATE_KEY (*object), wrapper, G_MAXUINT);
+ gck_sexp_unref (wrapper);
+}
+
+GckFactoryInfo*
+gck_private_key_get_factory (void)
+{
+ static CK_OBJECT_CLASS klass = CKO_PRIVATE_KEY;
+ static CK_BBOOL token = CK_FALSE;
+
+ static CK_ATTRIBUTE attributes[] = {
+ { CKA_CLASS, &klass, sizeof (klass) },
+ { CKA_TOKEN, &token, sizeof (token) },
+ };
+
+ static GckFactoryInfo factory = {
+ attributes,
+ G_N_ELEMENTS (attributes),
+ gck_private_key_create
+ };
+
+ return &factory;
+}
Modified: trunk/pkcs11/gck/gck-private-key.h
==============================================================================
--- trunk/pkcs11/gck/gck-private-key.h (original)
+++ trunk/pkcs11/gck/gck-private-key.h Sat Jan 3 19:30:08 2009
@@ -25,7 +25,9 @@
#include <glib-object.h>
#include "gck-key.h"
-#include "gck-sexp.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_PRIVATE_KEY (gck_private_key_get_factory ())
#define GCK_TYPE_PRIVATE_KEY (gck_private_key_get_type ())
#define GCK_PRIVATE_KEY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_PRIVATE_KEY, GckPrivateKey))
@@ -34,7 +36,6 @@
#define GCK_IS_PRIVATE_KEY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_PRIVATE_KEY))
#define GCK_PRIVATE_KEY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_PRIVATE_KEY, GckPrivateKeyClass))
-typedef struct _GckPrivateKey GckPrivateKey;
typedef struct _GckPrivateKeyClass GckPrivateKeyClass;
typedef struct _GckPrivateKeyPrivate GckPrivateKeyPrivate;
@@ -49,10 +50,16 @@
GType gck_private_key_get_type (void);
-GckPrivateKey* gck_private_key_new (void);
-
void gck_private_key_store_private (GckPrivateKey *self,
GckSexp *sexp,
guint num_uses);
+GckFactoryInfo* gck_private_key_get_factory (void);
+
+void gck_private_key_create (GckSession *session,
+ GckTransaction *transaction,
+ CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ GckObject **object);
+
#endif /* __GCK_PRIVATE_KEY_H__ */
Modified: trunk/pkcs11/gck/gck-public-key.c
==============================================================================
--- trunk/pkcs11/gck/gck-public-key.c (original)
+++ trunk/pkcs11/gck/gck-public-key.c Sat Jan 3 19:30:08 2009
@@ -23,20 +23,13 @@
#include "pkcs11/pkcs11.h"
+#include "gck-attributes.h"
#include "gck-crypto.h"
+#include "gck-factory.h"
#include "gck-public-key.h"
+#include "gck-transaction.h"
#include "gck-util.h"
-#if 0
-enum {
- PROP_0,
- PROP_PUBLIC_KEY
-};
-
-struct _GckPublicKeyPrivate {
-};
-#endif
-
G_DEFINE_TYPE (GckPublicKey, gck_public_key, GCK_TYPE_KEY);
/* -----------------------------------------------------------------------------
@@ -65,12 +58,85 @@
g_return_val_if_reached (CKR_GENERAL_ERROR);
gcry_sexp_release (numbers);
- rv = gck_util_set_ulong (attr, gcry_mpi_get_nbits (mpi));
+ rv = gck_attribute_set_ulong (attr, gcry_mpi_get_nbits (mpi));
gcry_mpi_release (mpi);
return rv;
}
+static CK_RV
+create_rsa_public (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+ gcry_error_t gcry;
+ gcry_mpi_t n = NULL;
+ gcry_mpi_t e = NULL;
+ CK_RV ret;
+
+ if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_MODULUS, &n) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_PUBLIC_EXPONENT, &e)) {
+ ret = CKR_TEMPLATE_INCOMPLETE;
+ goto done;
+ }
+
+ gcry = gcry_sexp_build (skey, NULL,
+ "(public-key (rsa (n %m) (e %m)))",
+ n, e);
+
+ if (gcry != 0) {
+ g_message ("couldn't create RSA key from passed attributes: %s", gcry_strerror (gcry));
+ ret = CKR_FUNCTION_FAILED;
+ goto done;
+ }
+
+ gck_attributes_consume (attrs, n_attrs, CKA_MODULUS, CKA_PUBLIC_EXPONENT, CKA_MODULUS_BITS, -1);
+ ret = CKR_OK;
+
+done:
+ gcry_mpi_release (n);
+ gcry_mpi_release (e);
+ return ret;
+}
+
+static CK_RV
+create_dsa_public (CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, gcry_sexp_t *skey)
+{
+ gcry_error_t gcry;
+ gcry_mpi_t p = NULL;
+ gcry_mpi_t q = NULL;
+ gcry_mpi_t g = NULL;
+ gcry_mpi_t y = NULL;
+ CK_RV ret;
+
+ if (!gck_attributes_find_mpi (attrs, n_attrs, CKA_PRIME, &p) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_SUBPRIME, &q) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_BASE, &g) ||
+ !gck_attributes_find_mpi (attrs, n_attrs, CKA_VALUE, &y)) {
+ ret = CKR_TEMPLATE_INCOMPLETE;
+ goto done;
+ }
+
+ gcry = gcry_sexp_build (skey, NULL,
+ "(public-key (dsa (p %m) (q %m) (g %m) (y %m)))",
+ p, q, g, y);
+
+ if (gcry != 0) {
+ g_message ("couldn't create DSA key from passed attributes: %s", gcry_strerror (gcry));
+ ret = CKR_FUNCTION_FAILED;
+ goto done;
+ }
+
+ gck_attributes_consume (attrs, n_attrs, CKA_PRIME, CKA_SUBPRIME,
+ CKA_BASE, CKA_VALUE, -1);
+ ret = CKR_OK;
+
+done:
+ gcry_mpi_release (p);
+ gcry_mpi_release (q);
+ gcry_mpi_release (g);
+ gcry_mpi_release (y);
+ return ret;
+}
+
/* -----------------------------------------------------------------------------
* PUBLIC_KEY
*/
@@ -84,22 +150,22 @@
{
case CKA_CLASS:
- return gck_util_set_ulong (attr, CKO_PUBLIC_KEY);
+ return gck_attribute_set_ulong (attr, CKO_PUBLIC_KEY);
case CKA_ENCRYPT:
- return gck_util_set_bool (attr, gck_key_get_algorithm (GCK_KEY (self)) == GCRY_PK_RSA);
+ return gck_attribute_set_bool (attr, gck_key_get_algorithm (GCK_KEY (self)) == GCRY_PK_RSA);
case CKA_VERIFY:
- return gck_util_set_bool (attr, TRUE);
+ return gck_attribute_set_bool (attr, TRUE);
case CKA_VERIFY_RECOVER:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_WRAP:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_TRUSTED:
- return gck_util_set_bool (attr, FALSE);
+ return gck_attribute_set_bool (attr, FALSE);
case CKA_WRAP_TEMPLATE:
return CKR_ATTRIBUTE_TYPE_INVALID;
@@ -130,26 +196,6 @@
return GCK_OBJECT_CLASS (gck_public_key_parent_class)->get_attribute (base, attr);
}
-#if 0
-static CK_RV
-gck_public_key_real_set_attribute (GckPublicKey *public_key, const CK_ATTRIBUTE* attr)
-{
- switch (attr->type) {
- /* TODO: CKA_LABEL */
-
- case CKA_TOKEN:
- case CKA_PRIVATE:
- case CKA_MODIFIABLE:
- return CKR_ATTRIBUTE_READ_ONLY;
-
- case CKA_CLASS:
- return CKR_ATTRIBUTE_READ_ONLY;
- };
-
- return CKA_ATTRIBUTE_TYPE_INVALID;
-}
-#endif
-
static GckSexp*
gck_public_key_acquire_crypto_sexp (GckKey *self)
{
@@ -174,26 +220,18 @@
static void
gck_public_key_init (GckPublicKey *self)
{
-#if 0
- self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_PUBLIC_KEY, GckPublicKeyPrivate);
-#endif
+
}
static void
gck_public_key_dispose (GObject *obj)
{
-#if 0
- GckPublicKey *self = GCK_PUBLIC_KEY (obj);
-#endif
G_OBJECT_CLASS (gck_public_key_parent_class)->dispose (obj);
}
static void
gck_public_key_finalize (GObject *obj)
{
-#if 0
- GckPublicKey *self = GCK_PUBLIC_KEY (obj);
-#endif
G_OBJECT_CLASS (gck_public_key_parent_class)->finalize (obj);
}
@@ -201,10 +239,6 @@
gck_public_key_set_property (GObject *obj, guint prop_id, const GValue *value,
GParamSpec *pspec)
{
-#if 0
- GckPublicKey *self = GCK_PUBLIC_KEY (obj);
-#endif
-
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -216,10 +250,6 @@
gck_public_key_get_property (GObject *obj, guint prop_id, GValue *value,
GParamSpec *pspec)
{
-#if 0
- GckPublicKey *self = GCK_PUBLIC_KEY (obj);
-#endif
-
switch (prop_id) {
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
@@ -235,9 +265,6 @@
GckKeyClass *key_class = GCK_KEY_CLASS (klass);
gck_public_key_parent_class = g_type_class_peek_parent (klass);
-#if 0
- g_type_class_add_private (klass, sizeof (GckPublicKeyPrivate));
-#endif
gobject_class->constructor = gck_public_key_constructor;
gobject_class->dispose = gck_public_key_dispose;
@@ -246,23 +273,75 @@
gobject_class->get_property = gck_public_key_get_property;
gck_class->get_attribute = gck_public_key_real_get_attribute;
-#if 0
- gck_class->set_attribute = gck_public_key_real_set_attribute;
-#endif
key_class->acquire_crypto_sexp = gck_public_key_acquire_crypto_sexp;
-
-#if 0
- g_public_key_class_install_property (gobject_class, PROP_PUBLIC_KEY,
- g_param_spec_pointer ("public_key", "PublicKey", "PublicKey.", G_PARAM_READWRITE));
-
- signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_PUBLIC_KEY,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckPublicKeyClass, signal),
- NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 0);
-#endif
}
/* -----------------------------------------------------------------------------
* PUBLIC
*/
+
+void
+gck_public_key_create (GckSession *session, GckTransaction *transaction,
+ CK_ATTRIBUTE_PTR attrs, CK_ULONG n_attrs, GckObject **object)
+{
+ CK_KEY_TYPE type;
+ GckSexp *wrapper;
+ gcry_sexp_t sexp;
+ CK_RV ret;
+
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (attrs || !n_attrs);
+ g_return_if_fail (object);
+
+ *object = NULL;
+
+ if (!gck_attributes_find_ulong (attrs, n_attrs, CKA_KEY_TYPE, &type)) {
+ gck_transaction_fail (transaction, CKR_TEMPLATE_INCOMPLETE);
+ return;
+ }
+
+ gck_attributes_consume (attrs, n_attrs, CKA_KEY_TYPE, CKA_CLASS, -1);
+
+ switch (type) {
+ case CKK_RSA:
+ ret = create_rsa_public (attrs, n_attrs, &sexp);
+ break;
+ case CKK_DSA:
+ ret = create_dsa_public (attrs, n_attrs, &sexp);
+ break;
+ default:
+ ret = CKR_ATTRIBUTE_VALUE_INVALID;
+ break;
+ };
+
+ if (ret != CKR_OK) {
+ gck_transaction_fail (transaction, ret);
+ return;
+ }
+
+ g_return_if_fail (sexp);
+ wrapper = gck_sexp_new (sexp);
+ *object = g_object_new (GCK_TYPE_PUBLIC_KEY, "base-sexp", wrapper, NULL);
+ gck_sexp_unref (wrapper);
+}
+
+GckFactoryInfo*
+gck_public_key_get_factory (void)
+{
+ static CK_OBJECT_CLASS klass = CKO_PUBLIC_KEY;
+ static CK_BBOOL token = CK_FALSE;
+
+ static CK_ATTRIBUTE attributes[] = {
+ { CKA_CLASS, &klass, sizeof (klass) },
+ { CKA_TOKEN, &token, sizeof (token) },
+ };
+
+ static GckFactoryInfo factory = {
+ attributes,
+ G_N_ELEMENTS (attributes),
+ gck_public_key_create
+ };
+
+ return &factory;
+}
Modified: trunk/pkcs11/gck/gck-public-key.h
==============================================================================
--- trunk/pkcs11/gck/gck-public-key.h (original)
+++ trunk/pkcs11/gck/gck-public-key.h Sat Jan 3 19:30:08 2009
@@ -25,6 +25,9 @@
#include <glib-object.h>
#include "gck-key.h"
+#include "gck-types.h"
+
+#define GCK_FACTORY_PUBLIC_KEY (gck_public_key_get_factory ())
#define GCK_TYPE_PUBLIC_KEY (gck_public_key_get_type ())
#define GCK_PUBLIC_KEY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_PUBLIC_KEY, GckPublicKey))
@@ -33,7 +36,6 @@
#define GCK_IS_PUBLIC_KEY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_PUBLIC_KEY))
#define GCK_PUBLIC_KEY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_PUBLIC_KEY, GckPublicKeyClass))
-typedef struct _GckPublicKey GckPublicKey;
typedef struct _GckPublicKeyClass GckPublicKeyClass;
typedef struct _GckPublicKeyPrivate GckPublicKeyPrivate;
@@ -48,4 +50,11 @@
GType gck_public_key_get_type (void);
+GckFactoryInfo* gck_public_key_get_factory (void);
+
+void gck_public_key_create (GckSession *session,
+ GckTransaction *transaction,
+ CK_ATTRIBUTE_PTR attrs,
+ CK_ULONG n_attrs,
+ GckObject **object);
#endif /* __GCK_PUBLIC_KEY_H__ */
Modified: trunk/pkcs11/gck/gck-session.c
==============================================================================
--- trunk/pkcs11/gck/gck-session.c (original)
+++ trunk/pkcs11/gck/gck-session.c Sat Jan 3 19:30:08 2009
@@ -23,11 +23,15 @@
#include "pkcs11/pkcs11.h"
+#include "gck-attributes.h"
#include "gck-crypto.h"
#include "gck-key.h"
+#include "gck-factory.h"
#include "gck-manager.h"
+#include "gck-memory-store.h"
#include "gck-session.h"
#include "gck-sexp.h"
+#include "gck-transaction.h"
enum {
PROP_0,
@@ -39,16 +43,6 @@
PROP_LOGGED_IN
};
-#if 0
-enum {
- SIGNAL,
- LAST_SIGNAL
-};
-
-static guint signals[LAST_SIGNAL] = { 0 };
-#endif
-
-
struct _GckSessionPrivate {
CK_SESSION_HANDLE handle;
@@ -56,12 +50,16 @@
GckModule *module;
GckManager *manager;
+ GckStore *store;
gboolean logged_in;
gboolean read_only;
CK_NOTIFY notify_callback;
CK_VOID_PTR application_ptr;
+
+ /* Objects owned by this session */
+ GHashTable *objects;
/* Used for context specific logins */
void (*current_operation) (GckSession *self);
@@ -78,6 +76,9 @@
G_DEFINE_TYPE (GckSession, gck_session, G_TYPE_OBJECT);
+static void add_object (GckSession *self, GckTransaction *transaction, GckObject *object);
+static void remove_object (GckSession *self, GckTransaction *transaction, GckObject *object);
+
/* -----------------------------------------------------------------------------
* INTERNAL
*/
@@ -115,9 +116,12 @@
CK_RV rv;
g_assert (GCK_IS_SESSION (self));
-
- if (self->pv->current_operation)
- return CKR_OPERATION_ACTIVE;
+
+ /* Cancel any current operation */
+ if (self->pv->current_operation) {
+ (self->pv->current_operation) (self);
+ g_assert (!self->pv->current_operation);
+ }
g_assert (!self->pv->crypto_sexp);
@@ -259,11 +263,13 @@
* If we're going to write to this object check that we're in a
* writable session and object is modifiable.
*/
- if (writable && !is_token) {
- if (gck_module_get_write_protected (self->pv->module))
- return CKR_TOKEN_WRITE_PROTECTED;
- if (self->pv->read_only && !is_token)
- return CKR_SESSION_READ_ONLY;
+ if (writable) {
+ if (is_token) {
+ if (gck_module_get_write_protected (self->pv->module))
+ return CKR_TOKEN_WRITE_PROTECTED;
+ if (self->pv->read_only)
+ return CKR_SESSION_READ_ONLY;
+ }
if (!gck_object_get_attribute_boolean (object, CKA_MODIFIABLE, &is_modifiable))
is_modifiable = FALSE;
if (!is_modifiable) /* What's a better return code in this case? */
@@ -274,6 +280,74 @@
return CKR_OK;
}
+
+static gboolean
+complete_remove (GckTransaction *transaction, GckSession *self, GckObject *object)
+{
+ if (gck_transaction_get_failed (transaction))
+ add_object (self, NULL, object);
+ g_object_unref (object);
+ return TRUE;
+}
+
+static void
+remove_object (GckSession *self, GckTransaction *transaction, GckObject *object)
+{
+ g_assert (GCK_IS_SESSION (self));
+ g_assert (GCK_IS_OBJECT (object));
+
+ g_object_ref (object);
+
+ gck_manager_unregister_object (self->pv->manager, object);
+ if (!g_hash_table_remove (self->pv->objects, object))
+ g_return_if_reached ();
+ g_object_set (object, "store", NULL, NULL);
+
+ if (transaction)
+ gck_transaction_add (transaction, self, (GckTransactionFunc)complete_remove,
+ g_object_ref (object));
+
+ g_object_unref (object);
+}
+
+static gboolean
+complete_add (GckTransaction *transaction, GckSession *self, GckObject *object)
+{
+ if (gck_transaction_get_failed (transaction))
+ remove_object (self, NULL, object);
+ g_object_unref (object);
+ return TRUE;
+}
+
+static void
+add_object (GckSession *self, GckTransaction *transaction, GckObject *object)
+{
+ g_assert (GCK_IS_SESSION (self));
+ g_assert (GCK_IS_OBJECT (object));
+
+ /* Must not already be associated with a session or manager */
+ g_return_if_fail (gck_object_get_manager (object) == NULL);
+ g_return_if_fail (g_object_get_data (G_OBJECT (object), "owned-by-session") == NULL);
+ g_return_if_fail (g_hash_table_lookup (self->pv->objects, object) == NULL);
+
+ g_hash_table_insert (self->pv->objects, object, g_object_ref (object));
+ g_object_set_data (G_OBJECT (object), "owned-by-session", self);
+ gck_manager_register_object (self->pv->manager, object);
+ g_object_set (object, "store", self->pv->store, NULL);
+
+ if (transaction)
+ gck_transaction_add (transaction, self, (GckTransactionFunc)complete_add,
+ 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)
@@ -304,9 +378,15 @@
gck_session_constructor (GType type, guint n_props, GObjectConstructParam *props)
{
GckSession *self = GCK_SESSION (G_OBJECT_CLASS (gck_session_parent_class)->constructor(type, n_props, props));
- g_return_val_if_fail (self, NULL);
+ CK_ATTRIBUTE attr;
+ g_return_val_if_fail (self, NULL);
+ /* Register store attributes */
+ attr.type = CKA_LABEL;
+ attr.pValue = "";
+ attr.ulValueLen = 0;
+ gck_store_register_schema (self->pv->store, &attr, NULL, 0);
return G_OBJECT (self);
}
@@ -315,7 +395,11 @@
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->read_only = TRUE;
+
+ /* Create the store and register attributes */
+ self->pv->store = GCK_STORE (gck_memory_store_new ());
}
static void
@@ -326,15 +410,18 @@
/* Cleanup any current operation */
if (self->pv->current_operation)
(self->pv->current_operation) (self);
+ g_assert (!self->pv->current_operation);
- g_return_if_fail (self->pv->module);
- g_object_unref (self->pv->module);
+ if (self->pv->module)
+ g_object_unref (self->pv->module);
self->pv->module = NULL;
- g_return_if_fail (self->pv->manager);
- g_object_unref (self->pv->manager);
+ if (self->pv->manager)
+ g_object_unref (self->pv->manager);
self->pv->manager = NULL;
+ g_hash_table_remove_all (self->pv->objects);
+
G_OBJECT_CLASS (gck_session_parent_class)->dispose (obj);
}
@@ -346,6 +433,12 @@
g_assert (self->pv->module == NULL);
g_assert (self->pv->manager == NULL);
+ g_hash_table_destroy (self->pv->objects);
+ self->pv->objects = NULL;
+
+ g_object_unref (self->pv->store);
+ self->pv->store = NULL;
+
G_OBJECT_CLASS (gck_session_parent_class)->finalize (obj);
}
@@ -455,13 +548,6 @@
g_object_class_install_property (gobject_class, PROP_LOGGED_IN,
g_param_spec_boolean ("logged-in", "Logged in", "Whether this session is logged in or not",
FALSE, G_PARAM_READWRITE));
-
-#if 0
- signals[SIGNAL] = g_signal_new ("signal", GCK_TYPE_SESSION,
- G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckSessionClass, signal),
- NULL, NULL, g_cclosure_marshal_VOID__OBJECT,
- G_TYPE_NONE, 0);
-#endif
}
/* -----------------------------------------------------------------------------
@@ -640,8 +726,90 @@
gck_session_C_CreateObject (GckSession* self, CK_ATTRIBUTE_PTR template,
CK_ULONG count, CK_OBJECT_HANDLE_PTR new_object)
{
- /* TODO: Need to implement this */
- return CKR_FUNCTION_NOT_SUPPORTED;
+ GckObject *object = NULL;
+ GckTransaction *transaction;
+ CK_ATTRIBUTE_PTR attrs;
+ CK_ULONG n_attrs, i;
+ GckFactory factory;
+ gboolean is_token;
+ gboolean is_private;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
+ if (!new_object)
+ return CKR_ARGUMENTS_BAD;
+ if (!(!count || template))
+ return CKR_ARGUMENTS_BAD;
+
+ /* Find out if we can create such an object */
+ factory = gck_module_find_factory (gck_session_get_module (self), template, count);
+ if (!factory)
+ return CKR_TEMPLATE_INCOMPLETE;
+
+ /* Find out where we'll be creating this */
+ if (!gck_attributes_find_boolean (template, count, CKA_TOKEN, &is_token))
+ is_token = CK_FALSE;
+
+ /* See if we can create due to read-only */
+ if (is_token) {
+ if (gck_module_get_write_protected (self->pv->module))
+ return CKR_TOKEN_WRITE_PROTECTED;
+ if (self->pv->read_only)
+ return CKR_SESSION_READ_ONLY;
+ }
+
+ /* The transaction for this whole dealio */
+ transaction = gck_transaction_new ();
+
+ /*
+ * Duplicate the memory for the attributes (but not values) so we
+ * can 'consume' in the factory function
+ */
+ attrs = g_memdup (template, count * sizeof (CK_ATTRIBUTE));
+ n_attrs = count;
+
+ /* Actually create the object */
+ object = NULL;
+ (factory) (self, transaction, attrs, n_attrs, &object);
+
+ if (!gck_transaction_get_failed (transaction)) {
+ g_return_val_if_fail (object, CKR_GENERAL_ERROR);
+
+ /* Can only create public objects unless logged in */
+ if (!gck_session_get_logged_in (self) &&
+ gck_object_get_attribute_boolean (object, CKA_PRIVATE, &is_private) &&
+ is_private == TRUE) {
+ gck_transaction_fail (transaction, CKR_USER_NOT_LOGGED_IN);
+ }
+ }
+
+ /* Find somewhere to store the object */
+ if (!gck_transaction_get_failed (transaction)) {
+ if (is_token)
+ gck_module_store_token_object (self->pv->module, transaction, object);
+ else
+ add_object (self, transaction, object);
+ }
+
+ /* Next go through and set all attributes that weren't used initially */
+ gck_attributes_consume (attrs, n_attrs, CKA_TOKEN, -1);
+ for (i = 0; i < n_attrs && !gck_transaction_get_failed (transaction); ++i) {
+ if (!gck_attribute_consumed (&attrs[i]))
+ gck_object_set_attribute (object, transaction, &attrs[i]);
+ }
+
+ gck_transaction_complete (transaction);
+ rv = gck_transaction_get_result (transaction);
+ g_object_unref (transaction);
+ if (rv == CKR_OK) {
+ g_assert (object);
+ *new_object = gck_object_get_handle (object);
+ }
+ if (object)
+ g_object_unref (object);
+ g_free (attrs);
+
+ return rv;
}
CK_RV
@@ -712,10 +880,39 @@
}
CK_RV
-gck_session_C_DestroyObject (GckSession* self, CK_OBJECT_HANDLE object)
+gck_session_C_DestroyObject (GckSession* self, CK_OBJECT_HANDLE handle)
{
- /* TODO: Need to implement this */
- return CKR_FUNCTION_NOT_SUPPORTED;
+ GckObject *object;
+ GckSession *session;
+ GckTransaction *transaction;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_SESSION (self), CKR_SESSION_HANDLE_INVALID);
+
+ rv = gck_session_lookup_writable_object (self, handle, &object);
+ if (rv != CKR_OK)
+ return rv;
+
+ transaction = gck_transaction_new ();
+
+ /* Lookup the actual session that owns this object, if no session, then a token object */
+ session = g_object_get_data (G_OBJECT (object), "owned-by-session");
+ if (session != NULL)
+ remove_object (session, transaction, object);
+ else
+ gck_module_remove_token_object (self->pv->module, transaction, object);
+
+ gck_transaction_complete (transaction);
+ rv = gck_transaction_get_result (transaction);
+ g_object_unref (transaction);
+
+ if (rv == CKR_OK) {
+ /* Check that it's really gone */
+ g_return_val_if_fail (gck_session_lookup_readable_object (self, handle, &object) ==
+ CKR_OBJECT_HANDLE_INVALID, CKR_GENERAL_ERROR);
+ }
+
+ return rv;
}
CK_RV
@@ -732,8 +929,11 @@
if (!(template || !count))
return CKR_ARGUMENTS_BAD;
- if (self->pv->current_operation)
- return CKR_OPERATION_ACTIVE;
+ /* Cancel any current operation */
+ if (self->pv->current_operation) {
+ (self->pv->current_operation) (self);
+ g_assert (!self->pv->current_operation);
+ }
/* See whether this is token or not */
all = !attributes_find_boolean (template, count, CKA_TOKEN, &token);
Modified: trunk/pkcs11/gck/gck-sexp.h
==============================================================================
--- trunk/pkcs11/gck/gck-sexp.h (original)
+++ trunk/pkcs11/gck/gck-sexp.h Sat Jan 3 19:30:08 2009
@@ -26,8 +26,7 @@
#include <glib-object.h>
-struct _GckSexp;
-typedef struct _GckSexp GckSexp;
+#include "gck-types.h"
GckSexp* gck_sexp_new (gcry_sexp_t sexp);
Added: trunk/pkcs11/gck/gck-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-store.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,328 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-attributes.h"
+#include "gck-object.h"
+#include "gck-store.h"
+#include "gck-transaction.h"
+#include "gck-util.h"
+
+typedef struct _Schema {
+ CK_ATTRIBUTE_TYPE type;
+ gpointer default_value;
+ gsize default_length;
+ GckStoreValidator validator;
+ guint flags;
+} Schema;
+
+struct _GckStorePrivate {
+ GHashTable *schemas;
+};
+
+G_DEFINE_TYPE (GckStore, gck_store, G_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static void
+schema_free (gpointer data)
+{
+ Schema *schema;
+
+ if (data == NULL)
+ return;
+
+ schema = data;
+ g_free (schema->default_value);
+ g_slice_free (Schema, schema);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static GObject*
+gck_store_constructor (GType type, guint n_props, GObjectConstructParam *props)
+{
+ GckStore *self = GCK_STORE (G_OBJECT_CLASS (gck_store_parent_class)->constructor(type, n_props, props));
+ g_return_val_if_fail (self, NULL);
+
+ return G_OBJECT (self);
+}
+
+static void
+gck_store_init (GckStore *self)
+{
+ self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCK_TYPE_STORE, GckStorePrivate);
+ self->pv->schemas = g_hash_table_new_full (gck_util_ulong_hash, gck_util_ulong_equal,
+ NULL, schema_free);
+}
+
+static void
+gck_store_dispose (GObject *obj)
+{
+ GckStore *self = GCK_STORE (obj);
+
+ g_hash_table_remove_all (self->pv->schemas);
+
+ G_OBJECT_CLASS (gck_store_parent_class)->dispose (obj);
+}
+
+static void
+gck_store_finalize (GObject *obj)
+{
+ GckStore *self = GCK_STORE (obj);
+
+ g_hash_table_destroy (self->pv->schemas);
+
+ G_OBJECT_CLASS (gck_store_parent_class)->finalize (obj);
+}
+
+static void
+gck_store_set_property (GObject *obj, guint prop_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_store_get_property (GObject *obj, guint prop_id, GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_store_class_init (GckStoreClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->constructor = gck_store_constructor;
+ gobject_class->dispose = gck_store_dispose;
+ gobject_class->finalize = gck_store_finalize;
+ gobject_class->set_property = gck_store_set_property;
+ gobject_class->get_property = gck_store_get_property;
+
+ g_type_class_add_private (klass, sizeof (GckStorePrivate));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+gconstpointer
+gck_store_read_value (GckStore *self, GckObject *object,
+ CK_ATTRIBUTE_TYPE type, gsize *n_value)
+{
+ CK_ATTRIBUTE at;
+ Schema *schema;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_STORE (self), NULL);
+ g_return_val_if_fail (GCK_IS_OBJECT (object), NULL);
+ g_return_val_if_fail (n_value, NULL);
+
+ g_assert (GCK_STORE_GET_CLASS (self)->read_value);
+
+ schema = g_hash_table_lookup (self->pv->schemas, &type);
+ if (schema == NULL)
+ return NULL;
+
+ at.type = type;
+ at.pValue = NULL;
+ at.ulValueLen = 0;
+
+ rv = GCK_STORE_GET_CLASS (self)->read_value (self, object, &at);
+ if (rv == CKR_ATTRIBUTE_TYPE_INVALID || rv == CKR_USER_NOT_LOGGED_IN) {
+ at.pValue = schema->default_value;
+ at.ulValueLen = schema->default_length;
+ } else if (rv != CKR_OK) {
+ g_return_val_if_reached (NULL);
+ }
+
+ *n_value = at.ulValueLen;
+ return at.pValue;
+}
+
+gchar*
+gck_store_read_string (GckStore *self, GckObject *object, CK_ATTRIBUTE_TYPE type)
+{
+ gconstpointer value;
+ gsize n_value;
+
+ g_return_val_if_fail (GCK_IS_STORE (self), NULL);
+ g_return_val_if_fail (GCK_IS_OBJECT (object), NULL);
+
+ value = gck_store_read_value (self, object, type, &n_value);
+ if (!value)
+ return NULL;
+
+ return g_strndup (value, n_value);
+}
+
+CK_RV
+gck_store_get_attribute (GckStore *self, GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+ CK_ATTRIBUTE at;
+ Schema *schema;
+ CK_RV rv;
+
+ g_return_val_if_fail (GCK_IS_STORE (self), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (GCK_IS_OBJECT (object), CKR_GENERAL_ERROR);
+ g_return_val_if_fail (attr, CKR_GENERAL_ERROR);
+
+ g_assert (GCK_STORE_GET_CLASS (self)->read_value);
+
+ schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
+ if (schema == NULL)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ if (schema->flags & GCK_STORE_IS_INTERNAL)
+ return CKR_ATTRIBUTE_TYPE_INVALID;
+
+ if (schema->flags & GCK_STORE_IS_SENSITIVE)
+ return CKR_ATTRIBUTE_SENSITIVE;
+
+ at.type = attr->type;
+ at.pValue = NULL;
+ at.ulValueLen = 0;
+
+ rv = GCK_STORE_GET_CLASS (self)->read_value (self, object, &at);
+ if (rv == CKR_ATTRIBUTE_TYPE_INVALID) {
+ at.pValue = schema->default_value;
+ at.ulValueLen = schema->default_length;
+ } else if (rv != CKR_OK) {
+ return rv;
+ }
+
+ /*
+ * If we get an assert here, then the derived class is probably
+ * trying to fill the buffer in the attribute passed. It should
+ * actually just be setting the pValue to its own buffers.
+ */
+ g_assert (at.pValue || !at.ulValueLen);
+
+ return gck_attribute_set_data (attr, at.pValue, at.ulValueLen);
+}
+
+void
+gck_store_write_value (GckStore *self, GckTransaction *transaction,
+ GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+ Schema *schema;
+
+ g_return_if_fail (GCK_IS_STORE (self));
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_return_if_fail (attr);
+
+ g_return_if_fail (!gck_transaction_get_failed (transaction));
+ g_assert (GCK_STORE_GET_CLASS (self)->write_value);
+
+ schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
+ if (schema == NULL) {
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_TYPE_INVALID);
+ return;
+ }
+
+ GCK_STORE_GET_CLASS (self)->write_value (self, transaction, object, attr);
+}
+
+void
+gck_store_set_attribute (GckStore *self, GckTransaction *transaction,
+ GckObject *object, CK_ATTRIBUTE_PTR attr)
+{
+ Schema *schema;
+ CK_RV rv = CKR_OK;
+
+ g_return_if_fail (GCK_IS_STORE (self));
+ g_return_if_fail (GCK_IS_TRANSACTION (transaction));
+ g_return_if_fail (GCK_IS_OBJECT (object));
+ g_return_if_fail (attr);
+
+ g_return_if_fail (!gck_transaction_get_failed (transaction));
+ g_assert (GCK_STORE_GET_CLASS (self)->write_value);
+
+ schema = g_hash_table_lookup (self->pv->schemas, &(attr->type));
+ if (schema == NULL)
+ rv = CKR_ATTRIBUTE_TYPE_INVALID;
+ else if (schema->flags & GCK_STORE_IS_INTERNAL)
+ rv = CKR_ATTRIBUTE_TYPE_INVALID;
+ else if (schema->validator)
+ rv = (schema->validator) (object, attr);
+
+ if (rv != CKR_OK) {
+ gck_transaction_fail (transaction, rv);
+ return;
+ }
+
+ GCK_STORE_GET_CLASS (self)->write_value (self, transaction, object, attr);
+}
+
+void
+gck_store_register_schema (GckStore *self, CK_ATTRIBUTE_PTR attr,
+ GckStoreValidator validator, guint flags)
+{
+ Schema *schema;
+
+ g_return_if_fail (GCK_IS_STORE (self));
+ g_return_if_fail (g_hash_table_lookup (self->pv->schemas, &(attr->type)) == NULL);
+ g_return_if_fail (!attr->ulValueLen || attr->pValue);
+ g_return_if_fail (attr->ulValueLen != (CK_ULONG)-1);
+
+ schema = g_slice_new0 (Schema);
+ schema->type = attr->type;
+ schema->flags = flags;
+ schema->validator = validator;
+ schema->default_value = attr->pValue;
+ schema->default_length = attr->ulValueLen;
+ if (schema->default_value)
+ schema->default_value = g_memdup (schema->default_value,
+ schema->default_length);
+
+ g_hash_table_insert (self->pv->schemas, &(schema->type), schema);
+}
+
+gboolean
+gck_store_lookup_schema (GckStore *self, CK_ATTRIBUTE_TYPE type, guint *flags)
+{
+ Schema *schema;
+
+ g_return_val_if_fail (GCK_IS_STORE (self), FALSE);
+
+ schema = g_hash_table_lookup (self->pv->schemas, &type);
+ if (!schema)
+ return FALSE;
+ if (flags)
+ *flags = schema->flags;
+ return TRUE;
+}
Added: trunk/pkcs11/gck/gck-store.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-store.h Sat Jan 3 19:30:08 2009
@@ -0,0 +1,101 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCK_STORE_H__
+#define __GCK_STORE_H__
+
+#include <glib-object.h>
+
+#include "gck-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+enum {
+ GCK_STORE_IS_INTERNAL = 0x01,
+ GCK_STORE_IS_SENSITIVE = 0x02
+};
+
+#define GCK_TYPE_STORE (gck_store_get_type ())
+#define GCK_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_STORE, GckStore))
+#define GCK_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_STORE, GckStoreClass))
+#define GCK_IS_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_STORE))
+#define GCK_IS_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_STORE))
+#define GCK_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_STORE, GckStoreClass))
+
+typedef struct _GckStoreClass GckStoreClass;
+typedef struct _GckStorePrivate GckStorePrivate;
+
+struct _GckStore {
+ GObject parent;
+ GckStorePrivate *pv;
+};
+
+struct _GckStoreClass {
+ GObjectClass parent_class;
+
+ /* Virtual methods */
+
+ CK_RV (*read_value) (GckStore *self, GckObject *object, CK_ATTRIBUTE_PTR attr);
+ void (*write_value) (GckStore *self, GckTransaction *transaction, GckObject *object, CK_ATTRIBUTE_PTR attr);
+};
+
+typedef CK_RV (*GckStoreValidator) (GckObject *object,
+ CK_ATTRIBUTE_PTR attr);
+
+GType gck_store_get_type (void);
+
+gboolean gck_store_lookup_schema (GckStore *self,
+ CK_ATTRIBUTE_TYPE type,
+ guint *flags);
+
+void gck_store_register_schema (GckStore *self,
+ CK_ATTRIBUTE_PTR type_and_default,
+ GckStoreValidator validator,
+ guint flags);
+
+void gck_store_set_attribute (GckStore *self,
+ GckTransaction *transaction,
+ GckObject *object,
+ CK_ATTRIBUTE_PTR attr);
+
+void gck_store_write_value (GckStore *self,
+ GckTransaction *transaction,
+ GckObject *object,
+ CK_ATTRIBUTE_PTR attr);
+
+CK_RV gck_store_get_attribute (GckStore *self,
+ GckObject *object,
+ CK_ATTRIBUTE_PTR attr);
+
+gconstpointer gck_store_read_value (GckStore *self,
+ GckObject *object,
+ CK_ATTRIBUTE_TYPE type,
+ gsize *n_value);
+
+gchar* gck_store_read_string (GckStore *self,
+ GckObject *object,
+ CK_ATTRIBUTE_TYPE type);
+
+void gck_store_notify_attribute (GckStore *self,
+ GckObject *object,
+ CK_ATTRIBUTE_TYPE type);
+
+#endif /* __GCK_STORE_H__ */
Added: trunk/pkcs11/gck/gck-transaction.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-transaction.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,291 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "gck-marshal.h"
+#include "gck-transaction.h"
+
+enum {
+ PROP_0,
+ PROP_COMPLETED,
+ PROP_FAILED,
+ PROP_RESULT
+};
+
+enum {
+ COMPLETE,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+struct _GckTransaction {
+ GObject parent;
+ GList *completes;
+ gboolean failed;
+ gboolean completed;
+ CK_RV result;
+};
+
+typedef struct _Complete {
+ GObject *object;
+ GckTransactionFunc func;
+ gpointer user_data;
+} Complete;
+
+G_DEFINE_TYPE (GckTransaction, gck_transaction, G_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL
+ */
+
+static gboolean
+complete_invoke (GckTransaction *transaction, Complete *complete)
+{
+ g_assert (complete);
+ g_assert (complete->func);
+ g_assert (complete->object);
+
+ return (complete->func) (transaction, complete->object, complete->user_data);
+}
+
+static void
+complete_destroy (Complete *complete)
+{
+ g_assert (complete->func);
+ g_assert (G_IS_OBJECT (complete->object));
+ g_object_unref (complete->object);
+ g_slice_free (Complete, complete);
+}
+
+static gboolean
+complete_accumulator (GSignalInvocationHint *ihint, GValue *return_accu,
+ const GValue *handler_return, gpointer data)
+{
+ gboolean result;
+
+ /* If any of them return false, then the result is false */
+ result = g_value_get_boolean (handler_return);
+ if (result == FALSE)
+ g_value_set_boolean (return_accu, FALSE);
+
+ /* Continue signal invocations */
+ return TRUE;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static gboolean
+gck_transaction_real_complete (GckTransaction *self)
+{
+ GList *l;
+
+ g_return_val_if_fail (!self->completed, FALSE);
+ self->completed = TRUE;
+ g_object_notify (G_OBJECT (self), "completed");
+
+ for (l = self->completes; l; l = g_list_next (l)) {
+ complete_invoke (self, l->data);
+ complete_destroy (l->data);
+ }
+
+ g_list_free (self->completes);
+ self->completes = NULL;
+
+ return TRUE;
+}
+
+static void
+gck_transaction_init (GckTransaction *self)
+{
+
+}
+
+static void
+gck_transaction_dispose (GObject *obj)
+{
+ GckTransaction *self = GCK_TRANSACTION (obj);
+
+ if (!self->completed)
+ gck_transaction_complete (self);
+
+ G_OBJECT_CLASS (gck_transaction_parent_class)->dispose (obj);
+}
+
+static void
+gck_transaction_finalize (GObject *obj)
+{
+ GckTransaction *self = GCK_TRANSACTION (obj);
+
+ g_assert (!self->completes);
+ g_assert (self->completed);
+
+ G_OBJECT_CLASS (gck_transaction_parent_class)->finalize (obj);
+}
+
+static void
+gck_transaction_set_property (GObject *obj, guint prop_id, const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_transaction_get_property (GObject *obj, guint prop_id, GValue *value,
+ GParamSpec *pspec)
+{
+ GckTransaction *self = GCK_TRANSACTION (obj);
+
+ switch (prop_id) {
+ case PROP_COMPLETED:
+ g_value_set_boolean (value, gck_transaction_get_completed (self));
+ break;
+ case PROP_FAILED:
+ g_value_set_boolean (value, gck_transaction_get_failed (self));
+ break;
+ case PROP_RESULT:
+ g_value_set_ulong (value, gck_transaction_get_result (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gck_transaction_class_init (GckTransactionClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ gobject_class->dispose = gck_transaction_dispose;
+ gobject_class->finalize = gck_transaction_finalize;
+ gobject_class->set_property = gck_transaction_set_property;
+ gobject_class->get_property = gck_transaction_get_property;
+
+ klass->complete = gck_transaction_real_complete;
+
+ g_object_class_install_property (gobject_class, PROP_COMPLETED,
+ g_param_spec_boolean ("completed", "Completed", "Whether transaction is complete",
+ FALSE, G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class, PROP_FAILED,
+ g_param_spec_boolean ("failed", "Failed", "Whether transaction failed",
+ FALSE, G_PARAM_READABLE));
+
+ g_object_class_install_property (gobject_class, PROP_RESULT,
+ g_param_spec_ulong ("result", "Result", "Result code for transaction",
+ 0, G_MAXULONG, CKR_OK, G_PARAM_READABLE));
+
+ signals[COMPLETE] = g_signal_new ("complete", GCK_TYPE_TRANSACTION,
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GckTransactionClass, complete),
+ complete_accumulator, NULL, gck_marshal_BOOLEAN__VOID,
+ G_TYPE_BOOLEAN, 0, G_TYPE_NONE);
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC
+ */
+
+GckTransaction*
+gck_transaction_new (void)
+{
+ return g_object_new (GCK_TYPE_TRANSACTION, NULL);
+}
+
+void
+gck_transaction_add (GckTransaction *self, gpointer object,
+ GckTransactionFunc func, gpointer user_data)
+{
+ Complete *complete;
+
+ g_return_if_fail (GCK_IS_TRANSACTION (self));
+ g_return_if_fail (G_IS_OBJECT (object));
+ g_return_if_fail (func);
+
+ complete = g_slice_new0 (Complete);
+ complete->func = func;
+ complete->object = g_object_ref (object);
+ complete->user_data = user_data;
+
+ self->completes = g_list_prepend (self->completes, complete);
+}
+
+void
+gck_transaction_fail (GckTransaction *self, CK_RV result)
+{
+ g_return_if_fail (GCK_IS_TRANSACTION (self));
+ g_return_if_fail (!self->completed);
+ g_return_if_fail (result != CKR_OK);
+ g_return_if_fail (!self->failed);
+
+ self->failed = TRUE;
+ self->result = result;
+
+ g_object_notify (G_OBJECT (self), "failed");
+ g_object_notify (G_OBJECT (self), "result");
+}
+
+void
+gck_transaction_complete(GckTransaction *self)
+{
+ gboolean critical = FALSE;
+
+ g_return_if_fail (GCK_IS_TRANSACTION (self));
+ g_return_if_fail (!self->completed);
+ g_signal_emit (self, signals[COMPLETE], 0, &critical);
+ g_assert (self->completed);
+
+ if (!self->failed && critical) {
+ g_warning ("transaction failed to commit, data may be lost");
+ self->failed = TRUE;
+ self->result = CKR_GENERAL_ERROR;
+ g_object_notify (G_OBJECT (self), "failed");
+ g_object_notify (G_OBJECT (self), "result");
+ }
+}
+
+gboolean
+gck_transaction_get_completed (GckTransaction *self)
+{
+ g_return_val_if_fail (GCK_IS_TRANSACTION (self), FALSE);
+ return self->completed;
+}
+
+gboolean
+gck_transaction_get_failed (GckTransaction *self)
+{
+ g_return_val_if_fail (GCK_IS_TRANSACTION (self), FALSE);
+ return self->failed;
+}
+
+CK_RV
+gck_transaction_get_result (GckTransaction *self)
+{
+ g_return_val_if_fail (GCK_IS_TRANSACTION (self), FALSE);
+ return self->result;
+}
Added: trunk/pkcs11/gck/gck-transaction.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-transaction.h Sat Jan 3 19:30:08 2009
@@ -0,0 +1,72 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCK_TRANSACTION_H__
+#define __GCK_TRANSACTION_H__
+
+#include <glib-object.h>
+
+#include "gck-types.h"
+
+#include "pkcs11/pkcs11.h"
+
+#define GCK_TYPE_TRANSACTION (gck_transaction_get_type ())
+#define GCK_TRANSACTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_TRANSACTION, GckTransaction))
+#define GCK_TRANSACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_TRANSACTION, GckTransactionClass))
+#define GCK_IS_TRANSACTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_TRANSACTION))
+#define GCK_IS_TRANSACTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_TRANSACTION))
+#define GCK_TRANSACTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_TRANSACTION, GckTransactionClass))
+
+typedef struct _GckTransactionClass GckTransactionClass;
+
+struct _GckTransactionClass {
+ GObjectClass parent_class;
+
+ /* signals --------------------------------------------------------- */
+
+ gboolean (*complete) (GckTransaction *transaction);
+};
+
+GType gck_transaction_get_type (void);
+
+GckTransaction* gck_transaction_new (void);
+
+typedef gboolean (*GckTransactionFunc) (GckTransaction *self,
+ GObject *object,
+ gpointer user_data);
+
+void gck_transaction_add (GckTransaction *self,
+ gpointer object,
+ GckTransactionFunc callback,
+ gpointer user_data);
+
+void gck_transaction_fail (GckTransaction *self,
+ CK_RV result);
+
+void gck_transaction_complete (GckTransaction *self);
+
+gboolean gck_transaction_get_failed (GckTransaction *self);
+
+CK_RV gck_transaction_get_result (GckTransaction *self);
+
+gboolean gck_transaction_get_completed (GckTransaction *self);
+
+#endif /* __GCK_TRANSACTION_H__ */
Added: trunk/pkcs11/gck/gck-types.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-types.h Sat Jan 3 19:30:08 2009
@@ -0,0 +1,41 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2008 Stefan Walter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#ifndef __GCK_TYPES_H__
+#define __GCK_TYPES_H__
+
+typedef struct _GckCertificate GckCertificate;
+typedef struct _GckCertificateKey GckCertificateKey;
+typedef struct _GckKey GckKey;
+typedef struct _GckFactoryInfo GckFactoryInfo;
+typedef struct _GckManager GckManager;
+typedef struct _GckModule GckModule;
+typedef struct _GckObject GckObject;
+typedef struct _GckPrivateKey GckPrivateKey;
+typedef struct _GckPublicKey GckPublicKey;
+typedef struct _GckSession GckSession;
+typedef struct _GckSessionPrivateKey GckSessionPrivateKey;
+typedef struct _GckSessionPublicKey GckSessionPublicKey;
+typedef struct _GckSexp GckSexp;
+typedef struct _GckStore GckStore;
+typedef struct _GckTransaction GckTransaction;
+
+#endif /* __GCK_TYPES_H__ */
Modified: trunk/pkcs11/gck/gck-util.c
==============================================================================
--- trunk/pkcs11/gck/gck-util.c (original)
+++ trunk/pkcs11/gck/gck-util.c Sat Jan 3 19:30:08 2009
@@ -58,69 +58,11 @@
}
CK_RV
-gck_util_set_bool (CK_ATTRIBUTE_PTR attr, CK_BBOOL value)
-{
- return gck_util_set_data (attr, &value, sizeof (CK_BBOOL));
-}
-
-CK_RV
-gck_util_set_ulong (CK_ATTRIBUTE_PTR attr, CK_ULONG value)
-{
- return gck_util_set_data (attr, &value, sizeof (CK_ULONG));
-}
-
-CK_RV
-gck_util_set_string (CK_ATTRIBUTE_PTR attr, const gchar* string)
-{
- g_return_val_if_fail (string, CKR_GENERAL_ERROR);
- return gck_util_set_data (attr, (CK_VOID_PTR)string, strlen (string));
-}
-
-CK_RV
-gck_util_set_date (CK_ATTRIBUTE_PTR attr, time_t time)
-{
- CK_DATE date;
- struct tm tm;
- gchar buf[16];
-
- /* 'Empty' date as defined in PKCS#11 */
- if (time == (time_t)-1)
- return gck_util_set_data (attr, NULL, 0);
-
- if (!attr->pValue) {
- attr->ulValueLen = sizeof (CK_DATE);
- return CKR_OK;
- }
-
- if (!gmtime_r (&time, &tm))
- g_return_val_if_reached (CKR_GENERAL_ERROR);
-
- g_assert (sizeof (date.year) == 4);
- snprintf ((char*)buf, 5, "%04d", 1900 + tm.tm_year);
- memcpy (date.year, buf, 4);
-
- g_assert (sizeof (date.month) == 2);
- snprintf ((char*)buf, 3, "%02d", tm.tm_mon + 1);
- memcpy (date.month, buf, 2);
-
- g_assert (sizeof (date.day) == 2);
- snprintf ((char*)buf, 3, "%02d", tm.tm_mday);
- memcpy (date.day, buf, 2);
-
- return gck_util_set_data (attr, &date, sizeof (date));
-}
-CK_RV
-gck_util_set_data (CK_ATTRIBUTE_PTR attr, gconstpointer value, gsize n_value)
-{
- return gck_util_return_data (attr->pValue, &(attr->ulValueLen), value, n_value);
-}
-
-CK_RV
gck_util_return_data (CK_VOID_PTR output, CK_ULONG_PTR n_output,
gconstpointer input, gsize n_input)
{
g_return_val_if_fail (n_output, CKR_GENERAL_ERROR);
- g_return_val_if_fail (input, CKR_GENERAL_ERROR);
+ g_return_val_if_fail (input || !n_input, CKR_GENERAL_ERROR);
/* Just asking for the length */
if (!output) {
@@ -135,38 +77,8 @@
}
*n_output = n_input;
- memcpy (output, input, n_input);
- return CKR_OK;
-}
-
-CK_RV
-gck_util_set_mpi (CK_ATTRIBUTE_PTR attr, gcry_mpi_t mpi)
-{
- gsize len;
- gcry_error_t gcry;
-
- g_assert (attr);
- g_assert (mpi);
-
- /* Get the size */
- gcry = gcry_mpi_print (GCRYMPI_FMT_USG, NULL, 0, &len, mpi);
- g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
-
- if (!attr->pValue) {
- attr->ulValueLen = len;
- return CKR_OK;
- }
-
- if (len > attr->ulValueLen) {
- attr->ulValueLen = len;
- return CKR_BUFFER_TOO_SMALL;
- }
-
- /* Write in directly to attribute */
- gcry = gcry_mpi_print (GCRYMPI_FMT_USG, attr->pValue, len, &len, mpi);
- g_return_val_if_fail (gcry == 0, CKR_GENERAL_ERROR);
-
- attr->ulValueLen = len;
+ if (n_input)
+ memcpy (output, input, n_input);
return CKR_OK;
}
Modified: trunk/pkcs11/gck/gck-util.h
==============================================================================
--- trunk/pkcs11/gck/gck-util.h (original)
+++ trunk/pkcs11/gck/gck-util.h Sat Jan 3 19:30:08 2009
@@ -37,28 +37,12 @@
void gck_util_ulong_free (gpointer ptr_to_ulong);
-CK_RV gck_util_set_bool (CK_ATTRIBUTE_PTR attr,
- CK_BBOOL value);
-
-CK_RV gck_util_set_ulong (CK_ATTRIBUTE_PTR attr,
- CK_ULONG value);
-
-CK_RV gck_util_set_string (CK_ATTRIBUTE_PTR attr,
- const gchar* string);
-
-CK_RV gck_util_set_date (CK_ATTRIBUTE_PTR attr,
- time_t when);
-
-CK_RV gck_util_set_data (CK_ATTRIBUTE_PTR attr,
- gconstpointer value,
- gsize n_value);
-
CK_RV gck_util_return_data (CK_VOID_PTR output,
CK_ULONG_PTR n_output,
gconstpointer input,
gsize n_input);
-CK_RV gck_util_set_mpi (CK_ATTRIBUTE_PTR attr,
+CK_RV gck_attribute_set_mpi (CK_ATTRIBUTE_PTR attr,
gcry_mpi_t mpi);
CK_ULONG gck_util_next_handle (void);
Modified: trunk/pkcs11/gck/tests/Makefile.am
==============================================================================
--- trunk/pkcs11/gck/tests/Makefile.am (original)
+++ trunk/pkcs11/gck/tests/Makefile.am Sat Jan 3 19:30:08 2009
@@ -5,13 +5,17 @@
asn1-def-test.h: test.asn
asn1Parser -o asn1-def-test.h test.asn
+# Test files should be listed in order they need to run
UNIT_AUTO = \
unit-test-crypto.c \
unit-test-data-asn1.c \
unit-test-data-der.c \
unit-test-data-openssl.c \
- unit-test-file-tracker.c \
- $(BUILT_SOURCES)
+ unit-test-transaction.c \
+ unit-test-store.c \
+ unit-test-memory-store.c \
+ unit-test-file-store.c \
+ unit-test-file-tracker.c
UNIT_PROMPT =
Added: trunk/pkcs11/gck/tests/test-data/test-file-store.store
==============================================================================
Binary file. No diff available.
Added: trunk/pkcs11/gck/tests/unit-test-file-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-file-store.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,388 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-file-store.c: Test file store functionality
+
+ Copyright (C) 2008 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 "gck/gck-file-store.h"
+#include "gck/gck-object.h"
+#include "gck/gck-transaction.h"
+
+/* Both point to the same thing */
+static GckStore *store = NULL;
+static GckFileStore *file_store = NULL;
+static GckTransaction *transaction = NULL;
+static GckObject *object = NULL;
+static GckObject *prv_object = NULL;
+static gchar *test_filename = NULL;
+
+static void
+copy_file (const gchar *from, const gchar *to)
+{
+ gchar *contents;
+ gsize length;
+ gboolean ret;
+
+ ret = g_file_get_contents (from, &contents, &length, NULL);
+ g_assert (ret == TRUE);
+ ret = g_file_set_contents (to, contents, length, NULL);
+ g_assert (ret == TRUE);
+ g_free (contents);
+}
+
+DEFINE_SETUP(file_store)
+{
+ CK_ATTRIBUTE attr;
+ CK_ULONG twentyfour = 24;
+
+ test_filename = test_build_filename ("unit-test-file-store");
+
+ copy_file ("./test-data/test-file-store.store", test_filename);
+ file_store = gck_file_store_new (test_filename);
+ store = GCK_STORE (file_store);
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "label";
+ attr.ulValueLen = 5;
+
+ gck_store_register_schema (store, &attr, NULL, 0);
+ g_assert (gck_store_lookup_schema (store, CKA_LABEL, NULL));
+
+ attr.type = CKA_VALUE;
+ attr.pValue = NULL;
+ attr.ulValueLen = 0;
+
+ gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_SENSITIVE);
+
+ attr.type = CKA_BITS_PER_PIXEL;
+ attr.pValue = &twentyfour;
+ attr.ulValueLen = sizeof (twentyfour);
+
+ gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_INTERNAL);
+
+ transaction = gck_transaction_new ();
+ object = g_object_new (GCK_TYPE_OBJECT, NULL);
+ prv_object = g_object_new (GCK_TYPE_OBJECT, NULL);
+
+ gck_file_store_connect_entry (file_store, "unique-one", object);
+ gck_file_store_connect_entry (file_store, "unique-private", prv_object);
+}
+
+DEFINE_TEARDOWN(file_store)
+{
+ g_free (test_filename);
+
+ gck_file_store_disconnect_entry (file_store, "unique-private", prv_object);
+
+ if (prv_object != NULL)
+ g_object_unref (prv_object);
+ prv_object = NULL;
+
+ g_object_unref (file_store);
+ file_store = NULL;
+ store = NULL;
+
+ g_object_unref (transaction);
+ transaction = NULL;
+
+ if (object != NULL)
+ g_object_unref (object);
+ object = NULL;
+}
+
+DEFINE_TEST(test_properties)
+{
+ const gchar *filename;
+ gboolean locked;
+ gchar *name;
+
+ filename = gck_file_store_get_filename (file_store);
+ g_assert_cmpstr (filename, ==, test_filename);
+
+ locked = gck_file_store_get_locked (file_store);
+ g_assert (locked == TRUE);
+
+ /* Try properties */
+ locked = FALSE;
+ g_object_get (file_store, "filename", &name, "locked", &locked, NULL);
+ g_assert_cmpstr (name, ==, test_filename);
+ g_assert (locked == TRUE);
+}
+
+DEFINE_TEST(test_store_read)
+{
+ gboolean ret;
+
+ ret = gck_file_store_refresh (file_store);
+ g_assert (ret);
+}
+
+DEFINE_TEST(test_unlock)
+{
+ gchar *str;
+ CK_RV rv;
+
+ /* We shouldn't be able to read from private object */
+ g_assert (!gck_file_store_have_entry (file_store, "unique-private"));
+
+ /* Try with wrong password */
+ rv = gck_file_store_unlock (file_store, (guchar*)"password", 8);
+ g_assert (rv == CKR_PIN_INCORRECT);
+ g_assert (gck_file_store_get_locked (file_store) == TRUE);
+
+ /* A valid unlock */
+ rv = gck_file_store_unlock (file_store, (guchar*)"booo", 4);
+ g_assert (rv == CKR_OK);
+ g_assert (gck_file_store_get_locked (file_store) == FALSE);
+
+ /* Unlocking twice should result in this code */
+ rv = gck_file_store_unlock (file_store, (guchar*)"booo", 4);
+ g_assert (rv == CKR_USER_ALREADY_LOGGED_IN);
+ g_assert (gck_file_store_get_locked (file_store) == FALSE);
+
+ /* Now we should be able to read from private object */
+ g_assert (gck_file_store_have_entry (file_store, "unique-private"));
+ str = gck_store_read_string (store, prv_object, CKA_LABEL);
+ g_assert_cmpstr (str, ==, "private-label");
+ g_free (str);
+
+ /* Now lock again */
+ rv = gck_file_store_lock (file_store);
+ g_assert (rv == CKR_OK);
+
+ /* Locking twice should result in this code */
+ rv = gck_file_store_lock (file_store);
+ g_assert (rv == CKR_USER_NOT_LOGGED_IN);
+
+ /* We should get default attributes */
+ str = gck_store_read_string (store, prv_object, CKA_LABEL);
+ g_assert_cmpstr (str, ==, "label");
+ g_free (str);
+}
+
+DEFINE_TEST(write_encrypted)
+{
+ CK_ATTRIBUTE attr;
+ gboolean ret;
+ gchar *str;
+ CK_RV rv;
+
+ rv = gck_file_store_unlock (file_store, (guchar*)"booo", 4);
+ g_assert (rv == CKR_OK);
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "private-label-two";
+ attr.ulValueLen = 17;
+
+ gck_store_set_attribute (store, transaction, prv_object, &attr);
+
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+ ret = gck_file_store_refresh (file_store);
+ g_assert (ret);
+
+ str = gck_store_read_string (store, prv_object, CKA_LABEL);
+ g_assert_cmpstr (str, ==, "private-label-two");
+ g_free (str);
+}
+
+DEFINE_TEST(file_set_get_attribute)
+{
+ gchar buffer[16];
+ CK_ATTRIBUTE attr;
+ CK_RV rv;
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "booyah";
+ attr.ulValueLen = 6;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+ attr.pValue = buffer;
+ attr.ulValueLen = 7;
+ rv = gck_store_get_attribute (store, object, &attr);
+ g_assert (rv == CKR_OK);
+ g_assert (attr.ulValueLen == 6);
+ g_assert (memcmp (attr.pValue, "booyah", 6) == 0);
+}
+
+DEFINE_TEST(file_write_read_value)
+{
+ CK_ATTRIBUTE attr;
+ CK_ULONG five = 5;
+ gconstpointer value;
+ gsize n_value;
+
+ attr.type = CKA_BITS_PER_PIXEL;
+ attr.pValue = &five;
+ attr.ulValueLen = sizeof (five);
+
+ gck_store_write_value (store, transaction, object, &attr);
+
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+ value = gck_store_read_value (store, object, CKA_BITS_PER_PIXEL, &n_value);
+ g_assert (value);
+ g_assert (n_value == sizeof (five));
+ g_assert (memcmp (value, &five, sizeof (five)) == 0);
+}
+
+DEFINE_TEST(destroy_entry)
+{
+ gboolean ret;
+ gchar *str;
+
+ str = gck_store_read_string (store, object, CKA_LABEL);
+ g_assert_cmpstr (str, ==, "public-label");
+ g_free (str);
+
+ gck_file_store_destroy_entry (file_store, transaction, "unique-one");
+ gck_transaction_complete (transaction);
+
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+ g_assert (!gck_transaction_get_failed (transaction));
+
+ ret = gck_file_store_refresh (file_store);
+ g_assert (ret);
+
+ str = gck_store_read_string (store, object, CKA_LABEL);
+ g_assert_cmpstr (str, ==, "label");
+ g_free (str);
+}
+
+DEFINE_TEST(refresh_modifications)
+{
+ GckFileStore *fs;
+ gboolean ret;
+ gchar *str;
+
+ /* Check that our label is correct */
+ str = gck_store_read_string (store, object, CKA_LABEL);
+ g_assert_cmpstr (str, ==, "public-label");
+ g_free (str);
+
+ /* Open a second file store on the same file */
+ fs = gck_file_store_new (test_filename);
+ ret = gck_file_store_refresh (fs);
+ g_assert (ret);
+
+ /* Delete something from other store */
+ gck_file_store_destroy_entry (fs, transaction, "unique-one");
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+ g_assert (!gck_transaction_get_failed (transaction));
+
+ /* Refresh first file store */
+ ret = gck_file_store_refresh (file_store);
+ g_assert (ret);
+
+ /* Should be gone, we should see default label */
+ str = gck_store_read_string (store, object, CKA_LABEL);
+ g_assert_cmpstr (str, ==, "label");
+ g_free (str);
+
+ g_object_unref (fs);
+}
+
+DEFINE_TEST(file_store_revert_first)
+{
+ CK_ATTRIBUTE attr, prev;
+ gconstpointer value;
+ gsize n_value;
+
+ prev.type = CKA_LABEL;
+ prev.pValue = "numberone";
+ prev.ulValueLen = 9;
+
+ /* Change the attribute */
+ gck_store_set_attribute (store, transaction, object, &prev);
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+ /* Value should be new value */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == prev.ulValueLen);
+ g_assert (memcmp (prev.pValue, value, n_value) == 0);
+
+ /* A new transaction */
+ g_object_unref (transaction);
+ transaction = gck_transaction_new ();
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "second";
+ attr.ulValueLen = 6;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+ g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+ /* Should get new value */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == attr.ulValueLen);
+ g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "third";
+ attr.ulValueLen = 5;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+ g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+ /* Should get new value */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == attr.ulValueLen);
+ g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+ /* Fail for some arbitrary reason */
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+
+ /* Value should not have changed yet */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == attr.ulValueLen);
+ g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+ /* Now complete the transaction */
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_failed (transaction) == TRUE);
+
+ /* Value should now have changed, back to default */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == prev.ulValueLen);
+ g_assert (memcmp (prev.pValue, value, n_value) == 0);
+}
+
+DEFINE_TEST(file_store_nonexistant)
+{
+ GckFileStore *fs;
+ gboolean ret;
+
+ /* Should be able to read from a nonexistant file store */
+ fs = gck_file_store_new ("./nonexistant");
+ ret = gck_file_store_refresh (fs);
+ g_assert (ret);
+
+ g_object_unref (fs);
+}
Added: trunk/pkcs11/gck/tests/unit-test-memory-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-memory-store.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,431 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-memory-store.c: Test memory store functionality
+
+ Copyright (C) 2008 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "run-auto-test.h"
+
+#include "gck/gck-object.h"
+#include "gck/gck-memory-store.h"
+#include "gck/gck-transaction.h"
+
+static GckStore *store = NULL;
+static GckObject *object = NULL;
+static GckTransaction *transaction = NULL;
+static guchar buffer[1024];
+
+static CK_RV
+test_validator (GckObject *obj, CK_ATTRIBUTE_PTR attr)
+{
+ const gchar *data;
+ guint i;
+
+ g_assert (obj == object);
+ g_assert (attr);
+ g_assert (attr->type == CKA_LABEL);
+
+ /* Test that the whole string is ascii and lower case */
+ data = attr->pValue;
+ for (i = 0; i < attr->ulValueLen; ++i) {
+ if (!g_ascii_isprint(data[i]) || !g_ascii_islower (data[i]))
+ return CKR_ATTRIBUTE_VALUE_INVALID;
+ }
+
+ return CKR_OK;
+}
+
+DEFINE_SETUP(memory_store)
+{
+ CK_ATTRIBUTE attr;
+ CK_ULONG twentyfour = 24;
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "label";
+ attr.ulValueLen = 5;
+
+ store = GCK_STORE (gck_memory_store_new ());
+
+ gck_store_register_schema (store, &attr, test_validator, 0);
+ g_assert (gck_store_lookup_schema (store, CKA_LABEL, NULL));
+
+ attr.type = CKA_VALUE;
+ attr.pValue = NULL;
+ attr.ulValueLen = 0;
+
+ gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_SENSITIVE);
+
+ attr.type = CKA_BITS_PER_PIXEL;
+ attr.pValue = &twentyfour;
+ attr.ulValueLen = sizeof (twentyfour);
+
+ gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_INTERNAL);
+
+ object = g_object_new (GCK_TYPE_OBJECT, NULL);
+
+ transaction = gck_transaction_new ();
+}
+
+DEFINE_TEARDOWN(memory_store)
+{
+ g_object_unref (store);
+ store = NULL;
+
+ g_object_unref (transaction);
+ transaction = NULL;
+
+ if (object != NULL)
+ g_object_unref (object);
+ object = NULL;
+}
+
+DEFINE_TEST(get_attribute_default)
+{
+ CK_ATTRIBUTE attr;
+ CK_RV rv;
+
+ attr.type = CKA_LABEL;
+ attr.pValue = NULL;
+ rv = gck_store_get_attribute (store, object, &attr);
+ g_assert (rv == CKR_OK);
+ g_assert (attr.ulValueLen == 5);
+ attr.pValue = buffer;
+ rv = gck_store_get_attribute (store, object, &attr);
+ g_assert (rv == CKR_OK);
+ g_assert (attr.ulValueLen == 5);
+ g_assert (memcmp (attr.pValue, "label", 5) == 0);
+}
+
+DEFINE_TEST(read_value_default)
+{
+ gconstpointer value;
+ gsize n_value;
+
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value);
+ g_assert (n_value == 5);
+ g_assert (memcmp (value, "label", 5) == 0);
+
+ value = gck_store_read_value (store, object, CKA_BITS_PER_PIXEL, &n_value);
+ g_assert (value);
+ g_assert (n_value == sizeof (CK_ULONG));
+ g_assert (*((CK_ULONG_PTR)value) == 24);
+}
+
+DEFINE_TEST(read_string)
+{
+ gchar *str;
+
+ str = gck_store_read_string (store, object, CKA_LABEL);
+ g_assert_cmpstr (str, ==, "label");
+ g_free (str);
+}
+
+DEFINE_TEST(get_invalid)
+{
+ CK_ATTRIBUTE attr;
+ CK_RV rv;
+
+ attr.type = CKA_APPLICATION;
+ attr.pValue = NULL;
+ attr.ulValueLen = 0;
+
+ rv = gck_store_get_attribute (store, object, &attr);
+ g_assert (rv == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(get_sensitive)
+{
+ CK_ATTRIBUTE attr;
+ CK_RV rv;
+
+ attr.type = CKA_VALUE;
+ attr.pValue = NULL;
+ attr.ulValueLen = 0;
+
+ rv = gck_store_get_attribute (store, object, &attr);
+ g_assert (rv == CKR_ATTRIBUTE_SENSITIVE);
+}
+
+DEFINE_TEST(get_internal)
+{
+ CK_ATTRIBUTE attr;
+ CK_RV rv;
+
+ attr.type = CKA_BITS_PER_PIXEL;
+ attr.pValue = NULL;
+ attr.ulValueLen = 0;
+
+ rv = gck_store_get_attribute (store, object, &attr);
+ g_assert (rv == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(set_invalid)
+{
+ CK_ATTRIBUTE attr;
+
+ attr.type = CKA_APPLICATION;
+ attr.pValue = "me";
+ attr.ulValueLen = 2;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+ g_assert (gck_transaction_get_result (transaction) == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(set_internal)
+{
+ CK_ATTRIBUTE attr;
+ CK_ULONG five = 5;
+
+ attr.type = CKA_BITS_PER_PIXEL;
+ attr.pValue = &five;
+ attr.ulValueLen = sizeof (five);
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+ g_assert (gck_transaction_get_result (transaction) == CKR_ATTRIBUTE_TYPE_INVALID);
+}
+
+DEFINE_TEST(set_get_attribute)
+{
+ CK_ATTRIBUTE attr;
+ CK_RV rv;
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "booyah";
+ attr.ulValueLen = 6;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+ attr.pValue = buffer;
+ attr.ulValueLen = 1024;
+ rv = gck_store_get_attribute (store, object, &attr);
+ g_assert (rv == CKR_OK);
+ g_assert (attr.ulValueLen == 6);
+ g_assert (memcmp (attr.pValue, "booyah", 6) == 0);
+}
+
+DEFINE_TEST(write_read_value)
+{
+ CK_ATTRIBUTE attr;
+ CK_ULONG five = 5;
+ gconstpointer value;
+ gsize n_value;
+
+ attr.type = CKA_BITS_PER_PIXEL;
+ attr.pValue = &five;
+ attr.ulValueLen = sizeof (five);
+
+ gck_store_write_value (store, transaction, object, &attr);
+
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+ value = gck_store_read_value (store, object, CKA_BITS_PER_PIXEL, &n_value);
+ g_assert (value);
+ g_assert (n_value == sizeof (five));
+ g_assert (memcmp (value, &five, sizeof (five)) == 0);
+}
+
+DEFINE_TEST(set_no_validate)
+{
+ CK_ATTRIBUTE attr;
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "CAPITALS";
+ attr.ulValueLen = 8;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+ g_assert (gck_transaction_get_failed (transaction));
+
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_result (transaction) == CKR_ATTRIBUTE_VALUE_INVALID);
+}
+
+DEFINE_TEST(set_transaction_default)
+{
+ CK_ATTRIBUTE attr;
+ gconstpointer value;
+ gsize n_value;
+
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "another";
+ attr.ulValueLen = 7;
+
+ /* Change the attribute */
+ gck_store_set_attribute (store, transaction, object, &attr);
+ g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+ /* Should get new value */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == attr.ulValueLen);
+ g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+ /* Fail for some arbitrary reason */
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+
+ /* Value should not have changed yet */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == attr.ulValueLen);
+ g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+ /* Now complete the transaction */
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_failed (transaction) == TRUE);
+
+ /* Value should now have changed, back to default */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == 5);
+ g_assert (memcmp (value, "label", 5) == 0);
+}
+
+DEFINE_TEST(set_transaction_revert_first)
+{
+ CK_ATTRIBUTE attr, prev;
+ gconstpointer value;
+ gsize n_value;
+
+ prev.type = CKA_LABEL;
+ prev.pValue = "numberone";
+ prev.ulValueLen = 9;
+
+ /* Change the attribute */
+ gck_store_set_attribute (store, transaction, object, &prev);
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+ /* Value should be new value */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == prev.ulValueLen);
+ g_assert (memcmp (prev.pValue, value, n_value) == 0);
+
+ /* A new transaction */
+ g_object_unref (transaction);
+ transaction = gck_transaction_new ();
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "second";
+ attr.ulValueLen = 6;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+ g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+ /* Should get new value */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == attr.ulValueLen);
+ g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "third";
+ attr.ulValueLen = 5;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+ g_assert (gck_transaction_get_failed (transaction) == FALSE);
+
+ /* Should get new value */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == attr.ulValueLen);
+ g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+ /* Fail for some arbitrary reason */
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+
+ /* Value should not have changed yet */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == attr.ulValueLen);
+ g_assert (memcmp (attr.pValue, value, n_value) == 0);
+
+ /* Now complete the transaction */
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_failed (transaction) == TRUE);
+
+ /* Value should now have changed, back to default */
+ value = gck_store_read_value (store, object, CKA_LABEL, &n_value);
+ g_assert (value && n_value == prev.ulValueLen);
+ g_assert (memcmp (prev.pValue, value, n_value) == 0);
+}
+
+static void
+notify_attribute (GckObject *obj, CK_ATTRIBUTE_TYPE type, gpointer data)
+{
+ g_assert (obj == object);
+ g_assert (type == CKA_LABEL);
+ g_assert (data);
+
+ *((CK_ATTRIBUTE_TYPE*)data) = type;
+}
+
+DEFINE_TEST(set_notifies)
+{
+ CK_ATTRIBUTE attr;
+ CK_ATTRIBUTE_TYPE type = 0;
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "valid";
+ attr.ulValueLen = 5;
+
+ g_signal_connect (object, "notify-attribute", G_CALLBACK (notify_attribute), &type);
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+
+ /* We should have been notified that the attribute changed at this point */
+ g_assert (type == CKA_LABEL);
+
+ /* Reset for next notify */
+ type = 0;
+
+ /* Fail for some arbitrary reason */
+ gck_transaction_fail (transaction, CKR_ATTRIBUTE_VALUE_INVALID);
+
+ /* We should not have been notified yet */
+ g_assert (type == 0);
+
+ /* Now complete the transaction */
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_failed (transaction) == TRUE);
+
+ /* Now we should have been notified that this changed back */
+ g_assert (type == CKA_LABEL);
+}
+
+DEFINE_TEST(set_object_gone_first)
+{
+ CK_ATTRIBUTE attr;
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "valid";
+ attr.ulValueLen = 5;
+
+ gck_store_set_attribute (store, transaction, object, &attr);
+ gck_transaction_complete (transaction);
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+ /* This tests memory store internal tracking */
+ g_object_unref (object);
+ object = NULL;
+}
Added: trunk/pkcs11/gck/tests/unit-test-store.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-store.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,79 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-store.c: Test general store functionality
+
+ Copyright (C) 2008 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "run-auto-test.h"
+
+#include "gck/gck-store.h"
+
+static GckStore *store = NULL;
+
+DEFINE_SETUP(store)
+{
+ store = g_object_new (GCK_TYPE_STORE, NULL);
+}
+
+DEFINE_TEARDOWN(store)
+{
+ g_object_unref (store);
+ store = NULL;
+}
+
+DEFINE_TEST(store_schema)
+{
+ CK_ATTRIBUTE attr;
+
+ attr.type = CKA_LABEL;
+ attr.pValue = "Label";
+ attr.ulValueLen = 5;
+
+ gck_store_register_schema (store, &attr, NULL, 0);
+ g_assert (gck_store_lookup_schema (store, CKA_LABEL, NULL));
+
+ /* Not in the schema */
+ g_assert (!gck_store_lookup_schema (store, CKA_VALUE, NULL));
+}
+
+DEFINE_TEST(store_schema_flags)
+{
+ CK_ATTRIBUTE attr;
+ guint flags;
+
+ attr.type = CKA_VALUE;
+ attr.pValue = NULL;
+ attr.ulValueLen = 0;
+
+ gck_store_register_schema (store, &attr, NULL, GCK_STORE_IS_SENSITIVE);
+ g_assert (gck_store_lookup_schema (store, CKA_VALUE, &flags));
+ g_assert (flags == GCK_STORE_IS_SENSITIVE);
+}
+
+/*
+ * That's all we can test in the base class of GckStore without a proper
+ * derived class. For more tests see unit-test-memory-store.c and
+ * unit-test-file-store.c
+ */
Added: trunk/pkcs11/gck/tests/unit-test-transaction.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-transaction.c Sat Jan 3 19:30:08 2009
@@ -0,0 +1,188 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-store.c: Test general store functionality
+
+ Copyright (C) 2008 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 "gck/gck-transaction.h"
+
+DEFINE_TEST(transaction_empty)
+{
+ GckTransaction *transaction;
+ gboolean completed, failed;
+ CK_RV result;
+
+ transaction = gck_transaction_new ();
+ g_assert (GCK_IS_TRANSACTION (transaction));
+
+ g_assert (gck_transaction_get_failed (transaction) == FALSE);
+ g_assert (gck_transaction_get_completed (transaction) == FALSE);
+ g_assert (gck_transaction_get_result (transaction) == CKR_OK);
+
+ gck_transaction_complete (transaction);
+
+ /* Make sure values are actually set */
+ result = (CK_RV)-1;
+ completed = failed = FALSE;
+
+ g_object_get (transaction, "completed", &completed, "failed", &failed, "result", &result, NULL);
+ g_assert (result == CKR_OK);
+ g_assert (completed == TRUE);
+ g_assert (failed == FALSE);
+
+ g_object_unref (transaction);
+}
+
+DEFINE_TEST(transaction_fail)
+{
+ GckTransaction *transaction;
+
+ transaction = gck_transaction_new ();
+
+ gck_transaction_fail (transaction, CKR_ARGUMENTS_BAD);
+
+ g_assert (gck_transaction_get_failed (transaction) == TRUE);
+ g_assert (gck_transaction_get_completed (transaction) == FALSE);
+ g_assert (gck_transaction_get_result (transaction) == CKR_ARGUMENTS_BAD);
+
+ gck_transaction_complete (transaction);
+
+ g_assert (gck_transaction_get_failed (transaction) == TRUE);
+ g_assert (gck_transaction_get_completed (transaction) == TRUE);
+ g_assert (gck_transaction_get_result (transaction) == CKR_ARGUMENTS_BAD);
+
+ g_object_unref (transaction);
+}
+
+
+static gboolean
+completed_signal (GckTransaction *transaction, gpointer data)
+{
+ g_assert (GCK_IS_TRANSACTION (transaction));
+ g_assert (data);
+
+ *((guint*)data) = TRUE;
+ return TRUE;
+}
+
+static gboolean
+completed_callback (GckTransaction *transaction, GObject *object, gpointer data)
+{
+ g_assert (GCK_IS_TRANSACTION (transaction));
+ g_assert (data);
+
+ /* In this case we set the object to the transaction for fun */
+ g_assert (GCK_IS_TRANSACTION (transaction));
+ g_assert (transaction == GCK_TRANSACTION (object));
+
+ *((guint*)data) = gck_transaction_get_failed (transaction);
+ return TRUE;
+}
+
+DEFINE_TEST(transaction_signals_success)
+{
+ GckTransaction *transaction = gck_transaction_new ();
+
+ /* Initialize with some invalid values */
+ guint completed = 3;
+ guint failed = 3;
+
+ g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
+ gck_transaction_add (transaction, transaction, completed_callback, &failed);
+
+ /* No callbacks called yet */
+ g_assert (completed == 3);
+ g_assert (failed == 3);
+
+ gck_transaction_complete (transaction);
+
+ g_assert (completed == TRUE);
+ g_assert (failed == FALSE);
+
+ g_object_unref (transaction);
+}
+
+DEFINE_TEST(transaction_signals_failure)
+{
+ GckTransaction *transaction = gck_transaction_new ();
+
+ /* Initialize with some invalid values */
+ guint completed = 3;
+ guint failed = 3;
+
+ g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
+ gck_transaction_add (transaction, transaction, completed_callback, &failed);
+
+ gck_transaction_fail (transaction, CKR_ARGUMENTS_BAD);
+
+ /* No callbacks called yet */
+ g_assert (completed == 3);
+ g_assert (failed == 3);
+
+ gck_transaction_complete (transaction);
+
+ g_assert (completed == TRUE);
+ g_assert (failed == TRUE);
+
+ g_object_unref (transaction);
+}
+
+static guint order_value = 3;
+
+static gboolean
+order_callback (GckTransaction *transaction, GObject *object, gpointer data)
+{
+ g_assert (GCK_IS_TRANSACTION (transaction));
+ g_assert (data);
+ g_assert (GPOINTER_TO_UINT (data) == order_value);
+ --order_value;
+ return TRUE;
+}
+
+DEFINE_TEST(transaction_order_is_reverse)
+{
+ GckTransaction *transaction = gck_transaction_new ();
+
+ order_value = 3;
+ gck_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (1));
+ gck_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (2));
+ gck_transaction_add (transaction, transaction, order_callback, GUINT_TO_POINTER (3));
+
+ gck_transaction_complete (transaction);
+ g_object_unref (transaction);
+}
+
+DEFINE_TEST(transaction_dispose_completes)
+{
+ GckTransaction *transaction = gck_transaction_new ();
+
+ /* Initialize with some invalid values */
+ guint completed = 3;
+
+ g_signal_connect (transaction, "complete", G_CALLBACK (completed_signal), &completed);
+
+ g_object_run_dispose (G_OBJECT (transaction));
+
+ g_assert (completed == TRUE);
+
+ g_object_unref (transaction);
+}
Modified: trunk/pkcs11/roots/gck-roots-certificate.c
==============================================================================
--- trunk/pkcs11/roots/gck-roots-certificate.c (original)
+++ trunk/pkcs11/roots/gck-roots-certificate.c Sat Jan 3 19:30:08 2009
@@ -61,7 +61,7 @@
switch (attr->type) {
case CKA_TRUSTED:
- return gck_util_set_bool (attr, TRUE);
+ return gck_attribute_set_bool (attr, TRUE);
case CKA_CERTIFICATE_CATEGORY:
if (!gck_certificate_calc_category (GCK_CERTIFICATE (self), &category))
@@ -69,7 +69,7 @@
/* Unknown category, is CA by default in this slot */
if (category == 0)
category = 2;
- return gck_util_set_ulong (attr, category);
+ return gck_attribute_set_ulong (attr, category);
}
return GCK_OBJECT_CLASS (gck_roots_certificate_parent_class)->get_attribute (base, attr);
Modified: trunk/pkcs11/ssh-keys/gck-ssh-private-key.c
==============================================================================
--- trunk/pkcs11/ssh-keys/gck-ssh-private-key.c (original)
+++ trunk/pkcs11/ssh-keys/gck-ssh-private-key.c Sat Jan 3 19:30:08 2009
@@ -24,6 +24,7 @@
#include "gck-ssh-openssh.h"
#include "gck-ssh-private-key.h"
+#include "gck/gck-attributes.h"
#include "gck/gck-manager.h"
#include "gck/gck-object.h"
#include "gck/gck-sexp.h"
@@ -138,7 +139,7 @@
switch (attr->type) {
case CKA_LABEL:
- return gck_util_set_string (attr, self->label ? self->label : "");
+ return gck_attribute_set_string (attr, self->label ? self->label : "");
}
return GCK_OBJECT_CLASS (gck_ssh_private_key_parent_class)->get_attribute (base, attr);
Modified: trunk/pkcs11/ssh-keys/gck-ssh-public-key.c
==============================================================================
--- trunk/pkcs11/ssh-keys/gck-ssh-public-key.c (original)
+++ trunk/pkcs11/ssh-keys/gck-ssh-public-key.c Sat Jan 3 19:30:08 2009
@@ -51,7 +51,7 @@
switch (attr->type) {
case CKA_LABEL:
- return gck_util_set_string (attr, self->label ? self->label : "");
+ return gck_attribute_set_string (attr, self->label ? self->label : "");
}
return GCK_OBJECT_CLASS (gck_ssh_public_key_parent_class)->get_attribute (base, attr);
Modified: trunk/tests/gtest-helpers.c
==============================================================================
--- trunk/tests/gtest-helpers.c (original)
+++ trunk/tests/gtest-helpers.c Sat Jan 3 19:30:08 2009
@@ -36,6 +36,7 @@
#include "common/gkr-secure-memory.h"
static GStaticMutex memory_mutex = G_STATIC_MUTEX_INIT;
+static const gchar *test_path = NULL;
void gkr_memory_lock (void)
{
@@ -87,6 +88,12 @@
return mainloop;
}
+gchar*
+test_build_filename (const gchar *basename)
+{
+ return g_build_filename (test_path, basename, NULL);
+}
+
static void
chdir_base_dir (char* argv0)
{
@@ -112,16 +119,16 @@
main (int argc, char* argv[])
{
GLogLevelFlags fatal_mask;
- const gchar* envi;
g_thread_init (NULL);
- envi = getenv ("GNOME_KEYRING_TEST_PATH");
- if (envi) {
+ test_path = getenv ("GNOME_KEYRING_TEST_PATH");
+ if (test_path) {
setenv ("GNOME_KEYRING_OUTSIDE_TEST", "TRUE", 1);
} else {
- setenv ("GNOME_KEYRING_TEST_PATH", "/tmp/test-gnome-keyring", 1);
- g_mkdir_with_parents ("/tmp/test-gnome-keyring", 0777);
+ test_path = "/tmp/test-gnome-keyring";
+ setenv ("GNOME_KEYRING_TEST_PATH", test_path, 1);
+ g_mkdir_with_parents (test_path, 0777);
}
chdir_base_dir (argv[0]);
Modified: trunk/tests/gtest-helpers.h
==============================================================================
--- trunk/tests/gtest-helpers.h (original)
+++ trunk/tests/gtest-helpers.h Sat Jan 3 19:30:08 2009
@@ -24,12 +24,23 @@
#ifndef GTEST_HELPERS_H_
#define GTEST_HELPERS_H_
+#include "config.h"
+
#include <glib.h>
+#include <glib-object.h>
+#include <glib/gstdio.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
void test_mainloop_quit (void);
void test_mainloop_run (int timeout);
GMainLoop* test_mainloop_get (void);
+gchar* test_build_filename (const gchar *basename);
+
#define DECLARE_SETUP(x) \
void setup_##x(int *v, gconstpointer d)
#define DEFINE_SETUP(x) \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]