summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcr/Makefile.am2
-rw-r--r--gcr/gcr-base.h1
-rw-r--r--gcr/gcr-certificate-request.c493
-rw-r--r--gcr/gcr-certificate-request.h71
-rw-r--r--gcr/gcr-oids.list9
-rw-r--r--gcr/tests/Makefile.am5
-rw-r--r--gcr/tests/console-interaction.c175
-rw-r--r--gcr/tests/console-interaction.h34
-rw-r--r--gcr/tests/frob-certificate-request.c114
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;
+}