[gcr] gcr: Add GcrCertificateRequest class for requesting certificates



commit 6830937f195dce60a7bfe2c59846ffdda0c3e55a
Author: Stef Walter <stefw collabora co uk>
Date:   Fri Nov 18 15:03:59 2011 +0100

    gcr: Add GcrCertificateRequest class for requesting certificates
    
     * The GcrCertificateRequest class can be used to build certificate
       requests.
     * Currently only the PKCS#10 format is supported.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=663604

 gcr/Makefile.am                      |    2 +
 gcr/gcr-base.h                       |    1 +
 gcr/gcr-certificate-request.c        |  493 ++++++++++++++++++++++++++++++++++
 gcr/gcr-certificate-request.h        |   71 +++++
 gcr/gcr-oids.list                    |    9 +-
 gcr/tests/Makefile.am                |    5 +
 gcr/tests/console-interaction.c      |  175 ++++++++++++
 gcr/tests/console-interaction.h      |   34 +++
 gcr/tests/frob-certificate-request.c |  114 ++++++++
 9 files changed, 901 insertions(+), 3 deletions(-)
---
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index addfca0..f8ea461 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -17,6 +17,7 @@ HEADER_BASE_FILES = \
 	gcr-base.h \
 	gcr-certificate.h \
 	gcr-certificate-chain.h \
+	gcr-certificate-request.h \
 	gcr-collection.h \
 	gcr-comparable.h \
 	gcr-deprecated-base.h \
@@ -98,6 +99,7 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
 	gcr-callback-output-stream.c gcr-callback-output-stream.h \
 	gcr-certificate.c gcr-certificate.h \
 	gcr-certificate-chain.c gcr-certificate-chain.h \
+	gcr-certificate-request.c gcr-certificate-request.h \
 	gcr-collection.c gcr-collection.h \
 	gcr-comparable.c gcr-comparable.h \
 	gcr-debug.c gcr-debug.h \
diff --git a/gcr/gcr-base.h b/gcr/gcr-base.h
index 753c381..ff871cb 100644
--- a/gcr/gcr-base.h
+++ b/gcr/gcr-base.h
@@ -36,6 +36,7 @@
 
 #include "gcr-certificate.h"
 #include "gcr-certificate-chain.h"
+#include "gcr-certificate-request.h"
 #include "gcr-deprecated-base.h"
 #include "gcr-enum-types-base.h"
 #include "gcr-filter-collection.h"
diff --git a/gcr/gcr-certificate-request.c b/gcr/gcr-certificate-request.c
new file mode 100644
index 0000000..a097e5b
--- /dev/null
+++ b/gcr/gcr-certificate-request.c
@@ -0,0 +1,493 @@
+/*
+ * 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>
+ */
+
+#include "config.h"
+
+#include "gcr-certificate-request.h"
+#include "gcr-enum-types-base.h"
+#include "gcr-oids.h"
+#include "gcr-subject-public-key.h"
+
+#include <egg/egg-asn1x.h>
+#include <egg/egg-asn1-defs.h>
+#include <egg/egg-dn.h>
+
+#include <glib/gi18n-lib.h>
+
+#define GCR_CERTIFICATE_REQUEST_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_REQUEST, GcrCertificateRequestClass))
+#define GCR_IS_CERTIFICATE_REQUEST_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_REQUEST))
+#define GCR_CERTIFICATE_REQUEST_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_REQUEST, GcrCertificateRequestClass))
+
+typedef struct _GcrCertificateRequestClass GcrCertificateRequestClass;
+
+struct _GcrCertificateRequest {
+	GObject parent;
+
+	GckObject *private_key;
+	GNode *asn;
+};
+
+struct _GcrCertificateRequestClass {
+	GObjectClass parent_class;
+};
+
+enum {
+	PROP_0,
+	PROP_FORMAT,
+	PROP_PRIVATE_KEY
+};
+
+/* Forward declarations */
+G_DEFINE_TYPE (GcrCertificateRequest, gcr_certificate_request, G_TYPE_OBJECT);
+
+static void
+gcr_certificate_request_init (GcrCertificateRequest *self)
+{
+
+}
+
+static void
+gcr_certificate_request_constructed (GObject *obj)
+{
+	GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
+	GNode *version;
+
+	G_OBJECT_CLASS (gcr_certificate_request_parent_class)->constructed (obj);
+
+	self->asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-10-CertificationRequest");
+	g_return_if_fail (self->asn != NULL);
+
+	/* Setup the version */
+	version = egg_asn1x_node (self->asn, "certificationRequestInfo", "version", NULL);
+	egg_asn1x_set_integer_as_ulong (version, 0);
+}
+
+static void
+gcr_certificate_request_finalize (GObject *obj)
+{
+	GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
+
+	egg_asn1x_destroy (self->asn);
+
+	G_OBJECT_CLASS (gcr_certificate_request_parent_class)->finalize (obj);
+}
+
+static void
+gcr_certificate_request_set_property (GObject *obj,
+                                      guint prop_id,
+                                      const GValue *value,
+                                      GParamSpec *pspec)
+{
+	GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
+	GcrCertificateRequestFormat format;
+
+	switch (prop_id) {
+	case PROP_PRIVATE_KEY:
+		g_return_if_fail (self->private_key == NULL);
+		self->private_key = g_value_dup_object (value);
+		g_return_if_fail (GCK_IS_OBJECT (self->private_key));
+		break;
+	case PROP_FORMAT:
+		format = g_value_get_enum (value);
+		g_return_if_fail (format == GCR_CERTIFICATE_REQUEST_PKCS10);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_request_get_property (GObject *obj,
+                                      guint prop_id,
+                                      GValue *value,
+                                      GParamSpec *pspec)
+{
+	GcrCertificateRequest *self = GCR_CERTIFICATE_REQUEST (obj);
+
+	switch (prop_id) {
+	case PROP_PRIVATE_KEY:
+		g_value_set_object (value, self->private_key);
+		break;
+	case PROP_FORMAT:
+		g_value_set_enum (value, GCR_CERTIFICATE_REQUEST_PKCS10);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_request_class_init (GcrCertificateRequestClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+	_gcr_oids_init ();
+
+	gobject_class->constructed = gcr_certificate_request_constructed;
+	gobject_class->finalize = gcr_certificate_request_finalize;
+	gobject_class->set_property = gcr_certificate_request_set_property;
+	gobject_class->get_property = gcr_certificate_request_get_property;
+
+	g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY,
+	            g_param_spec_object ("private-key", "Private key", "Private key for request",
+	                                 GCK_TYPE_OBJECT, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+	g_object_class_install_property (gobject_class, PROP_FORMAT,
+	              g_param_spec_enum ("format", "Format", "Format of certificate request",
+	                                 GCR_TYPE_CERTIFICATE_REQUEST_FORMAT, GCR_CERTIFICATE_REQUEST_PKCS10,
+	                                 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+/**
+ * gcr_certificate_request_prepare:
+ * @format: the format for the certificate request
+ * @private_key: the private key the the certificate is being requested for
+ *
+ * xxx
+ *
+ * Returns: (transfer full): a new #GcrCertificate request
+ */
+GcrCertificateRequest *
+gcr_certificate_request_prepare (GcrCertificateRequestFormat format,
+                                 GckObject *private_key)
+{
+	g_return_val_if_fail (format == GCR_CERTIFICATE_REQUEST_PKCS10, NULL);
+	g_return_val_if_fail (GCK_IS_OBJECT (private_key), NULL);
+
+	return g_object_new (GCR_TYPE_CERTIFICATE_REQUEST,
+	                     "format", format,
+	                     "private-key", private_key,
+	                     NULL);
+}
+
+void
+gcr_certificate_request_set_cn (GcrCertificateRequest *self,
+                                const gchar *cn)
+{
+	GNode *subject;
+	GNode *dn;
+
+	g_return_if_fail (GCR_IS_CERTIFICATE_REQUEST (self));
+	g_return_if_fail (cn != NULL);
+
+	subject = egg_asn1x_node (self->asn, "certificationRequestInfo", "subject", NULL);
+	dn = egg_asn1x_node (subject, "rdnSequence", NULL);
+
+	/* TODO: we shouldn't really be clearing this, but replacing CN */
+	egg_asn1x_set_choice (subject, dn);
+	egg_asn1x_clear (dn);
+	egg_dn_add_string_part (dn, GCR_OID_NAME_CN, cn);
+}
+
+
+static EggBytes *
+prepare_to_be_signed (GcrCertificateRequest *self)
+{
+	GNode *node;
+
+	node = egg_asn1x_node (self->asn, "certificationRequestInfo", NULL);
+	return egg_asn1x_encode (node, NULL);
+}
+
+static gboolean
+prepare_subject_public_key_and_mechanism (GcrCertificateRequest *self,
+                                          GNode *subject_public_key,
+                                          GQuark *algorithm,
+                                          GckMechanism *mechanism,
+                                          GError **error)
+{
+	EggBytes *encoded;
+	GNode *node;
+	GQuark oid;
+
+	g_assert (algorithm != NULL);
+	g_assert (mechanism != NULL);
+
+	encoded = egg_asn1x_encode (subject_public_key, NULL);
+	g_return_val_if_fail (encoded != NULL, FALSE);
+
+	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;
+		*algorithm = GCR_OID_PKIX1_SHA1_WITH_RSA;
+
+	} else if (oid == GCR_OID_PKIX1_DSA) {
+		mechanism->type = CKM_DSA_SHA1;
+		*algorithm = GCR_OID_PKIX1_SHA1_WITH_DSA;
+
+	} else {
+		egg_bytes_unref (encoded);
+		g_set_error (error, GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED,
+		             _("Unsupported key type for certificate request"));
+		return FALSE;
+	}
+
+	node = egg_asn1x_node (self->asn, "certificationRequestInfo", "subjectPKInfo", NULL);
+	if (!egg_asn1x_set_element_raw (node, encoded))
+		g_return_val_if_reached (FALSE);
+
+	egg_bytes_unref (encoded);
+	return TRUE;
+}
+
+static void
+encode_take_signature_into_request (GcrCertificateRequest *self,
+                                    GQuark algorithm,
+                                    GNode *subject_public_key,
+                                    guchar *result,
+                                    gsize n_result)
+{
+	EggBytes *data;
+	GNode *params;
+	GNode *node;
+
+	node = egg_asn1x_node (self->asn, "signature", NULL);
+	egg_asn1x_take_bits_as_raw (node, egg_bytes_new_take (result, n_result), n_result * 8);
+
+	node = egg_asn1x_node (self->asn, "signatureAlgorithm", "algorithm", NULL);
+	egg_asn1x_set_oid_as_quark (node, algorithm);
+
+	node = egg_asn1x_node (self->asn, "signatureAlgorithm", "parameters", NULL);
+	params = egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL);
+	data = egg_asn1x_encode (params, NULL);
+	egg_asn1x_set_element_raw (node, data);
+	egg_bytes_unref (data);
+}
+
+gboolean
+gcr_certificate_request_complete (GcrCertificateRequest *self,
+                                  GCancellable *cancellable,
+                                  GError **error)
+{
+	GNode *subject_public_key;
+	GckMechanism mechanism = { 0, };
+	GQuark algorithm = 0;
+	EggBytes *tbs;
+	GckSession *session;
+	guchar *signature;
+	gsize n_signature;
+	gboolean ret;
+
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_REQUEST (self), FALSE);
+	g_return_val_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+	subject_public_key = _gcr_subject_public_key_load (self->private_key,
+	                                                   cancellable, error);
+	if (subject_public_key == NULL)
+		return FALSE;
+
+	ret = prepare_subject_public_key_and_mechanism (self, subject_public_key,
+	                                                &algorithm, &mechanism, error);
+
+	if (!ret) {
+		egg_asn1x_destroy (subject_public_key);
+		return FALSE;
+	}
+
+	tbs = prepare_to_be_signed (self);
+	session = gck_object_get_session (self->private_key);
+	signature = gck_session_sign_full (session, self->private_key, &mechanism,
+	                                   egg_bytes_get_data (tbs),
+	                                   egg_bytes_get_size (tbs),
+	                                   &n_signature, cancellable, error);
+	g_object_unref (session);
+	egg_bytes_unref (tbs);
+
+	if (!signature) {
+		egg_asn1x_destroy (subject_public_key);
+		return FALSE;
+	}
+
+	encode_take_signature_into_request (self, algorithm, subject_public_key,
+	                                    signature, n_signature);
+	egg_asn1x_destroy (subject_public_key);
+	return TRUE;
+}
+
+typedef struct {
+	GcrCertificateRequest *request;
+	GCancellable *cancellable;
+	GQuark algorithm;
+	GNode *subject_public_key;
+	GckMechanism mechanism;
+	GckSession *session;
+	EggBytes *tbs;
+} CompleteClosure;
+
+static void
+complete_closure_free (gpointer data)
+{
+	CompleteClosure *closure = data;
+	egg_asn1x_destroy (closure->subject_public_key);
+	g_clear_object (&closure->request);
+	g_clear_object (&closure->cancellable);
+	g_clear_object (&closure->session);
+	if (closure->tbs)
+		egg_bytes_unref (closure->tbs);
+	g_free (closure);
+}
+
+static void
+on_certificate_request_signed (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);
+	GError *error = NULL;
+	guchar *signature;
+	gsize n_signature;
+
+	signature = gck_session_sign_finish (closure->session, result, &n_signature, &error);
+	if (result == NULL) {
+		encode_take_signature_into_request (closure->request,
+		                                    closure->algorithm,
+		                                    closure->subject_public_key,
+		                                    signature, n_signature);
+
+	} else {
+		g_simple_async_result_take_error (res, error);
+	}
+
+	g_simple_async_result_complete (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);
+	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);
+	}
+
+	if (error != NULL) {
+		g_simple_async_result_take_error (res, error);
+		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));
+	}
+
+	g_object_unref (res);
+}
+
+void
+gcr_certificate_request_complete_async (GcrCertificateRequest *self,
+                                        GCancellable *cancellable,
+                                        GAsyncReadyCallback callback,
+                                        gpointer user_data)
+{
+	GSimpleAsyncResult *res;
+	CompleteClosure *closure;
+
+	g_return_if_fail (GCR_IS_CERTIFICATE_REQUEST (self));
+	g_return_if_fail (cancellable == NULL || G_CANCELLABLE (cancellable));
+
+	res = g_simple_async_result_new (G_OBJECT (self), callback, user_data,
+	                                 gcr_certificate_request_complete_async);
+	closure = g_new0 (CompleteClosure, 1);
+	closure->cancellable = cancellable ? g_object_ref (cancellable) : NULL;
+	closure->session = gck_object_get_session (self->private_key);
+	closure->request = g_object_ref (self);
+	g_simple_async_result_set_op_res_gpointer (res, closure, complete_closure_free);
+
+	_gcr_subject_public_key_load_async (self->private_key, cancellable,
+	                                    on_subject_public_key_loaded,
+	                                    g_object_ref (res));
+
+	g_object_unref (res);
+}
+
+/**
+ *
+ */
+gboolean
+gcr_certificate_request_complete_finish (GcrCertificateRequest *self,
+                                         GAsyncResult *result,
+                                         GError **error)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_REQUEST (self), FALSE);
+	g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+	g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (self),
+	                      gcr_certificate_request_complete_async), FALSE);
+
+	if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+		return FALSE;
+
+	return TRUE;
+}
+
+/**
+ * gcr_certificate_request_encode:
+ * @self: a certificate request
+ * @length: location to place length of returned data
+ *
+ * Encode the certificate request. It must have been completed with
+ * gcr_certificate_request_complete() or gcr_certificate_request_complete_async()
+ *
+ * The output is a DER encoded certificate request.
+ *
+ * Returns: (transfer full) (array length=length): the encoded certificate request
+ */
+guchar *
+gcr_certificate_request_encode (GcrCertificateRequest *self,
+                                gsize *length)
+{
+	EggBytes *bytes;
+
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_REQUEST (self), NULL);
+	g_return_val_if_fail (length != NULL, NULL);
+
+	bytes = egg_asn1x_encode (self->asn, NULL);
+	if (bytes == NULL) {
+		g_warning ("couldn't encode certificate request: %s",
+		           egg_asn1x_message (self->asn));
+		return NULL;
+	}
+
+	*length = egg_bytes_get_size (bytes);
+	return g_byte_array_free (egg_bytes_unref_to_array (bytes), FALSE);
+}
diff --git a/gcr/gcr-certificate-request.h b/gcr/gcr-certificate-request.h
new file mode 100644
index 0000000..b83ba0f
--- /dev/null
+++ b/gcr/gcr-certificate-request.h
@@ -0,0 +1,71 @@
+/*
+ * 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_CERTIFICATE_REQUEST_H__
+#define __GCR_CERTIFICATE_REQUEST_H__
+
+#include <glib-object.h>
+
+#include "gcr-types.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+	GCR_CERTIFICATE_REQUEST_PKCS10 = 1,
+} GcrCertificateRequestFormat;
+
+#define GCR_TYPE_CERTIFICATE_REQUEST               (gcr_certificate_request_get_type ())
+#define GCR_CERTIFICATE_REQUEST(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_REQUEST, GcrCertificateRequest))
+#define GCR_IS_CERTIFICATE_REQUEST(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_REQUEST))
+
+typedef struct _GcrCertificateRequest GcrCertificateRequest;
+
+GType                     gcr_certificate_request_get_type            (void) G_GNUC_CONST;
+
+GcrCertificateRequest *   gcr_certificate_request_prepare             (GcrCertificateRequestFormat format,
+                                                                       GckObject *private_key);
+
+void                      gcr_certificate_request_set_cn              (GcrCertificateRequest *self,
+                                                                       const gchar *cn);
+
+gboolean                  gcr_certificate_request_complete            (GcrCertificateRequest *self,
+                                                                       GCancellable *cancellable,
+                                                                       GError **error);
+
+void                      gcr_certificate_request_complete_async      (GcrCertificateRequest *self,
+                                                                       GCancellable *cancellable,
+                                                                       GAsyncReadyCallback callback,
+                                                                       gpointer user_data);
+
+gboolean                  gcr_certificate_request_complete_finish     (GcrCertificateRequest *self,
+                                                                       GAsyncResult *result,
+                                                                       GError **error);
+
+guchar *                  gcr_certificate_request_get_der_data        (GcrCertificateRequest *request,
+                                                                       gsize *length);
+
+G_END_DECLS
+
+#endif /* __GCR_CERTIFICATE_REQUEST_H__ */
diff --git a/gcr/gcr-oids.list b/gcr/gcr-oids.list
index 2fe3364..b49f4bd 100644
--- a/gcr/gcr-oids.list
+++ b/gcr/gcr-oids.list
@@ -1,11 +1,15 @@
+NAME_CN                 2.5.4.3
+
 BASIC_CONSTRAINTS	2.5.29.19
 EXTENDED_KEY_USAGE	2.5.29.37
 SUBJECT_KEY_IDENTIFIER	2.5.29.14
 KEY_USAGE		2.5.29.15
 SUBJECT_ALT_NAME	2.5.29.17
 
-PKIX1_RSA	1.2.840.113549.1.1.1
-PKIX1_DSA	1.2.840.10040.4.1
+PKIX1_RSA			1.2.840.113549.1.1.1
+PKIX1_SHA1_WITH_RSA		1.2.840.113549.1.1.5
+PKIX1_DSA			1.2.840.10040.4.1
+PKIX1_SHA1_WITH_DSA		1.2.840.10040.4.3
 
 PKCS7_DATA			1.2.840.113549.1.7.1
 PKCS7_SIGNED_DATA		1.2.840.113549.1.7.2
@@ -18,6 +22,5 @@ PKCS12_BAG_PKCS8_ENCRYPTED_KEY	1.2.840.113549.1.12.10.1.2
 PKCS12_BAG_CERTIFICATE		1.2.840.113549.1.12.10.1.3
 PKCS12_BAG_CRL			1.2.840.113549.1.12.10.1.4
 
-
 ALT_NAME_XMPP_ADDR		1.3.6.1.5.5.7.8.5
 ALT_NAME_DNS_SRV		1.3.6.1.5.5.7.8.7
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index 5e611f7..f711931 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -59,6 +59,7 @@ EXTRA_DIST = \
 
 noinst_PROGRAMS = \
 	frob-certificate \
+	frob-certificate-request \
 	frob-combo-selector \
 	frob-gnupg-selector \
 	frob-key \
@@ -72,3 +73,7 @@ noinst_PROGRAMS = \
 frob_unlock_SOURCES = \
 	frob-unlock.c \
 	../gcr-viewer-window.c
+
+frob_certificate_request_SOURCES = \
+	frob-certificate-request.c \
+	console-interaction.c console-interaction.h
diff --git a/gcr/tests/console-interaction.c b/gcr/tests/console-interaction.c
new file mode 100644
index 0000000..6d75207
--- /dev/null
+++ b/gcr/tests/console-interaction.c
@@ -0,0 +1,175 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; 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>
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <string.h>
+
+#ifdef G_OS_WIN32
+#include <glib/gprintf.h>
+#include <conio.h>
+#endif
+
+#include "console-interaction.h"
+
+/*
+ * WARNING: This is not the example you're looking for [slow hand wave]. This
+ * is not industrial strength, it's just for testing. It uses embarassing
+ * functions like getpass() and does lazy things with threads.
+ */
+
+#define TYPE_CONSOLE_INTERACTION         (console_interaction_get_type ())
+#define CONSOLE_INTERACTION(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), TYPE_CONSOLE_INTERACTION, ConsoleInteraction))
+#define CONSOLE_INTERACTION_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), TYPE_CONSOLE_INTERACTION, ConsoleInteractionClass))
+#define IS_CONSOLE_INTERACTION(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), TYPE_CONSOLE_INTERACTION))
+#define IS_CONSOLE_INTERACTION_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), TYPE_CONSOLE_INTERACTION))
+#define CONSOLE_INTERACTION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TYPE_CONSOLE_INTERACTION, ConsoleInteractionClass))
+
+typedef struct _ConsoleInteraction        ConsoleInteraction;
+typedef struct _ConsoleInteractionClass   ConsoleInteractionClass;
+
+struct _ConsoleInteraction
+{
+  GTlsInteraction parent_instance;
+};
+
+struct _ConsoleInteractionClass
+{
+  GTlsInteractionClass parent_class;
+};
+
+GType                  console_interaction_get_type    (void) G_GNUC_CONST;
+
+G_DEFINE_TYPE (ConsoleInteraction, console_interaction, G_TYPE_TLS_INTERACTION);
+
+#ifdef G_OS_WIN32
+/* win32 doesn't have getpass() */
+static gchar *
+getpass (const gchar *prompt)
+{
+  static gchar buf[BUFSIZ];
+  gint i;
+
+  g_printf ("%s", prompt);
+  fflush (stdout);
+
+  for (i = 0; i < BUFSIZ - 1; ++i)
+    {
+      buf[i] = _getch ();
+      if (buf[i] == '\r')
+        break;
+    }
+  buf[i] = '\0';
+
+  g_printf ("\n");
+
+  return &buf[0];
+}
+#endif
+
+static GTlsInteractionResult
+console_interaction_ask_password (GTlsInteraction    *interaction,
+                                        GTlsPassword       *password,
+                                        GCancellable       *cancellable,
+                                        GError            **error)
+{
+  const gchar *value;
+  gchar *prompt;
+
+  prompt = g_strdup_printf ("Password \"%s\"': ", g_tls_password_get_description (password));
+  value = getpass (prompt);
+  g_free (prompt);
+
+  if (g_cancellable_set_error_if_cancelled (cancellable, error))
+    return G_TLS_INTERACTION_FAILED;
+
+  g_tls_password_set_value (password, (guchar *)value, -1);
+  return G_TLS_INTERACTION_HANDLED;
+}
+
+static void
+ask_password_with_getpass (GSimpleAsyncResult    *res,
+                           GObject               *object,
+                           GCancellable          *cancellable)
+{
+  GTlsPassword *password;
+  GError *error = NULL;
+
+  password = g_simple_async_result_get_op_res_gpointer (res);
+  console_interaction_ask_password (G_TLS_INTERACTION (object), password,
+                                          cancellable, &error);
+  if (error != NULL)
+    g_simple_async_result_take_error (res, error);
+}
+
+static void
+console_interaction_ask_password_async (GTlsInteraction    *interaction,
+                                              GTlsPassword       *password,
+                                              GCancellable       *cancellable,
+                                              GAsyncReadyCallback callback,
+                                              gpointer            user_data)
+{
+  GSimpleAsyncResult *res;
+
+  res = g_simple_async_result_new (G_OBJECT (interaction), callback, user_data,
+                                   console_interaction_ask_password);
+  g_simple_async_result_set_op_res_gpointer (res, g_object_ref (password), g_object_unref);
+  g_simple_async_result_run_in_thread (res, ask_password_with_getpass,
+                                       G_PRIORITY_DEFAULT, cancellable);
+  g_object_unref (res);
+}
+
+static GTlsInteractionResult
+console_interaction_ask_password_finish (GTlsInteraction    *interaction,
+                                               GAsyncResult       *result,
+                                               GError            **error)
+{
+  g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (interaction),
+                        console_interaction_ask_password), G_TLS_INTERACTION_FAILED);
+
+  if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error))
+    return G_TLS_INTERACTION_FAILED;
+
+  return G_TLS_INTERACTION_HANDLED;
+}
+
+static void
+console_interaction_init (ConsoleInteraction *interaction)
+{
+
+}
+
+static void
+console_interaction_class_init (ConsoleInteractionClass *klass)
+{
+  GTlsInteractionClass *interaction_class = G_TLS_INTERACTION_CLASS (klass);
+  interaction_class->ask_password = console_interaction_ask_password;
+  interaction_class->ask_password_async = console_interaction_ask_password_async;
+  interaction_class->ask_password_finish = console_interaction_ask_password_finish;
+}
+
+GTlsInteraction *
+console_interaction_new (void)
+{
+  return g_object_new (TYPE_CONSOLE_INTERACTION, NULL);
+}
diff --git a/gcr/tests/console-interaction.h b/gcr/tests/console-interaction.h
new file mode 100644
index 0000000..b767421
--- /dev/null
+++ b/gcr/tests/console-interaction.h
@@ -0,0 +1,34 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2011 Collabora, Ltd.
+ *
+ * This library 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 of the License, or (at your option) any later version.
+ *
+ * This 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; 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>
+ */
+
+#ifndef __CONSOLE_INTERACTION_H__
+#define __CONSOLE_INTERACTION_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+GTlsInteraction *      console_interaction_new         (void);
+
+G_END_DECLS
+
+#endif /* __G_TLS_CONSOLE_INTERACTION_H__ */
diff --git a/gcr/tests/frob-certificate-request.c b/gcr/tests/frob-certificate-request.c
new file mode 100644
index 0000000..a13a553
--- /dev/null
+++ b/gcr/tests/frob-certificate-request.c
@@ -0,0 +1,114 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2010 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>
+ */
+
+#include "config.h"
+
+#include "console-interaction.h"
+
+#include "gcr/gcr-base.h"
+
+#include "egg/egg-armor.h"
+
+#include <gtk/gtk.h>
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+const gchar *cn_name = NULL;
+
+static GckObject *
+load_key_for_uri (const gchar *uri)
+{
+	GError *error = NULL;
+	GTlsInteraction *interaction;
+	GckEnumerator *enumerator;
+	GList *modules;
+	GckObject *key;
+
+	gcr_pkcs11_initialize (NULL, &error);
+	g_assert_no_error (error);
+
+	modules = gcr_pkcs11_get_modules ();
+	enumerator = gck_modules_enumerate_uri (modules, uri, GCK_SESSION_LOGIN_USER |
+	                                        GCK_SESSION_READ_ONLY, &error);
+	gck_list_unref_free (modules);
+
+	interaction = console_interaction_new ();
+	gck_enumerator_set_interaction (enumerator, interaction);
+	g_object_unref (interaction);
+
+	key = gck_enumerator_next (enumerator, NULL, &error);
+	g_assert_no_error (error);
+	g_object_unref (enumerator);
+
+	return key;
+}
+
+static void
+test_request (const gchar *uri)
+{
+	GcrCertificateRequest *req;
+	GError *error = NULL;
+	GckObject *key;
+	guchar *data, *output;
+	gsize n_data, n_output;
+
+	key = load_key_for_uri (uri);
+	if (key == NULL)
+		g_error ("couldn't find key for uri: %s", uri);
+
+	req = gcr_certificate_request_prepare (GCR_CERTIFICATE_REQUEST_PKCS10, key);
+	g_object_unref (key);
+
+	gcr_certificate_request_set_cn (req, cn_name);
+	gcr_certificate_request_complete (req, NULL, &error);
+	g_assert_no_error (error);
+
+	data = gcr_certificate_request_get_der_data (req, &n_data);
+
+	output = egg_armor_write (data, n_data,
+	                          g_quark_from_static_string ("CERTIFICATE REQUEST"),
+	                          NULL, &n_output);
+
+	g_free (data);
+
+	write (1, output, n_output);
+	g_free (output);
+}
+
+int
+main(int argc, char *argv[])
+{
+	gtk_init (&argc, &argv);
+	g_set_prgname ("frob-certificate-request");
+
+	if (argc <= 1)
+		g_printerr ("frob-certificate-request: specify pkcs11: url of key");
+
+	if (cn_name == NULL)
+		cn_name = g_strdup ("name.example.com");
+
+	test_request (argv[1]);
+	return 0;
+}



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