[gnome-keyring/trust-store: 7/7] [gcr] Implement gcr_trust_xxx() functions.



commit 62f95ff4566d353d8bc94e10c40d39cf5c095c7c
Author: Stef Walter <stef memberwebs com>
Date:   Sat Sep 18 17:20:23 2010 +0000

    [gcr] Implement gcr_trust_xxx() functions.
    
    For looking up certificate trust exceptions and trust roots.
    We do not do trust chains or verification. We provide access to trust
    storage.

 gcr/Makefile.am        |    2 +
 gcr/gcr-internal.h     |   12 +
 gcr/gcr-library.c      |   55 +++++
 gcr/gcr-trust.c        |  579 ++++++++++++++++++++++++++++++++++++++++++++++++
 gcr/gcr-trust.h        |   93 ++++++++
 gcr/gcr-types.h        |    4 +
 gcr/gcr.h              |    2 +
 gcr/gkm-test.c         |   60 +++++
 gcr/gkm-test.h         |   62 +++++
 gcr/tests/Makefile.am  |    1 +
 gcr/tests/test-trust.c |  238 ++++++++++++++++++++
 po/POTFILES.in         |    1 +
 12 files changed, 1109 insertions(+), 0 deletions(-)
---
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index b1dcc9f..80492ab 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -22,6 +22,7 @@ inc_HEADERS = \
 	gcr-importer.h \
 	gcr-parser.h \
 	gcr-simple-certificate.h \
+	gcr-trust.h \
 	gcr-types.h \
 	gcr-unlock-options.h \
 	gcr-unlock-options-widget.h
@@ -53,6 +54,7 @@ libgcr GCR_VERSION_SUFFIX@_la_SOURCES = \
 	gcr-library.c \
 	gcr-parser.c gcr-parser.h \
 	gcr-simple-certificate.c gcr-simple-certificate.h \
+	gcr-trust.c gcr-trust.h \
 	gcr-types.h \
 	gcr-unlock-options.h \
 	gcr-unlock-options-widget.c gcr-unlock-options-widget.h \
diff --git a/gcr/gcr-internal.h b/gcr/gcr-internal.h
index a4630ab..ff036ec 100644
--- a/gcr/gcr-internal.h
+++ b/gcr/gcr-internal.h
@@ -5,8 +5,20 @@
 
 #include <glib.h>
 
+#include <gck/gck.h>
+
 void              _gcr_initialize                  (void);
 
 GList*            _gcr_get_pkcs11_modules          (void);
 
+GckSlot*          _gcr_slot_for_storing_trust      (GError **error);
+
+#ifdef WITH_TESTS
+
+void              _gcr_set_test_pkcs11_modules     (GList *modules);
+
+void              _gcr_set_test_trust_slot         (const gchar *uri);
+
+#endif
+
 #endif /* GCR_INTERNAL_H_ */
diff --git a/gcr/gcr-library.c b/gcr/gcr-library.c
index 4317426..54557c0 100644
--- a/gcr/gcr-library.c
+++ b/gcr/gcr-library.c
@@ -33,7 +33,10 @@
 
 #include <gcrypt.h>
 
+#include <glib/gi18n-lib.h>
+
 static GList *all_modules = NULL;
+static const gchar *trust_slot_uri = "pkcs11:manufacturer=Gnome%20Keyring;serial=1:XDG:DEFAULT";
 
 GQuark
 gcr_data_error_get_domain (void)
@@ -44,6 +47,15 @@ gcr_data_error_get_domain (void)
 	return domain;
 }
 
+GQuark
+gcr_error_get_domain (void)
+{
+	static GQuark domain = 0;
+	if (domain == 0)
+		domain = g_quark_from_static_string ("gcr-error");
+	return domain;
+}
+
 /* -----------------------------------------------------------------------------
  * MEMORY
  */
@@ -129,3 +141,46 @@ _gcr_get_pkcs11_modules (void)
 {
 	return all_modules;
 }
+
+GckSlot*
+_gcr_slot_for_storing_trust (GError **error)
+{
+	GList *modules;
+	GckSlot *slot;
+
+	modules = _gcr_get_pkcs11_modules ();
+
+	/*
+	 * TODO: We need a better way to figure this out as far as
+	 * being able to store trust. But for now just hard code in
+	 * gnome-keyring.
+	 */
+
+	slot = gck_modules_token_for_uri (modules, trust_slot_uri, error);
+	if (!slot) {
+		if (error && !*error) {
+			g_set_error (error, GCR_ERROR, /* TODO: */ 0,
+			             _("Unable to find a place to store trust choices."));
+		}
+	}
+
+	return slot;
+}
+
+#ifdef WITH_TESTS
+
+void
+_gcr_set_test_pkcs11_modules (GList *modules)
+{
+	modules = gck_list_ref_copy (modules);
+	gck_list_unref_free (all_modules);
+	all_modules = modules;
+}
+
+void
+_gcr_set_test_trust_slot (const gchar *uri)
+{
+	trust_slot_uri = uri;
+}
+
+#endif /* WITH_TESTS */
diff --git a/gcr/gcr-trust.c b/gcr/gcr-trust.c
new file mode 100644
index 0000000..947fb71
--- /dev/null
+++ b/gcr/gcr-trust.c
@@ -0,0 +1,579 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 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 "gcr.h"
+#include "gcr-types.h"
+#include "gcr-internal.h"
+#include "gcr-trust.h"
+
+#include <gck/gck.h>
+
+#include <pkcs11/pkcs11n.h>
+
+/* ----------------------------------------------------------------------------------
+ * HELPERS
+ */
+
+typedef struct _GcrTrustOperation {
+	GckEnumerator *en;
+	GckAttributes *attrs;
+	GcrPurpose purpose;
+	GcrTrust trust;
+} GcrTrustOperation;
+
+static CK_ATTRIBUTE_TYPE
+attribute_type_for_purpose (GcrPurpose purpose)
+{
+	switch (purpose) {
+	case GCR_PURPOSE_SERVER_AUTH:
+		return CKA_TRUST_SERVER_AUTH;
+	case GCR_PURPOSE_CLIENT_AUTH:
+		return CKA_TRUST_CLIENT_AUTH;
+	case GCR_PURPOSE_CODE_SIGNING:
+		return CKA_TRUST_CODE_SIGNING;
+	case GCR_PURPOSE_EMAIL:
+		return CKA_TRUST_EMAIL_PROTECTION;
+	case GCR_PURPOSE_TIME_STAMPING:
+		return CKA_TRUST_TIME_STAMPING;
+	case GCR_PURPOSE_IPSEC_ENDPOINT:
+		return CKA_TRUST_IPSEC_END_SYSTEM;
+	case GCR_PURPOSE_IPSEC_TUNNEL:
+		return CKA_TRUST_IPSEC_TUNNEL;
+	case GCR_PURPOSE_IPSEC_USER:
+		return CKA_TRUST_IPSEC_USER;
+	case GCR_PURPOSE_IKE_INTERMEDIATE:
+		g_return_val_if_reached ((CK_ULONG)-1);
+	default:
+		g_return_val_if_reached ((CK_ULONG)-1);
+	};
+}
+
+static void
+trust_operation_free (gpointer data)
+{
+	GcrTrustOperation *op = data;
+	g_assert (data);
+
+	/* No reference held */
+	g_assert (GCK_IS_ENUMERATOR (op->en));
+	op->en = NULL;
+
+	g_assert (op->attrs);
+	gck_attributes_unref (op->attrs);
+	op->attrs = NULL;
+
+	g_slice_free (GcrTrustOperation, op);
+}
+
+static void
+trust_operation_init (GckEnumerator *en, GckAttributes *attrs,
+                      GcrPurpose purpose, GcrTrust trust)
+{
+	GcrTrustOperation *op;
+
+	g_assert (GCK_IS_ENUMERATOR (en));
+	g_assert (!g_object_get_data (G_OBJECT (en), "trust-operation"));
+	g_assert (attrs);
+
+	op = g_slice_new0 (GcrTrustOperation);
+	op->purpose = purpose;
+	op->trust = trust;
+	op->attrs = gck_attributes_ref (attrs);
+
+	/* No reference held, GckEnumerator owns */
+	op->en = en;
+	g_object_set_data_full (G_OBJECT (en), "trust-operation", op, trust_operation_free);
+}
+
+static GcrTrustOperation*
+trust_operation_get (GckEnumerator *en)
+{
+	GcrTrustOperation *op = g_object_get_data (G_OBJECT (en), "trust-operation");
+	g_assert (op);
+	g_assert (op->en == en);
+	return op;
+}
+
+static GckAttributes*
+prepare_trust_attrs (GcrCertificate *cert)
+{
+	GckAttributes *attrs;
+	gpointer data;
+	gsize n_data;
+
+	attrs = gck_attributes_new ();
+	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_NETSCAPE_TRUST);
+
+	data = gcr_certificate_get_issuer_raw (cert, &n_data);
+	g_return_val_if_fail (data, NULL);
+	gck_attributes_add_data (attrs, CKA_ISSUER, data, n_data);
+	g_free (data);
+
+	data = gcr_certificate_get_serial_number (cert, &n_data);
+	g_return_val_if_fail (data, NULL);
+	gck_attributes_add_data (attrs, CKA_SERIAL_NUMBER, data, n_data);
+	g_free (data);
+
+	data = gcr_certificate_get_fingerprint (cert, G_CHECKSUM_SHA1, &n_data);
+	g_return_val_if_fail (data, NULL);
+	gck_attributes_add_data (attrs, CKA_CERT_SHA1_HASH, data, n_data);
+	g_free (data);
+
+	return attrs;
+}
+
+/* ----------------------------------------------------------------------------------
+ * GET CERTIFICATE EXCEPTION
+ */
+
+static GckEnumerator*
+prepare_get_certificate_exception (GcrCertificate *cert, GcrPurpose purpose)
+{
+	GckAttributes *attrs;
+	GckEnumerator *en;
+	GList *modules;
+
+	modules = _gcr_get_pkcs11_modules ();
+
+	attrs = prepare_trust_attrs (cert);
+	g_return_val_if_fail (attrs, NULL);
+
+	/*
+	 * TODO: We need to be able to sort the modules by preference
+	 * on which sources of trust storage we want to read over which
+	 * others.
+	 */
+
+	en = gck_modules_enumerate_objects (modules, attrs, 0);
+	trust_operation_init (en, attrs, purpose, GCR_TRUST_UNKNOWN);
+	gck_attributes_unref (attrs);
+
+	return en;
+}
+
+static GcrTrust
+perform_get_certificate_exception (GckEnumerator *en, GCancellable *cancel, GError **error)
+{
+	CK_ATTRIBUTE_TYPE type;
+	GcrTrustOperation *op;
+	GckObject *object;
+	gpointer data;
+	gsize n_data;
+	gulong value;
+
+	op = trust_operation_get (en);
+
+	g_assert (op != NULL);
+	g_assert (op->trust == GCR_TRUST_UNKNOWN);
+
+	type = attribute_type_for_purpose (op->purpose);
+
+	while (op->trust == GCR_TRUST_UNKNOWN) {
+		object = gck_enumerator_next (en, cancel, error);
+		if (!object)
+			break;
+
+		data = gck_object_get_data (object, type, &n_data, error);
+
+		g_object_unref (object);
+
+		if (!data)
+			break;
+
+		if (!gck_value_to_ulong (data, n_data, &value)) {
+			g_message ("an invalid sized value was received for trust attribute");
+			value = CKT_NETSCAPE_TRUST_UNKNOWN;
+		}
+
+		if (value == CKT_NETSCAPE_TRUSTED)
+			op->trust = GCR_TRUST_TRUSTED;
+		else if (value == CKT_NETSCAPE_UNTRUSTED)
+			op->trust = GCR_TRUST_UNTRUSTED;
+
+		g_free (data);
+	}
+
+	return op->trust;
+}
+
+GcrTrust
+gcr_trust_get_certificate_exception (GcrCertificate *cert, GcrPurpose purpose,
+                                     GCancellable *cancel, GError **error)
+{
+	GckEnumerator *en;
+	GcrTrust trust;
+
+	en = prepare_get_certificate_exception (cert, purpose);
+	g_return_val_if_fail (en, GCR_TRUST_UNKNOWN);
+
+	trust = perform_get_certificate_exception (en, cancel, error);
+
+	g_object_unref (en);
+
+	return trust;
+}
+
+static void
+thread_get_certificate_exception (GSimpleAsyncResult *res, GObject *object, GCancellable *cancel)
+{
+	GError *error = NULL;
+
+	perform_get_certificate_exception (GCK_ENUMERATOR (object), cancel, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (res, error);
+		g_clear_error (&error);
+	}
+}
+
+void
+gcr_trust_get_certificate_exception_async (GcrCertificate *cert, GcrPurpose purpose,
+                                           GCancellable *cancel, GAsyncReadyCallback callback,
+                                           gpointer user_data)
+{
+	GSimpleAsyncResult *async;
+	GckEnumerator *en;
+
+	en = prepare_get_certificate_exception (cert, purpose);
+	g_return_if_fail (en);
+
+	async = g_simple_async_result_new (G_OBJECT (en), callback, user_data,
+	                                   gcr_trust_get_certificate_exception_async);
+
+	g_simple_async_result_run_in_thread (async, thread_get_certificate_exception,
+	                                     G_PRIORITY_DEFAULT, cancel);
+
+	g_object_unref (async);
+	g_object_unref (en);
+}
+
+GcrTrust
+gcr_trust_get_certificate_exception_finish (GAsyncResult *res, GError **error)
+{
+	GcrTrustOperation *op;
+	GObject *object;
+
+	object = g_async_result_get_source_object (res);
+	g_return_val_if_fail (g_simple_async_result_is_valid (res, object,
+	                      gcr_trust_get_certificate_exception_async), GCR_TRUST_UNKNOWN);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+		return GCR_TRUST_UNKNOWN;
+
+	op = trust_operation_get (GCK_ENUMERATOR (object));
+	return op->trust;
+}
+
+/* ----------------------------------------------------------------------------------
+ * SET CERTIFICATE EXCEPTION
+ */
+
+static GckEnumerator*
+prepare_set_certificate_exception (GcrCertificate *cert, GcrPurpose purpose, GcrTrust trust)
+{
+	GckAttributes *attrs;
+	GckEnumerator *en;
+	GList *modules;
+
+	modules = _gcr_get_pkcs11_modules ();
+
+	attrs = prepare_trust_attrs (cert);
+	g_return_val_if_fail (attrs, NULL);
+
+	gck_attributes_add_boolean (attrs, CKA_MODIFIABLE, TRUE);
+	gck_attributes_add_boolean (attrs, CKA_TOKEN, TRUE);
+
+	/*
+	 * TODO: We need to be able to sort the modules by preference
+	 * on which sources of trust storage we want to read over which
+	 * others.
+	 */
+
+	en = gck_modules_enumerate_objects (modules, attrs, CKF_RW_SESSION);
+	trust_operation_init (en, attrs, purpose, trust);
+	gck_attributes_unref (attrs);
+
+	return en;
+}
+
+static gboolean
+perform_set_certificate_exception (GckEnumerator *en, GCancellable *cancel, GError **error)
+{
+	CK_ATTRIBUTE_TYPE type;
+	GcrTrustOperation *op;
+	GckAttributes *attrs;
+	gboolean ret = FALSE;
+	GError *lerr = NULL;
+	GckObject *object;
+	GckSession *session;
+	gulong value;
+	GckSlot *slot;
+
+	op = trust_operation_get (en);
+	g_assert (op != NULL);
+
+	/* We need an error below */
+	if (error && !*error)
+		*error = lerr;
+
+	switch (op->trust) {
+	case GCR_TRUST_UNKNOWN:
+		value = CKT_NETSCAPE_TRUST_UNKNOWN;
+		break;
+	case GCR_TRUST_UNTRUSTED:
+		value = CKT_NETSCAPE_UNTRUSTED;
+		break;
+	case GCR_TRUST_TRUSTED:
+		value = CKT_NETSCAPE_TRUSTED;
+		break;
+	}
+
+	type = attribute_type_for_purpose (op->purpose);
+	attrs = gck_attributes_new ();
+
+	object = gck_enumerator_next (en, cancel, error);
+
+	/* Only set this one attribute */
+	if (object) {
+
+		gck_attributes_add_ulong (attrs, type, value);
+		ret = gck_object_set (object, attrs, cancel, error);
+
+	/* Use all trust attributes to create trust object */
+	} else if (!*error) {
+
+		gck_attributes_add_all (attrs, op->attrs);
+		gck_attributes_add_ulong (attrs, type, value);
+
+		/* Find an appropriate token */
+		slot = _gcr_slot_for_storing_trust (error);
+		if (slot != NULL) {
+			session = gck_slot_open_session (slot, CKF_RW_SESSION, error);
+			if (session != NULL) {
+
+				object = gck_session_create_object (session, attrs, cancel, error);
+				if (object != NULL) {
+					g_object_unref (object);
+					ret = TRUE;
+				}
+
+				g_object_unref (session);
+			}
+
+		}
+
+		g_object_unref (slot);
+	}
+
+	gck_attributes_unref (attrs);
+
+	/* Our own local error pointer */
+	g_clear_error (&lerr);
+
+	return ret;
+}
+
+gboolean
+gcr_trust_set_certificate_exception (GcrCertificate *cert, GcrPurpose purpose, GcrTrust trust,
+                                     GCancellable *cancel, GError **error)
+{
+	GckEnumerator *en;
+	gboolean ret;
+
+	en = prepare_set_certificate_exception (cert, purpose, trust);
+	g_return_val_if_fail (en, FALSE);
+
+	ret = perform_set_certificate_exception (en, cancel, error);
+
+	g_object_unref (en);
+
+	return ret;
+}
+
+static void
+thread_set_certificate_exception (GSimpleAsyncResult *res, GObject *object, GCancellable *cancel)
+{
+	GError *error = NULL;
+
+	perform_set_certificate_exception (GCK_ENUMERATOR (object), cancel, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (res, error);
+		g_clear_error (&error);
+	}
+}
+
+void
+gcr_trust_set_certificate_exception_async (GcrCertificate *cert, GcrPurpose purpose,
+                                           GcrTrust trust, GCancellable *cancel,
+                                           GAsyncReadyCallback callback, gpointer user_data)
+{
+	GSimpleAsyncResult *async;
+	GckEnumerator *en;
+
+	en = prepare_set_certificate_exception (cert, purpose, trust);
+	g_return_if_fail (en);
+
+	async = g_simple_async_result_new (G_OBJECT (en), callback, user_data,
+	                                   gcr_trust_set_certificate_exception_async);
+
+	g_simple_async_result_run_in_thread (async, thread_set_certificate_exception,
+	                                     G_PRIORITY_DEFAULT, cancel);
+
+	g_object_unref (async);
+	g_object_unref (en);
+}
+
+gboolean
+gcr_trust_set_certificate_exception_finish (GAsyncResult *res, GError **error)
+{
+	GObject *object;
+
+	object = g_async_result_get_source_object (res);
+	g_return_val_if_fail (g_simple_async_result_is_valid (res, object,
+	                      gcr_trust_set_certificate_exception_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+		return FALSE;
+
+	return TRUE;
+}
+
+/* ----------------------------------------------------------------------------------
+ * CERTIFICATE ROOT
+ */
+
+static GckEnumerator*
+prepare_is_certificate_root (GcrCertificate *cert, GcrPurpose purpose)
+{
+	GckAttributes *attrs;
+	GckEnumerator *en;
+	GList *modules;
+
+	modules = _gcr_get_pkcs11_modules ();
+
+	attrs = prepare_trust_attrs (cert);
+	g_return_val_if_fail (attrs, NULL);
+
+	gck_attributes_add_ulong (attrs, attribute_type_for_purpose (purpose),
+	                          CKT_NETSCAPE_TRUSTED_DELEGATOR);
+
+	/*
+	 * TODO: We need to be able to sort the modules by preference
+	 * on which sources of trust storage we want to read over which
+	 * others.
+	 */
+
+	en = gck_modules_enumerate_objects (modules, attrs, CKF_RW_SESSION);
+	trust_operation_init (en, attrs, purpose, GCR_TRUST_UNKNOWN);
+	gck_attributes_unref (attrs);
+
+	return en;
+}
+
+static gboolean
+perform_is_certificate_root (GckEnumerator *en, GCancellable *cancel, GError **error)
+{
+	GcrTrustOperation *op;
+	GckObject *object;
+
+	op = trust_operation_get (en);
+	g_assert (op != NULL);
+
+	object = gck_enumerator_next (en, cancel, error);
+	if (object != NULL) {
+		op->trust = GCR_TRUST_TRUSTED;
+		g_object_unref (object);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+gboolean
+gcr_trust_is_certificate_root (GcrCertificate *cert, GcrPurpose purpose,
+                               GCancellable *cancel, GError **error)
+{
+	GckEnumerator *en;
+	gboolean ret;
+
+	en = prepare_is_certificate_root (cert, purpose);
+	g_return_val_if_fail (en, FALSE);
+
+	ret = perform_is_certificate_root (en, cancel, error);
+
+	g_object_unref (en);
+
+	return ret;
+}
+
+static void
+thread_is_certificate_root (GSimpleAsyncResult *res, GObject *object, GCancellable *cancel)
+{
+	GError *error = NULL;
+
+	perform_is_certificate_root (GCK_ENUMERATOR (object), cancel, &error);
+
+	if (error != NULL) {
+		g_simple_async_result_set_from_error (res, error);
+		g_clear_error (&error);
+	}
+}
+
+void
+gcr_trust_is_certificate_root_async (GcrCertificate *cert, GcrPurpose purpose,
+                                     GCancellable *cancel, GAsyncReadyCallback callback,
+                                     gpointer user_data)
+{
+	GSimpleAsyncResult *async;
+	GckEnumerator *en;
+
+	en = prepare_is_certificate_root (cert, purpose);
+	g_return_if_fail (en);
+
+	async = g_simple_async_result_new (G_OBJECT (en), callback, user_data,
+	                                   gcr_trust_is_certificate_root_async);
+
+	g_simple_async_result_run_in_thread (async, thread_is_certificate_root,
+	                                     G_PRIORITY_DEFAULT, cancel);
+
+	g_object_unref (async);
+	g_object_unref (en);
+}
+
+gboolean
+gcr_trust_is_certificate_root_finish (GAsyncResult *res, GError **error)
+{
+	GcrTrustOperation *op;
+	GObject *object;
+
+	object = g_async_result_get_source_object (res);
+	g_return_val_if_fail (g_simple_async_result_is_valid (res, object,
+	                      gcr_trust_is_certificate_root_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error))
+		return FALSE;
+
+	op = trust_operation_get (GCK_ENUMERATOR (object));
+	return op->trust == GCR_TRUST_TRUSTED;
+}
diff --git a/gcr/gcr-trust.h b/gcr/gcr-trust.h
new file mode 100644
index 0000000..89902fa
--- /dev/null
+++ b/gcr/gcr-trust.h
@@ -0,0 +1,93 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 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 __GCR_TRUST_H__
+#define __GCR_TRUST_H__
+
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+typedef enum _GcrTrust {
+	GCR_TRUST_UNTRUSTED = -1,
+	GCR_TRUST_UNKNOWN = 0,
+	GCR_TRUST_TRUSTED,
+} GcrTrust;
+
+typedef enum _GcrPurpose {
+	GCR_PURPOSE_SERVER_AUTH = 1,
+	GCR_PURPOSE_CLIENT_AUTH,
+	GCR_PURPOSE_CODE_SIGNING,
+	GCR_PURPOSE_EMAIL,
+	GCR_PURPOSE_TIME_STAMPING,
+	GCR_PURPOSE_IPSEC_ENDPOINT,
+	GCR_PURPOSE_IPSEC_TUNNEL,
+	GCR_PURPOSE_IPSEC_USER,
+	GCR_PURPOSE_IKE_INTERMEDIATE,
+} GcrPurpose;
+
+GcrTrust       gcr_trust_get_certificate_exception          (GcrCertificate *cert,
+                                                             GcrPurpose purpose,
+                                                             GCancellable *cancel,
+                                                             GError **error);
+
+void           gcr_trust_get_certificate_exception_async    (GcrCertificate *cert,
+                                                             GcrPurpose purpose,
+                                                             GCancellable *cancel,
+                                                             GAsyncReadyCallback callback,
+                                                             gpointer user_data);
+
+GcrTrust       gcr_trust_get_certificate_exception_finish   (GAsyncResult *res,
+                                                             GError **error);
+
+gboolean       gcr_trust_set_certificate_exception          (GcrCertificate *cert,
+                                                             GcrPurpose purpose,
+                                                             GcrTrust trust,
+                                                             GCancellable *cancel,
+                                                             GError **error);
+
+void           gcr_trust_set_certificate_exception_async    (GcrCertificate *cert,
+                                                             GcrPurpose purpose,
+                                                             GcrTrust trust,
+                                                             GCancellable *cancel,
+                                                             GAsyncReadyCallback callback,
+                                                             gpointer user_data);
+
+gboolean       gcr_trust_set_certificate_exception_finish   (GAsyncResult *res,
+                                                             GError **error);
+
+gboolean       gcr_trust_is_certificate_root                (GcrCertificate *cert,
+                                                             GcrPurpose purpose,
+                                                             GCancellable *cancel,
+                                                             GError **error);
+
+void           gcr_trust_is_certificate_root_async          (GcrCertificate *cert,
+                                                             GcrPurpose purpose,
+                                                             GCancellable *cancel,
+                                                             GAsyncReadyCallback callback,
+                                                             gpointer user_data);
+
+gboolean       gcr_trust_is_certificate_root_finish         (GAsyncResult *res,
+                                                             GError **error);
+
+G_END_DECLS
+
+#endif /* __GCR_TOKEN_MANAGER_H__ */
diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h
index 3051ff5..6d7decc 100644
--- a/gcr/gcr-types.h
+++ b/gcr/gcr-types.h
@@ -20,6 +20,10 @@ enum {
 	GCR_ERROR_LOCKED = 3
 };
 
+#define             GCR_ERROR                    (gcr_error_get_domain ())
+
+GQuark 	            gcr_error_get_domain         (void) G_GNUC_CONST;
+
 enum {
 	GCR_FORMAT_INVALID = 0,
 	
diff --git a/gcr/gcr.h b/gcr/gcr.h
index 49efed3..c150a34 100644
--- a/gcr/gcr.h
+++ b/gcr/gcr.h
@@ -29,6 +29,8 @@
 #include "gcr-certificate-details-widget.h"
 #include "gcr-importer.h"
 #include "gcr-parser.h"
+#include "gcr-simple-certificate.h"
+#include "gcr-trust.h"
 #include "gcr-types.h"
 
 #endif /* __GCR_H__ */
diff --git a/gcr/gkm-test.c b/gcr/gkm-test.c
new file mode 100644
index 0000000..3e268ac
--- /dev/null
+++ b/gcr/gkm-test.c
@@ -0,0 +1,60 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 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 "gkm-attributes.h"
+#include "gkm-test.h"
+#include "gkm-util.h"
+
+#include "pkcs11/pkcs11.h"
+#include "pkcs11/pkcs11i.h"
+
+#include <glib.h>
+
+#include <string.h>
+
+void
+gkm_assertion_message_cmprv (const gchar *domain, const gchar *file, gint line,
+                             const gchar *func, const gchar *expr,
+                             CK_RV arg1, const gchar *cmp, CK_RV arg2)
+{
+	gchar *a1, *a2, *s;
+	a1 = gkm_util_rv_to_string (arg1);
+	a2 = gkm_util_rv_to_string (arg2);
+	s = g_strdup_printf ("assertion failed (%s): (%s %s %s)", expr, a1, cmp, a2);
+	g_free (a1);
+	g_free (a2);
+	g_assertion_message (domain, file, line, func, s);
+	g_free (s);
+}
+
+void
+gkm_assertion_message_cmpulong (const gchar *domain, const gchar *file, gint line,
+                                const gchar *func, const gchar *expr,
+                                CK_ULONG arg1, const gchar *cmp, CK_ULONG arg2)
+{
+	char *s = NULL;
+	s = g_strdup_printf ("assertion failed (%s): (0x%08llx %s 0x%08llx)", expr,
+	                     (long long unsigned)arg1, cmp, (long long unsigned)arg2);
+	g_assertion_message (domain, file, line, func, s);
+	g_free (s);
+}
diff --git a/gcr/gkm-test.h b/gcr/gkm-test.h
new file mode 100644
index 0000000..97cc078
--- /dev/null
+++ b/gcr/gkm-test.h
@@ -0,0 +1,62 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 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 <glib.h>
+
+#include "pkcs11/pkcs11.h"
+#include "pkcs11/pkcs11i.h"
+
+#ifndef GKM_TEST_H
+#define GKM_TEST_H
+
+#define         gkm_assert_cmprv(v1, cmp, v2) \
+		do { CK_RV __v1 = (v1), __v2 = (v2); \
+			if (__v1 cmp __v2) ; else \
+				gkm_assertion_message_cmprv (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+				                             #v1 " " #cmp " " #v2, __v1, #cmp, __v2); \
+		} while (0)
+
+#define         gkm_assert_cmpulong(v1, cmp, v2) \
+		do { CK_RV __v1 = (v1), __v2 = (v2); \
+			if (__v1 cmp __v2) ; else \
+				gkm_assertion_message_cmpulong (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
+				                                #v1 " " #cmp " " #v2, __v1, #cmp, __v2); \
+		} while (0)
+
+void            gkm_assertion_message_cmprv        (const gchar *domain,
+                                                    const gchar *file,
+                                                    int line,
+                                                    const gchar *func,
+                                                    const gchar *expr,
+                                                    CK_RV arg1,
+                                                    const gchar *cmp,
+                                                    CK_RV arg2);
+
+void            gkm_assertion_message_cmpulong     (const gchar *domain,
+                                                    const gchar *file,
+                                                    gint line,
+                                                    const gchar *func,
+                                                    const gchar *expr,
+                                                    CK_ULONG arg1,
+                                                    const gchar *cmp,
+                                                    CK_ULONG arg2);
+
+#endif /* GKM_TEST_H */
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index 22295ad..d6d1839 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -2,6 +2,7 @@
 # Test files should be listed in order they need to run
 TESTING_FILES = \
 	unit-test-certificate.c \
+	test-trust.c \
 	unit-test-parser.c
 
 TESTING_LIBS =  \
diff --git a/gcr/tests/test-trust.c b/gcr/tests/test-trust.c
new file mode 100644
index 0000000..f97f009
--- /dev/null
+++ b/gcr/tests/test-trust.c
@@ -0,0 +1,238 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+   Copyright (C) 2010 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "test-suite.h"
+
+#include "gcr.h"
+#include "gcr/gcr-internal.h"
+
+#include "gck/gck-mock.h"
+#include "gck/gck-test.h"
+
+#include "pkcs11/pkcs11n.h"
+
+#include <glib.h>
+
+static CK_FUNCTION_LIST_PTR funcs;
+static GList *modules = NULL;
+static GcrCertificate *certificate = NULL;
+
+DEFINE_SETUP (trust_setup)
+{
+	GckModule *module;
+	guchar *contents;
+	gsize len;
+	CK_RV rv;
+
+	contents = testing_data_read ("der-certificate.crt", &len);
+	g_assert (contents);
+
+	certificate = gcr_simple_certificate_new (contents, len);
+
+	rv = gck_mock_C_GetFunctionList (&funcs);
+	gck_assert_cmprv (rv, ==, CKR_OK);
+
+	/* Open a session */
+	rv = (funcs->C_Initialize) (NULL);
+	gck_assert_cmprv (rv, ==, CKR_OK);
+
+	g_assert (!modules);
+	module = gck_module_new (funcs, 0);
+	modules = g_list_prepend (modules, module);
+
+	_gcr_set_test_pkcs11_modules (modules);
+	_gcr_set_test_trust_slot (GCK_MOCK_SLOT_ONE_URI);
+}
+
+DEFINE_TEARDOWN (trust_setup)
+{
+	CK_RV rv;
+
+	g_object_unref (certificate);
+	certificate = NULL;
+
+	g_assert (funcs);
+	rv = (funcs->C_Finalize) (NULL);
+	gck_assert_cmprv (rv, ==, CKR_OK);
+
+	gck_list_unref_free (modules);
+	modules = NULL;
+}
+
+DEFINE_TEST (trust_get_exception_none)
+{
+	GError *error = NULL;
+	GcrTrust trust;
+
+	trust = gcr_trust_get_certificate_exception (certificate, GCR_PURPOSE_EMAIL, NULL, &error);
+	g_assert_cmpint (trust, ==, GCR_TRUST_UNKNOWN);
+	g_assert (error == NULL);
+}
+
+DEFINE_TEST (trust_set_and_get_exception)
+{
+	GError *error = NULL;
+	GcrTrust trust;
+	gboolean ret;
+
+	trust = gcr_trust_get_certificate_exception (certificate, GCR_PURPOSE_EMAIL, NULL, &error);
+	g_assert_cmpint (trust, ==, GCR_TRUST_UNKNOWN);
+	g_assert (error == NULL);
+
+	ret = gcr_trust_set_certificate_exception (certificate, GCR_PURPOSE_EMAIL,
+	                                           GCR_TRUST_TRUSTED, NULL, &error);
+	g_assert (ret == TRUE);
+	g_assert (error == NULL);
+
+	trust = gcr_trust_get_certificate_exception (certificate, GCR_PURPOSE_EMAIL, NULL, &error);
+	g_assert_cmpint (trust, ==, GCR_TRUST_TRUSTED);
+	g_assert (error == NULL);
+}
+
+DEFINE_TEST (trust_set_and_override_exception)
+{
+	GError *error = NULL;
+	GcrTrust trust;
+	gboolean ret;
+
+	ret = gcr_trust_set_certificate_exception (certificate, GCR_PURPOSE_EMAIL,
+	                                           GCR_TRUST_TRUSTED, NULL, &error);
+	g_assert (ret == TRUE);
+	g_assert (error == NULL);
+
+	trust = gcr_trust_get_certificate_exception (certificate, GCR_PURPOSE_EMAIL, NULL, &error);
+	g_assert_cmpint (trust, ==, GCR_TRUST_TRUSTED);
+	g_assert (error == NULL);
+
+	ret = gcr_trust_set_certificate_exception (certificate, GCR_PURPOSE_EMAIL,
+	                                           GCR_TRUST_UNTRUSTED, NULL, &error);
+	g_assert (ret == TRUE);
+	g_assert (error == NULL);
+
+	trust = gcr_trust_get_certificate_exception (certificate, GCR_PURPOSE_EMAIL, NULL, &error);
+	g_assert_cmpint (trust, ==, GCR_TRUST_UNTRUSTED);
+	g_assert (error == NULL);
+}
+
+static void
+fetch_async_result (GObject *source, GAsyncResult *result, gpointer user_data)
+{
+	*((GAsyncResult**)user_data) = result;
+	g_object_ref (result);
+	testing_wait_stop ();
+}
+
+DEFINE_TEST (trust_set_and_get_exception_async)
+{
+	GAsyncResult *result = NULL;
+	GError *error = NULL;
+	GcrTrust trust;
+	gboolean ret;
+
+	gcr_trust_get_certificate_exception_async (certificate, GCR_PURPOSE_EMAIL, NULL, fetch_async_result, &result);
+	testing_wait_until (500);
+	g_assert (result);
+	trust = gcr_trust_get_certificate_exception_finish (result, &error);
+	g_assert (trust == GCR_TRUST_UNKNOWN);
+	g_assert (error == NULL);
+	g_object_unref (result);
+	result = NULL;
+
+	gcr_trust_set_certificate_exception_async (certificate, GCR_PURPOSE_EMAIL, GCR_TRUST_TRUSTED,
+	                                           NULL, fetch_async_result, &result);
+	testing_wait_until (500);
+	g_assert (result);
+	ret = gcr_trust_set_certificate_exception_finish (result, &error);
+	g_assert (ret == TRUE);
+	g_assert (error == NULL);
+	g_object_unref (result);
+	result = NULL;
+
+	gcr_trust_get_certificate_exception_async (certificate, GCR_PURPOSE_EMAIL, NULL, fetch_async_result, &result);
+	testing_wait_until (500);
+	g_assert (result);
+	trust = gcr_trust_get_certificate_exception_finish (result, &error);
+	g_assert (trust == GCR_TRUST_TRUSTED);
+	g_assert (error == NULL);
+	g_object_unref (result);
+	result = NULL;
+}
+
+DEFINE_TEST (trust_is_certificate_root_not)
+{
+	GError *error = NULL;
+	gboolean ret;
+
+	ret = gcr_trust_is_certificate_root (certificate, GCR_PURPOSE_CLIENT_AUTH, NULL, &error);
+	g_assert (ret == FALSE);
+	g_assert (error == NULL);
+}
+
+DEFINE_TEST (trust_is_certificate_root_yes)
+{
+	GError *error = NULL;
+	GckAttributes *attrs;
+	gpointer data;
+	gsize n_data;
+	gboolean ret;
+
+	/* Create a certificate root trust */
+	attrs = gck_attributes_new ();
+	data = gcr_certificate_get_issuer_raw (certificate, &n_data);
+	g_assert (data && n_data);
+	gck_attributes_add_data (attrs, CKA_ISSUER, data, n_data);
+	g_free (data);
+	data = gcr_certificate_get_serial_number (certificate, &n_data);
+	g_assert (data && n_data);
+	gck_attributes_add_data (attrs, CKA_SERIAL_NUMBER, data, n_data);
+	g_free (data);
+	data = gcr_certificate_get_fingerprint (certificate, G_CHECKSUM_SHA1, &n_data);
+	g_assert (data);
+	gck_attributes_add_data (attrs, CKA_CERT_SHA1_HASH, data, n_data);
+	g_free (data);
+	gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_NETSCAPE_TRUST);
+	gck_attributes_add_ulong (attrs, CKA_TRUST_CLIENT_AUTH, CKT_NETSCAPE_TRUSTED_DELEGATOR);
+	gck_mock_module_take_object (attrs);
+
+	ret = gcr_trust_is_certificate_root (certificate, GCR_PURPOSE_CLIENT_AUTH, NULL, &error);
+	g_assert (ret == TRUE);
+	g_assert (error == NULL);
+}
+
+DEFINE_TEST (trust_is_certificate_root_async)
+{
+	GAsyncResult *result = NULL;
+	GError *error = NULL;
+	gboolean ret;
+
+	gcr_trust_is_certificate_root_async (certificate, GCR_PURPOSE_CLIENT_AUTH, NULL, fetch_async_result, &result);
+	testing_wait_until (500);
+	g_assert (result);
+
+	ret = gcr_trust_is_certificate_root_finish (result, &error);
+	g_assert (ret == FALSE);
+	g_assert (error == NULL);
+
+	g_object_unref (result);
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 5fbcfda..8dcd2e5 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -18,6 +18,7 @@ gcr/gcr-certificate-details-widget.c
 [type: gettext/glade]gcr/gcr-import-dialog.ui
 [type: gettext/glade]gcr/gcr-unlock-options-widget.ui
 gcr/gcr-importer.c
+gcr/gcr-library.c
 gcr/gcr-parser.c
 gp11/gp11-misc.c
 gck/gck-uri.c



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