[gcr] gcr: Support plain RSA signing



commit df77f1b4561671791b535a89d3f39c7ded35b1e1
Author: Stef Walter <stefw collabora co uk>
Date:   Wed Nov 23 18:13:07 2011 +0100

    gcr: Support plain RSA signing
    
     * And detect the mechanisms supported on a given key.

 gcr/Makefile.am                      |    1 +
 gcr/gcr-certificate-request.c        |  243 ++++++++++++++++++++++++++++++----
 gcr/gcr-certificate-request.h        |   13 ++
 gcr/gcr-key-mechanisms.c             |  222 +++++++++++++++++++++++++++++++
 gcr/gcr-key-mechanisms.h             |   56 ++++++++
 gcr/tests/frob-certificate-request.c |    9 ++
 6 files changed, 515 insertions(+), 29 deletions(-)
---
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index 13db5ed..7710662 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -115,6 +115,7 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
 	gcr-importer.c gcr-importer.h \
 	gcr-import-interaction.c gcr-import-interaction.h \
 	gcr-internal.h \
+	gcr-key-mechanisms.h gcr-key-mechanisms.c \
 	gcr-library.c gcr-library.h \
 	gcr-memory.c \
 	gcr-memory-icon.c gcr-memory-icon.h \
diff --git a/gcr/gcr-certificate-request.c b/gcr/gcr-certificate-request.c
index 477c443..310736a 100644
--- a/gcr/gcr-certificate-request.c
+++ b/gcr/gcr-certificate-request.c
@@ -22,6 +22,7 @@
 #include "config.h"
 
 #include "gcr-certificate-request.h"
+#include "gcr-key-mechanisms.h"
 #include "gcr-enum-types-base.h"
 #include "gcr-oids.h"
 #include "gcr-subject-public-key.h"
@@ -72,6 +73,8 @@ struct _GcrCertificateRequest {
 
 	GckObject *private_key;
 	GNode *asn;
+	gulong *mechanisms;
+	gulong n_mechanisms;
 };
 
 struct _GcrCertificateRequestClass {
@@ -87,6 +90,27 @@ enum {
 /* Forward declarations */
 G_DEFINE_TYPE (GcrCertificateRequest, gcr_certificate_request, G_TYPE_OBJECT);
 
+/* When updating here, update prepare_to_be_signed() */
+static const gulong RSA_MECHANISMS[] = {
+	CKM_SHA1_RSA_PKCS,
+	CKM_RSA_PKCS,
+};
+
+/* When updating here, update prepare_to_be_signed() */
+static const gulong DSA_MECHANISMS[] = {
+	CKM_DSA_SHA1,
+	CKM_DSA,
+};
+
+static const gulong ALL_MECHANISMS[] = {
+	CKM_SHA1_RSA_PKCS,
+	CKM_DSA_SHA1,
+	CKM_RSA_PKCS,
+	CKM_DSA,
+};
+
+G_STATIC_ASSERT (sizeof (ALL_MECHANISMS) == sizeof (RSA_MECHANISMS) + sizeof (DSA_MECHANISMS));
+
 static void
 gcr_certificate_request_init (GcrCertificateRequest *self)
 {
@@ -115,6 +139,7 @@ gcr_certificate_request_finalize (GObject *obj)
 	GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
 
 	egg_asn1x_destroy (self->asn);
+	g_free (self->mechanisms);
 
 	G_OBJECT_CLASS (gcr_certificate_request_parent_class)->finalize (obj);
 }
@@ -275,29 +300,101 @@ gcr_certificate_request_set_cn (GcrCertificateRequest *self,
 	egg_dn_add_string_part (dn, GCR_OID_NAME_CN, cn);
 }
 
+static EggBytes *
+hash_sha1_pkcs1 (EggBytes *data)
+{
+	const guchar SHA1_ASN[15] = /* Object ID is 1.3.14.3.2.26 */
+		{ 0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03,
+		  0x02, 0x1a, 0x05, 0x00, 0x04, 0x14 };
+
+	GChecksum *checksum;
+	guchar *hash;
+	gsize n_hash;
+	gsize n_digest;
+
+	n_digest = g_checksum_type_get_length (G_CHECKSUM_SHA1);
+	n_hash = n_digest + sizeof (SHA1_ASN);
+	hash = g_malloc (n_hash);
+	memcpy (hash, SHA1_ASN, sizeof (SHA1_ASN));
+
+	checksum = g_checksum_new (G_CHECKSUM_SHA1);
+	g_checksum_update (checksum, egg_bytes_get_data (data), egg_bytes_get_size (data));
+	g_checksum_get_digest (checksum, hash + sizeof (SHA1_ASN), &n_digest);
+	g_checksum_free (checksum);
+
+	return egg_bytes_new_take (hash, n_hash);
+}
 
 static EggBytes *
-prepare_to_be_signed (GcrCertificateRequest *self)
+hash_sha1 (EggBytes *data)
+{
+	GChecksum *checksum;
+	guchar *hash;
+	gsize n_hash;
+
+	n_hash = g_checksum_type_get_length (G_CHECKSUM_SHA1);
+	hash = g_malloc (n_hash);
+
+	checksum = g_checksum_new (G_CHECKSUM_SHA1);
+	g_checksum_update (checksum, egg_bytes_get_data (data), egg_bytes_get_size (data));
+	g_checksum_get_digest (checksum, hash, &n_hash);
+	g_checksum_free (checksum);
+
+	return egg_bytes_new_take (hash, n_hash);
+}
+
+static EggBytes *
+prepare_to_be_signed (GcrCertificateRequest *self,
+                      GckMechanism *mechanism)
 {
 	GNode *node;
+	EggBytes *data;
+	EggBytes *hash;
+
+	g_assert (mechanism != NULL);
 
 	node = egg_asn1x_node (self->asn, "certificationRequestInfo", NULL);
-	return egg_asn1x_encode (node, NULL);
+	data = egg_asn1x_encode (node, NULL);
+
+	mechanism->parameter = NULL;
+	mechanism->n_parameter = 0;
+
+	switch (mechanism->type) {
+	case CKM_SHA1_RSA_PKCS:
+	case CKM_DSA_SHA1:
+		return data;
+
+	case CKM_RSA_PKCS:
+		hash = hash_sha1_pkcs1 (data);
+		egg_bytes_unref (data);
+		return hash;
+
+	case CKM_DSA:
+		hash = hash_sha1 (data);
+		egg_bytes_unref (data);
+		return hash;
+
+	default:
+		g_assert_not_reached ();
+		return NULL;
+	}
 }
 
 static gboolean
-prepare_subject_public_key_and_mechanism (GcrCertificateRequest *self,
-                                          GNode *subject_public_key,
-                                          GQuark *algorithm,
-                                          GckMechanism *mechanism,
-                                          GError **error)
+prepare_subject_public_key_and_mechanisms (GcrCertificateRequest *self,
+                                           GNode *subject_public_key,
+                                           GQuark *algorithm,
+                                           const gulong **mechanisms,
+                                           gsize *n_mechanisms,
+                                           GError **error)
 {
 	EggBytes *encoded;
 	GNode *node;
 	GQuark oid;
 
 	g_assert (algorithm != NULL);
-	g_assert (mechanism != NULL);
+	g_assert (mechanisms != NULL);
+	g_assert (n_mechanisms != NULL);
 
 	encoded = egg_asn1x_encode (subject_public_key, NULL);
 	g_return_val_if_fail (encoded != NULL, FALSE);
@@ -305,13 +402,14 @@ prepare_subject_public_key_and_mechanism (GcrCertificateRequest *self,
 	node = egg_asn1x_node (subject_public_key, "algorithm", "algorithm", NULL);
 	oid = egg_asn1x_get_oid_as_quark (node);
 
-	memset (mechanism, 0, sizeof (GckMechanism));
 	if (oid == GCR_OID_PKIX1_RSA) {
-		mechanism->type = CKM_SHA1_RSA_PKCS;
+		*mechanisms = RSA_MECHANISMS;
+		*n_mechanisms = G_N_ELEMENTS (RSA_MECHANISMS);
 		*algorithm = GCR_OID_PKIX1_SHA1_WITH_RSA;
 
 	} else if (oid == GCR_OID_PKIX1_DSA) {
-		mechanism->type = CKM_DSA_SHA1;
+		*mechanisms = DSA_MECHANISMS;
+		*n_mechanisms = G_N_ELEMENTS (DSA_MECHANISMS);
 		*algorithm = GCR_OID_PKIX1_SHA1_WITH_DSA;
 
 	} else {
@@ -372,6 +470,8 @@ gcr_certificate_request_complete (GcrCertificateRequest *self,
                                   GError **error)
 {
 	GNode *subject_public_key;
+	const gulong *mechanisms;
+	gsize n_mechanisms;
 	GckMechanism mechanism = { 0, };
 	GQuark algorithm = 0;
 	EggBytes *tbs;
@@ -389,15 +489,27 @@ gcr_certificate_request_complete (GcrCertificateRequest *self,
 	if (subject_public_key == NULL)
 		return FALSE;
 
-	ret = prepare_subject_public_key_and_mechanism (self, subject_public_key,
-	                                                &algorithm, &mechanism, error);
+	ret = prepare_subject_public_key_and_mechanisms (self, subject_public_key,
+	                                                 &algorithm, &mechanisms,
+	                                                 &n_mechanisms, error);
 
 	if (!ret) {
 		egg_asn1x_destroy (subject_public_key);
 		return FALSE;
 	}
 
-	tbs = prepare_to_be_signed (self);
+	/* Figure out which mechanism to use */
+	mechanism.type = _gcr_key_mechanisms_check (self->private_key, mechanisms,
+	                                            n_mechanisms, CKA_SIGN,
+	                                            cancellable, NULL);
+	if (mechanism.type == GCK_INVALID) {
+		egg_asn1x_destroy (subject_public_key);
+		g_set_error (error, GCK_ERROR, CKR_KEY_TYPE_INCONSISTENT,
+		             _("The key cannot be used to sign the request"));
+		return FALSE;
+	}
+
+	tbs = prepare_to_be_signed (self, &mechanism);
 	session = gck_object_get_session (self->private_key);
 	signature = gck_session_sign_full (session, self->private_key, &mechanism,
 	                                   egg_bytes_get_data (tbs),
@@ -452,7 +564,7 @@ on_certificate_request_signed (GObject *source,
 	gsize n_signature;
 
 	signature = gck_session_sign_finish (closure->session, result, &n_signature, &error);
-	if (result == NULL) {
+	if (error == NULL) {
 		encode_take_signature_into_request (closure->request,
 		                                    closure->algorithm,
 		                                    closure->subject_public_key,
@@ -467,21 +579,54 @@ on_certificate_request_signed (GObject *source,
 }
 
 static void
+on_mechanism_check (GObject *source,
+                    GAsyncResult *result,
+                    gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	CompleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+
+	closure->mechanism.type =  _gcr_key_mechanisms_check_finish (closure->request->private_key,
+	                                                             result, NULL);
+	if (closure->mechanism.type == GCK_INVALID) {
+		g_simple_async_result_set_error (res, GCK_ERROR, CKR_KEY_TYPE_INCONSISTENT,
+		                                 _("The key cannot be used to sign the request"));
+		g_simple_async_result_complete (res);
+
+	} else {
+		closure->tbs = prepare_to_be_signed (closure->request, &closure->mechanism);
+		gck_session_sign_async (closure->session,
+		                        closure->request->private_key,
+		                        &closure->mechanism,
+		                        egg_bytes_get_data (closure->tbs),
+		                        egg_bytes_get_size (closure->tbs),
+		                        closure->cancellable,
+		                        on_certificate_request_signed,
+		                        g_object_ref (res));
+	}
+
+	g_object_unref (res);
+}
+
+static void
 on_subject_public_key_loaded (GObject *source,
                               GAsyncResult *result,
                               gpointer user_data)
 {
 	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
 	CompleteClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	const gulong *mechanisms;
+	gsize n_mechanisms;
 	GError *error = NULL;
 
 	closure->subject_public_key = _gcr_subject_public_key_load_finish (result, &error);
 	if (error == NULL) {
-		prepare_subject_public_key_and_mechanism (closure->request,
-		                                          closure->subject_public_key,
-		                                          &closure->algorithm,
-		                                          &closure->mechanism,
-		                                          &error);
+		prepare_subject_public_key_and_mechanisms (closure->request,
+		                                           closure->subject_public_key,
+		                                           &closure->algorithm,
+		                                           &mechanisms,
+		                                           &n_mechanisms,
+		                                           &error);
 	}
 
 	if (error != NULL) {
@@ -489,15 +634,10 @@ on_subject_public_key_loaded (GObject *source,
 		g_simple_async_result_complete (res);
 
 	} else {
-		closure->tbs = prepare_to_be_signed (closure->request);
-		gck_session_sign_async (closure->session,
-		                        closure->request->private_key,
-		                        &closure->mechanism,
-		                        egg_bytes_get_data (closure->tbs),
-		                        egg_bytes_get_size (closure->tbs),
-		                        closure->cancellable,
-		                        on_certificate_request_signed,
-		                        g_object_ref (res));
+		_gcr_key_mechanisms_check_async (closure->request->private_key,
+		                                 mechanisms, n_mechanisms, CKA_SIGN,
+		                                 closure->cancellable, on_mechanism_check,
+		                                 g_object_ref (res));
 	}
 
 	g_object_unref (res);
@@ -621,3 +761,48 @@ gcr_certificate_request_encode (GcrCertificateRequest *self,
 
 	return encoded;
 }
+
+gboolean
+gcr_certificate_request_capable (GckObject *private_key,
+                                 GCancellable *cancellable,
+                                 GError **error)
+{
+	g_return_val_if_fail (GCK_IS_OBJECT (private_key), FALSE);
+	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	return _gcr_key_mechanisms_check (private_key, ALL_MECHANISMS,
+	                                  G_N_ELEMENTS (ALL_MECHANISMS),
+	                                 CKA_SIGN, cancellable, error);
+}
+
+void
+gcr_certificate_request_capable_async (GckObject *private_key,
+                                       GCancellable *cancellable,
+                                       GAsyncReadyCallback callback,
+                                       gpointer user_data)
+{
+	g_return_if_fail (GCK_IS_OBJECT (private_key));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+	_gcr_key_mechanisms_check_async (private_key, ALL_MECHANISMS,
+	                                 G_N_ELEMENTS (ALL_MECHANISMS),
+	                                 CKA_SIGN, cancellable,
+	                                 callback, user_data);
+}
+
+gboolean
+gcr_certificate_request_capable_finish (GAsyncResult *result,
+                                        GError **error)
+{
+	GObject *source;
+	gulong mech;
+
+	g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
+
+	source = g_async_result_get_source_object (result);
+	mech = _gcr_key_mechanisms_check_finish (GCK_OBJECT (source), result, error);
+	g_object_unref (source);
+
+	return mech != GCK_INVALID;
+}
diff --git a/gcr/gcr-certificate-request.h b/gcr/gcr-certificate-request.h
index 53e1284..9081e7c 100644
--- a/gcr/gcr-certificate-request.h
+++ b/gcr/gcr-certificate-request.h
@@ -42,6 +42,19 @@ typedef enum {
 
 typedef struct _GcrCertificateRequest GcrCertificateRequest;
 
+gboolean                     gcr_certificate_request_capable          (GckObject *private_key,
+                                                                       GCancellable *cancellable,
+                                                                       GError **error);
+
+void                         gcr_certificate_request_capable_async    (GckObject *private_key,
+                                                                       GCancellable *cancellable,
+                                                                       GAsyncReadyCallback callback,
+                                                                       gpointer user_data);
+
+
+gboolean                     gcr_certificate_request_capable_finish   (GAsyncResult *result,
+                                                                       GError **error);
+
 GType                        gcr_certificate_request_get_type         (void) G_GNUC_CONST;
 
 GcrCertificateRequest *      gcr_certificate_request_prepare          (GcrCertificateRequestFormat format,
diff --git a/gcr/gcr-key-mechanisms.c b/gcr/gcr-key-mechanisms.c
new file mode 100644
index 0000000..ea2d527
--- /dev/null
+++ b/gcr/gcr-key-mechanisms.c
@@ -0,0 +1,222 @@
+/*
+ * 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"
+
+#define DEBUG_FLAG GCR_DEBUG_KEY
+#include "gcr-debug.h"
+#include "gcr-key-mechanisms.h"
+
+#include <glib/gi18n-lib.h>
+
+static gboolean
+check_have_attributes (GckAttributes *attrs,
+                       const gulong *types,
+                       gsize n_types)
+{
+	gsize i;
+
+	for (i = 0; i < n_types; i++) {
+		if (!gck_attributes_find (attrs, types[i]))
+			return FALSE;
+	}
+
+	return TRUE;
+}
+
+static gulong
+find_first_usable_mechanism (GckObject *key,
+                             GckAttributes *attrs,
+                             const gulong *mechanisms,
+                             gsize n_mechanisms,
+                             gulong action_attr_type)
+{
+	GckSession *session;
+	GckSlot *slot;
+	GArray *mechs;
+	gboolean can;
+	gsize i;
+
+	if (gck_attributes_find_boolean (attrs, action_attr_type, &can) && !can) {
+		_gcr_debug ("key not capable of needed action");
+		return GCK_INVALID;
+	}
+
+	session = gck_object_get_session (key);
+	slot = gck_session_get_slot (session);
+	mechs = gck_slot_get_mechanisms (slot);
+	g_object_unref (slot);
+	g_object_unref (session);
+
+	if (!mechs) {
+		_gcr_debug ("couldn't get slot mechanisms");
+		return GCK_INVALID;
+	}
+
+	for (i = 0; i < n_mechanisms; i++) {
+		if (gck_mechanisms_check (mechs, mechanisms[i], GCK_INVALID))
+			break;
+	}
+
+	gck_mechanisms_free (mechs);
+
+	if (i < n_mechanisms)
+		return mechanisms[i];
+	return GCK_INVALID;
+}
+
+gulong
+_gcr_key_mechanisms_check (GckObject *key,
+                           const gulong *mechanisms,
+                           gulong n_mechanisms,
+                           gulong action_attr_type,
+                           GCancellable *cancellable,
+                           GError **error)
+{
+	gulong attr_types[] = { action_attr_type };
+	GckAttributes *attrs = NULL;
+	gulong result;
+
+	g_return_val_if_fail (GCK_IS_OBJECT (key), GCK_INVALID);
+	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), GCK_INVALID);
+	g_return_val_if_fail (error == NULL || *error == NULL, GCK_INVALID);
+
+	if (GCK_IS_OBJECT_ATTRIBUTES (key)) {
+		attrs = gck_object_attributes_get_attributes (GCK_OBJECT_ATTRIBUTES (key));
+		if (!check_have_attributes (attrs, attr_types, G_N_ELEMENTS (attr_types))) {
+			gck_attributes_unref (attrs);
+			attrs = NULL;
+		}
+	}
+
+	if (attrs == NULL) {
+		attrs = gck_object_get_full (key, attr_types, G_N_ELEMENTS (attr_types),
+		                             cancellable, error);
+	}
+
+	if (!attrs)
+		return GCK_INVALID;
+
+	result = find_first_usable_mechanism (key, attrs, mechanisms, n_mechanisms, action_attr_type);
+	gck_attributes_unref (attrs);
+	return result;
+}
+
+typedef struct {
+	gulong *mechanisms;
+	gsize n_mechanisms;
+	gulong action_attr_type;
+	GckAttributes *attrs;
+} CheckClosure;
+
+static void
+check_closure_free (gpointer data)
+{
+	CheckClosure *closure = data;
+	g_free (closure->mechanisms);
+	gck_attributes_unref (closure->attrs);
+	g_free (closure);
+}
+
+static void
+on_check_get_attributes (GObject *source,
+                         GAsyncResult *result,
+                         gpointer user_data)
+{
+	GSimpleAsyncResult *res = G_SIMPLE_ASYNC_RESULT (user_data);
+	CheckClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+	GError *error = NULL;
+
+	closure->attrs = gck_object_get_finish (GCK_OBJECT (source), result, &error);
+	if (error != NULL)
+		g_simple_async_result_take_error (res, error);
+
+	g_simple_async_result_complete (res);
+	g_object_unref (res);
+}
+
+void
+_gcr_key_mechanisms_check_async (GckObject *key,
+                                 const gulong *mechanisms,
+                                 gulong n_mechanisms,
+                                 gulong action_attr_type,
+                                 GCancellable *cancellable,
+                                 GAsyncReadyCallback callback,
+                                 gpointer user_data)
+{
+	gulong attr_types[] = { action_attr_type };
+	CheckClosure *closure;
+	GSimpleAsyncResult *res;
+	GckAttributes *attrs;
+
+	g_return_if_fail (GCK_IS_OBJECT (key));
+	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+	res = g_simple_async_result_new (G_OBJECT (key), callback, user_data,
+	                                 _gcr_key_mechanisms_check_async);
+	closure = g_new0 (CheckClosure, 1);
+	closure->mechanisms = g_memdup (mechanisms, n_mechanisms * sizeof (gulong));
+	closure->n_mechanisms = n_mechanisms;
+	closure->action_attr_type = action_attr_type;
+	g_simple_async_result_set_op_res_gpointer (res, closure, check_closure_free);
+
+	if (GCK_IS_OBJECT_ATTRIBUTES (key)) {
+		attrs = gck_object_attributes_get_attributes (GCK_OBJECT_ATTRIBUTES (key));
+		if (check_have_attributes (attrs, attr_types, G_N_ELEMENTS (attr_types))) {
+			g_simple_async_result_set_op_res_gpointer (res, attrs, gck_attributes_unref);
+			g_simple_async_result_complete_in_idle (res);
+			g_object_unref (res);
+			return;
+		}
+
+		gck_attributes_unref (attrs);
+	}
+
+	gck_object_get_async (key, attr_types, G_N_ELEMENTS (attr_types),
+	                      cancellable, on_check_get_attributes, g_object_ref (res));
+
+	g_object_unref (res);
+
+
+}
+
+gulong
+_gcr_key_mechanisms_check_finish (GckObject *key,
+                                  GAsyncResult *result,
+                                  GError **error)
+{
+	CheckClosure *closure;
+	GSimpleAsyncResult *res;
+
+	g_return_val_if_fail (GCK_IS_OBJECT (key), GCK_INVALID);
+	g_return_val_if_fail (error == NULL || *error == NULL, GCK_INVALID);
+
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (key),
+	                      _gcr_key_mechanisms_check_async), FALSE);
+
+	res = G_SIMPLE_ASYNC_RESULT (result);
+	if (g_simple_async_result_propagate_error (res, error))
+		return FALSE;
+
+	closure = g_simple_async_result_get_op_res_gpointer (res);
+
+	return find_first_usable_mechanism (GCK_OBJECT (key), closure->attrs,
+	                                    closure->mechanisms, closure->n_mechanisms,
+	                                    closure->action_attr_type);
+}
diff --git a/gcr/gcr-key-mechanisms.h b/gcr/gcr-key-mechanisms.h
new file mode 100644
index 0000000..f856cee
--- /dev/null
+++ b/gcr/gcr-key-mechanisms.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * 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.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly."
+#endif
+
+#ifndef __GCR_KEY_MECHANISMS_H__
+#define __GCR_KEY_MECHANISMS_H__
+
+#include <glib-object.h>
+
+#include "gck/gck.h"
+
+G_BEGIN_DECLS
+
+gulong                 _gcr_key_mechanisms_check              (GckObject *key,
+                                                               const gulong *mechanisms,
+                                                               gsize n_mechanisms,
+                                                               gulong action_attr_type,
+                                                               GCancellable *cancellable,
+                                                               GError **error);
+
+void                   _gcr_key_mechanisms_check_async        (GckObject *key,
+                                                               const gulong *mechanisms,
+                                                               gsize n_mechanisms,
+                                                               gulong action_attr_type,
+                                                               GCancellable *cancellable,
+                                                               GAsyncReadyCallback callback,
+                                                               gpointer user_data);
+
+gulong                 _gcr_key_mechanisms_check_finish       (GckObject *key,
+                                                               GAsyncResult *result,
+                                                               GError **error);
+
+G_END_DECLS
+
+#endif /* __GCR_KEY_MECHANISMS_H__ */
diff --git a/gcr/tests/frob-certificate-request.c b/gcr/tests/frob-certificate-request.c
index ecf8584..46771fc 100644
--- a/gcr/tests/frob-certificate-request.c
+++ b/gcr/tests/frob-certificate-request.c
@@ -78,6 +78,15 @@ test_request (const gchar *uri)
 	if (key == NULL)
 		g_error ("couldn't find key for uri: %s", uri);
 
+	if (!gcr_certificate_request_capable (key, NULL, &error)) {
+		if (error != NULL)
+			g_error ("error checking key capabilities: %s", error->message);
+		g_clear_error (&error);
+		g_printerr ("frob-certificate-request: key doesn't have right capabilities");
+		g_object_unref (key);
+		return;
+	}
+
 	req = gcr_certificate_request_prepare (GCR_CERTIFICATE_REQUEST_PKCS10, key);
 	g_object_unref (key);
 



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