[rs-commit] r40 - in /redwax-signtext/trunk/src/linux: Makefile.am configure.ac crypto.c crypto.h message.c signtext.c signtext.h
rs-commit at redwax.eu
rs-commit at redwax.eu
Thu Sep 8 21:41:35 CEST 2022
Author: minfrin at redwax.eu
Date: Thu Sep 8 21:41:34 2022
New Revision: 40
Log:
Add the first pass at generating the CMS signature.
Modified:
redwax-signtext/trunk/src/linux/Makefile.am
redwax-signtext/trunk/src/linux/configure.ac
redwax-signtext/trunk/src/linux/crypto.c
redwax-signtext/trunk/src/linux/crypto.h
redwax-signtext/trunk/src/linux/message.c
redwax-signtext/trunk/src/linux/signtext.c
redwax-signtext/trunk/src/linux/signtext.h
Modified: redwax-signtext/trunk/src/linux/Makefile.am
==============================================================================
--- redwax-signtext/trunk/src/linux/Makefile.am (original)
+++ redwax-signtext/trunk/src/linux/Makefile.am Thu Sep 8 21:41:34 2022
@@ -12,22 +12,26 @@
$(AM_CPPFLAGS)
redwax_signtext_native_CFLAGS = \
- $(GTK3_CFLAGS) \
+ $(GTK3_CFLAGS) \
$(GTK4_CFLAGS) \
- $(JSON_GLIB_CFLAGS) \
- $(GCK1_CFLAGS) \
- $(GCR3_CFLAGS) \
- $(WARN_CFLAGS) \
+ $(JSON_GLIB_CFLAGS) \
+ $(GCK1_CFLAGS) \
+ $(GCR3_CFLAGS) \
+ $(KSBA_CFLAGS) \
+ $(GCRYPT_CFLAGS) \
+ $(WARN_CFLAGS) \
$(AM_CFLAGS)
redwax_signtext_native_LDFLAGS = \
$(AM_LDFLAGS)
-redwax_signtext_native_LDADD = \
- $(GTK3_LIBS) \
- $(GTK4_LIBS) \
- $(JSON_GLIB_LIBS) \
- $(GCK1_LIBS) \
- $(GCR3_LIBS) \
+redwax_signtext_native_LDADD = \
+ $(GTK3_LIBS) \
+ $(GTK4_LIBS) \
+ $(JSON_GLIB_LIBS) \
+ $(GCK1_LIBS) \
+ $(GCR3_LIBS) \
+ $(KSBA_LIBS) \
+ $(GCRYPT_LIBS) \
$(INTLLIBS)
Modified: redwax-signtext/trunk/src/linux/configure.ac
==============================================================================
--- redwax-signtext/trunk/src/linux/configure.ac (original)
+++ redwax-signtext/trunk/src/linux/configure.ac Thu Sep 8 21:41:34 2022
@@ -20,6 +20,12 @@
PKG_CHECK_MODULES([GCR3],
[gcr-3 >= 3])
+PKG_CHECK_MODULES([KSBA],
+ [ksba >= 1])
+
+PKG_CHECK_MODULES([GCRYPT],
+ [libgcrypt >= 1])
+
AC_CHECK_FUNCS([gtk_box_append gtk_window_set_child])
IT_PROG_INTLTOOL([0.40.0])
Modified: redwax-signtext/trunk/src/linux/crypto.c
==============================================================================
--- redwax-signtext/trunk/src/linux/crypto.c (original)
+++ redwax-signtext/trunk/src/linux/crypto.c Thu Sep 8 21:41:34 2022
@@ -18,6 +18,10 @@
#include "crypto.h"
+#include <ksba.h>
+
+#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
+
#ifndef CK_CERTIFICATE_CATEGORY_TOKEN_USER
#define CK_CERTIFICATE_CATEGORY_TOKEN_USER 0x00000001UL
#endif
@@ -113,9 +117,15 @@
for (l = incoming; l; l = g_list_next (l)) {
if (!gcr_collection_contains(signtext->incoming, l->data)) {
g_object_ref(l->data);
+
+ g_object_set_data_full(l->data, "slot",
+ g_object_ref(signtext_token->slot),
+ (GDestroyNotify)g_object_unref);
+
g_object_set_data_full(l->data, "token-info",
gck_token_info_copy(signtext_token->token_info),
(GDestroyNotify)gck_token_info_free);
+
gcr_simple_collection_add(GCR_SIMPLE_COLLECTION(signtext->incoming), l->data);
}
}
@@ -383,14 +393,14 @@
void crypto_pin_changed(GcrComboSelector *selector,
gpointer user_data)
{
- GObject *selected;
+ GcrPkcs11Certificate *certificate;
SignTextInstance *instance = user_data;
g_printerr("crypto_pin_changed\n");
- if (selected && GCR_IS_PKCS11_CERTIFICATE(selected)) {
-
- GcrPkcs11Certificate *certificate = GCR_PKCS11_CERTIFICATE(selected);
+ certificate = GCR_PKCS11_CERTIFICATE(gcr_combo_selector_get_selected(selector));
+
+ if (certificate) {
GckTokenInfo *token_info = g_object_get_data(G_OBJECT (certificate), "token-info");
@@ -423,3 +433,729 @@
}
+/*
+ * Handle the writing of the CMS structure.
+ */
+static int
+pem_writer_cb (void *cb_value, const void *buffer, size_t count)
+{
+ SignTextInstance *instance = cb_value;
+
+ g_printerr("pem_writer_cb: %d\n", (int)count);
+
+ return 0;
+}
+
+/*
+ * We're finished signing the CMS structure.
+ *
+ * Are we good to leave?
+ */
+static void
+crypto_sign_done (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ SignTextInstance *instance = user_data;
+ GError *gerror = NULL;
+ gchar *signature = NULL;
+
+ g_printerr("crypto_sign_done\n");
+
+ signature = g_task_propagate_pointer (G_TASK (res), &gerror);
+
+ if (gerror) {
+ GtkWidget* dialog;
+
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", ("Redwax SignText - Error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ ("Error: %s"),
+ gerror->message);
+
+ g_error_free (gerror);
+
+ gtk_widget_show (dialog);
+
+ }
+
+ if (signature) {
+ g_free(signature);
+ }
+
+ ksba_cert_release(instance->signer);
+
+}
+
+/*
+ * Generate and sign the CMS structure.
+ *
+ * When done, jump to the completion step to send the message.
+ */
+static void
+crypto_sign_do (GTask *task,
+ gpointer source_obj,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ SignTextInstance *instance = task_data;
+ GError *gerror = NULL;
+ gchar *signature = NULL;
+
+ ksba_writer_t w = NULL;
+ gpg_error_t err;
+ int rc;
+
+ ksba_stop_reason_t stopreason;
+
+ g_printerr("crypto_sign_do\n");
+
+ err = ksba_writer_new (&w);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_writer_new failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_writer_set_cb (w, pem_writer_cb, instance);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_writer_set_cb failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cms_set_reader_writer (instance->cms, NULL, w);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_reader_writer failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+
+
+
+ /* Main building loop. */
+ do {
+ err = ksba_cms_build (instance->cms, &stopreason);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_build failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+
+ if (stopreason == KSBA_SR_BEGIN_DATA) {
+ g_printerr("crypto_sign_do: begin data\n");
+
+ }
+
+
+ else if (stopreason == KSBA_SR_NEED_SIG) {
+
+ GckSlot *slot;
+ GArray *mechanisms;
+
+ gcry_md_hd_t md;
+
+ unsigned char *sigval;
+ size_t sigval_len;
+ gcry_sexp_t sexp;
+
+ unsigned char *digest;
+ size_t digest_len;
+
+ unsigned char *alg;
+ size_t alg_len;
+
+ unsigned char *sig;
+ gsize sig_len;
+
+ unsigned char *data;
+ gsize data_len;
+
+ g_printerr("crypto_sign_do: need sig\n");
+
+ slot = gck_session_get_slot(instance->session);
+ mechanisms = gck_slot_get_mechanisms(slot);
+
+ //int i;
+ //for (i = 0; i < gck_mechanisms_length(mechanisms); i++) {
+ //g_printerr("crypto_sign_do: mechs: 0x%lxUL (%s)\n", gck_mechanisms_at(mechanisms, i), gcry_pk_algo_name(gck_mechanisms_at(mechanisms, i)));
+ //}
+
+ if (!gck_mechanisms_check(mechanisms, CKM_RSA_PKCS, GCK_INVALID)) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "CKM_RSA_PKCS not supported by this card.");
+ goto fatal;
+ }
+
+ rc = gcry_md_open (&md, 0, 0);
+ if (rc) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_open failed: %s", gpg_strerror (rc));
+ goto fatal;
+ }
+
+ ksba_cms_set_hash_function (instance->cms, HASH_FNC, md);
+
+ gcry_md_enable (md, instance->hash_alg);
+
+ err = ksba_cms_hash_signed_attrs (instance->cms, 0);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_hash_signed_attrs failed: %s", gpg_strerror (err));
+ gcry_md_close (md);
+ goto fatal;
+ }
+
+ digest = gcry_md_read (md, instance->hash_alg);
+ digest_len = gcry_md_get_algo_dlen (instance->hash_alg);
+ gcry_md_close (md);
+ if (!digest || !digest_len) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_read / gcry_md_get_algo_dlen failed");
+ goto fatal;
+ }
+
+ if (gcry_md_algo_info(instance->hash_alg, GCRYCTL_GET_ASNOID, NULL, &alg_len)) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_algo_info failed.");
+ goto fatal;
+ }
+ alg = g_malloc(alg_len);
+ gcry_md_algo_info(instance->hash_alg, GCRYCTL_GET_ASNOID, alg, &alg_len);
+
+ /*
+ * Our signature is a DER of the digest algorithm, followed by the digest.
+ */
+ data_len = alg_len + digest_len;
+ data = g_malloc(data_len);
+ memcpy(data, alg, alg_len);
+ memcpy(data + alg_len, digest, digest_len);
+ g_free(alg);
+
+ /*
+ * Sign on the line.
+ */
+ sig = gck_session_sign(instance->session, instance->key, CKM_RSA_PKCS, data, data_len, &sig_len, instance->signtext->cancellable, &gerror);
+ g_free(data);
+ if (gerror) {
+ goto fatal;
+ }
+
+ rc = gcry_sexp_build(&sexp, NULL, "(sig-val(rsa(s %b)))",
+ sig_len, (char *)sig);
+
+ g_free(sig);
+ if (rc) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_sexp_build failed: %s", gcry_strerror (rc));
+ goto fatal;
+ }
+
+ sigval_len = gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, NULL, 0);
+ sigval = g_malloc(sigval_len);
+ gcry_sexp_sprint (sexp, GCRYSEXP_FMT_CANON, sigval, sigval_len);
+ gcry_sexp_release(sexp);
+
+ err = ksba_cms_set_sig_val (instance->cms, 0, sigval);
+ g_free(sigval);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_sig_val failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ }
+
+ } while (stopreason != KSBA_SR_READY);
+
+
+ if (gerror) {
+fatal:
+ g_task_return_error (task, gerror);
+ }
+ else {
+ g_task_return_pointer(task, signature, NULL);
+ }
+
+ ksba_writer_release(w);
+
+}
+
+/*
+ * Handle the results of the search for the private key.
+ *
+ * If we found the private key, get ready to trigger the sign.
+ */
+static void
+crypto_found_key (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *gerror = NULL;
+ SignTextInstance *instance = user_data;
+ GList *keys;
+
+ keys = gck_session_find_objects_finish(instance->session, res, &gerror);
+
+ if (!keys) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "Private key was not found for this certificate.");
+ goto fatal;
+ }
+
+ else if (g_list_length(keys) > 1) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "Multiple private keys were found for this certificate.");
+ goto fatal;
+ }
+
+ else {
+
+ instance->key = GCK_OBJECT(keys->data);
+
+ /* we sign synchronously, so do this in a task */
+
+ GTask *task = g_task_new (instance->sign, instance->signtext->cancellable, crypto_sign_done, instance);
+ g_task_set_task_data (task, instance, NULL);
+ g_task_run_in_thread (task, crypto_sign_do);
+ g_object_unref (task);
+
+ }
+
+ if (gerror) {
+ GtkWidget* dialog;
+
+fatal:
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", ("Redwax SignText - Error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ ("Error: %s"),
+ gerror->message);
+
+ g_error_free (gerror);
+
+ gtk_widget_show (dialog);
+
+ }
+
+}
+
+/*
+ * Handle the results of the attempt to login.
+ *
+ * If successful, start a search for our certificate's private key.
+ */
+static void
+crypto_find_key (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *gerror = NULL;
+ SignTextInstance *instance = user_data;
+
+ if (gck_session_login_finish(instance->session, res, &gerror)) {
+
+ GckAttributes *attrs;
+ const GckAttribute *id;
+
+ GckBuilder builder = GCK_BUILDER_INIT;
+
+ attrs = gcr_pkcs11_certificate_get_attributes(GCR_PKCS11_CERTIFICATE(instance->certificate));
+
+ id = gck_attributes_find(attrs, CKA_ID);
+ if (!id || !id->length) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "Certificate does not have an ID, cannot find the corresponding key.");
+ goto fatal;
+ }
+
+ /*
+ * Search for key on a token belonging to the certificate (ie not in a session).
+ */
+ gck_builder_add_boolean (&builder, CKA_TOKEN, TRUE);
+ gck_builder_add_ulong(&builder, CKA_CLASS, CKO_PRIVATE_KEY);
+ gck_builder_add_data(&builder, CKA_ID, id->value, id->length);
+
+ gck_session_find_objects_async(instance->session, gck_builder_end (&builder), instance->signtext->cancellable, crypto_found_key, instance);
+
+ }
+
+ if (gerror) {
+ GtkWidget* dialog;
+
+// FIXME: update the UI with the new status of PIN attempts
+
+fatal:
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", ("Redwax SignText - Error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ ("Error: %s"),
+ gerror->message);
+
+ g_error_free (gerror);
+
+ gtk_widget_show (dialog);
+
+ }
+
+}
+
+/*
+ * We have a newly opened session, try to log into the session.
+ *
+ * We either pass the PIN we captured, or we wait for the pinpad to have the PIN entered.
+ */
+static void
+crypto_login_session (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *gerror = NULL;
+ SignTextInstance *instance = user_data;
+
+ instance->session = gck_session_open_finish(res, &gerror);
+ if (instance->session) {
+
+ if (gtk_widget_get_sensitive(GTK_WIDGET(instance->pin))) {
+
+ const guchar *pin = (guchar *)gtk_entry_buffer_get_text(instance->pin_buffer);
+ gsize n_pin = gtk_entry_buffer_get_bytes(instance->pin_buffer);
+
+ gck_session_login_async(instance->session, CKU_USER, pin, n_pin, instance->signtext->cancellable, crypto_find_key, instance);
+
+ }
+ else {
+
+ gck_session_login_async(instance->session, CKU_USER, NULL, 0, instance->signtext->cancellable, crypto_find_key, instance);
+
+ }
+
+ }
+
+ if (gerror) {
+ GtkWidget* dialog;
+
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", ("Redwax SignText - Error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ ("Error: %s"),
+ gerror->message);
+
+ g_error_free (gerror);
+
+ gtk_widget_show (dialog);
+
+ }
+
+ if (instance->certificate) {
+ g_object_unref(instance->certificate);
+ }
+
+}
+
+/*
+ * Start the opening of the session.
+ *
+ * When the session has finished being opened, we jump to the session login above.
+ */
+static void
+crypto_open_session (SignTextInstance *instance)
+{
+ GckSlot *slot = g_object_get_data(G_OBJECT (instance->certificate), "slot");
+
+ gck_session_open_async(slot, GCK_SESSION_READ_ONLY, NULL, instance->signtext->cancellable, crypto_login_session, instance);
+
+}
+
+/*
+ * Receive the intermediate certs we found, and add them to the CMS object.
+ *
+ * Keep firing off requests for intermediates until we reach the root or we can't
+ * find any more certs.
+ *
+ * Jump to the open session step above.
+ */
+static void
+crypto_sign_lookup (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ SignTextInstance *instance = user_data;
+ GcrPkcs11Certificate *certificate;
+ GError *gerror = NULL;
+
+ g_printerr("crypto_sign_lookup\n");
+
+ certificate = GCR_PKCS11_CERTIFICATE(gcr_pkcs11_certificate_lookup_issuer_finish(res, &gerror));
+
+ /*
+ * Certificate exists and is not self signed? Add the additional cert.
+ */
+ if (certificate && !gcr_certificate_is_issuer(GCR_CERTIFICATE(certificate), GCR_CERTIFICATE(certificate))) {
+
+ ksba_cert_t cert;
+
+ const guint8 *der;
+ gsize der_len;
+
+ gpg_error_t err;
+
+ der = gcr_certificate_get_der_data(GCR_CERTIFICATE(certificate), &der_len);
+ if (!der) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "Certificate could not be decoded");
+ goto fatal;
+ }
+
+ err = ksba_cert_new(&cert);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cert_new failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cert_init_from_mem(cert, der, der_len);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cert_init_from_mem failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cms_add_cert(instance->cms, cert);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_add_cert failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ ksba_cert_release (cert);
+
+ gcr_pkcs11_certificate_lookup_issuer_async(GCR_CERTIFICATE(certificate), instance->signtext->cancellable, crypto_sign_lookup, instance);
+
+ }
+
+ else {
+
+ crypto_open_session (instance);
+
+ }
+
+ if (gerror) {
+ GtkWidget* dialog;
+
+fatal:
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", ("Redwax SignText - Error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ ("Error: %s"),
+ gerror->message);
+
+ g_error_free (gerror);
+
+ gtk_widget_show (dialog);
+
+ }
+
+ if (certificate) {
+ g_object_unref(certificate);
+ }
+}
+
+/*
+ * It's the main event! Start the signing process.
+ *
+ * Set up the CMS context.
+ *
+ * Identify the certificate that was selected, and set off the process to find the
+ * issuer of that cert.
+ */
+void
+crypto_sign(SignTextInstance *instance)
+{
+ GError *gerror = NULL;
+ GTimeZone *utc;
+ GDateTime *now;
+ ksba_isotime_t signed_time;
+ const guint8 *der;
+ gsize der_len;
+ gpg_error_t err;
+
+ g_printerr("crypto_sign\n");
+
+ instance->certificate = GCR_PKCS11_CERTIFICATE(g_object_ref(gcr_combo_selector_get_selected(instance->selector)));
+ if (!instance->certificate) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "No certificate selected");
+ goto fatal;
+ }
+
+ der = gcr_certificate_get_der_data(GCR_CERTIFICATE(instance->certificate), &der_len);
+ if (!der) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "Certificate could not be decoded");
+ goto fatal;
+ }
+
+ err = ksba_cms_new (&instance->cms);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_new failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cms_set_content_type (instance->cms, 0, KSBA_CT_SIGNED_DATA);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_content_type failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cms_set_content_type (instance->cms, 1, KSBA_CT_DATA);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_content_type failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cert_new(&instance->signer);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cert_new failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cert_init_from_mem(instance->signer, der, der_len);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cert_init_from_mem failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ /*
+ * By default we extract the digest from the certificate.
+ *
+ * The cert keeps track of the digest and the type of key in the same oid,
+ * re-map so we just have the digest.
+ */
+ instance->hash_oid = ksba_cert_get_digest_algo (instance->signer);
+ instance->hash_alg = instance->hash_oid ? gcry_md_map_name (instance->hash_oid) : 0;
+
+ switch (instance->hash_alg) {
+ case GCRY_MD_SHA1:
+ instance->hash_oid = "1.3.14.3.2.26";
+ break;
+ case GCRY_MD_RMD160:
+ instance->hash_oid = "1.3.36.3.2.1";
+ break;
+ case GCRY_MD_SHA224:
+ instance->hash_oid = "2.16.840.1.101.3.4.2.4";
+ break;
+ case GCRY_MD_SHA256:
+ instance->hash_oid = "2.16.840.1.101.3.4.2.1";
+ break;
+ case GCRY_MD_SHA384:
+ instance->hash_oid = "2.16.840.1.101.3.4.2.2";
+ break;
+ case GCRY_MD_SHA512:
+ instance->hash_oid = "2.16.840.1.101.3.4.2.3";
+ break;
+
+ case GCRY_MD_MD5: /* Don't use MD5. */
+ case 0: /* No mapping existed for the cert. */
+ default: /* We don't have oids for these. */
+ /* if we don't recognise the algorithm, fall back to SHA256 */
+ instance->hash_oid = "2.16.840.1.101.3.4.2.1";
+ instance->hash_alg = GCRY_MD_SHA256;
+ break;
+ }
+
+ g_printerr("crypto_sign: %s %d\n", instance->hash_oid, instance->hash_alg);
+
+ err = ksba_cms_add_signer (instance->cms, instance->signer);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_add_signer failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = ksba_cms_add_digest_algo (instance->cms, instance->hash_oid);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_add_digest_algo '%s' failed: %s", instance->hash_oid, gpg_strerror (err));
+ goto fatal;
+ }
+
+ err = gcry_md_open (&instance->data_md, 0, 0);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_open failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ gcry_md_enable (instance->data_md, instance->hash_alg);
+
+ g_printerr("crypto_sign: after\n");
+
+ if (instance->detached) {
+
+ GtkTextIter start_iter, end_iter;
+ char *text;
+
+ unsigned char *digest;
+ size_t digest_len;
+
+ /*
+ * Hash the content of the buffer in one go.
+ */
+ gtk_text_buffer_get_start_iter( instance->buffer, &start_iter);
+ gtk_text_buffer_get_end_iter( instance->buffer, &end_iter);
+
+ text = gtk_text_buffer_get_text( instance->buffer, &start_iter, &end_iter, FALSE);
+
+ gcry_md_write (instance->data_md, text, strlen(text));
+
+ g_free(text);
+
+ digest = gcry_md_read (instance->data_md, instance->hash_alg);
+ digest_len = gcry_md_get_algo_dlen (instance->hash_alg);
+ if (!digest || !digest_len) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "gcry_md_read / gcry_md_get_algo_dlen failed");
+ goto fatal;
+ }
+
+ err = ksba_cms_set_message_digest (instance->cms, 0, digest, digest_len);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_message_digest failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ }
+
+ utc = g_time_zone_new_utc();
+ now = g_date_time_new_now(utc);
+
+ snprintf (signed_time, 16, "%04d%02d%02dT%02d%02d%02d",
+ g_date_time_get_year(now), g_date_time_get_month(now), g_date_time_get_day_of_month(now),
+ g_date_time_get_hour(now), g_date_time_get_minute(now), g_date_time_get_second(now));
+
+ g_date_time_unref(now);
+ g_time_zone_unref(utc);
+
+g_printerr("crypto_sign: %.16s\n", signed_time);
+
+ err = ksba_cms_set_signing_time (instance->cms, 0, signed_time);
+ if (err) {
+ gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_SIGN_ERROR, "ksba_cms_set_signing_time failed: %s", gpg_strerror (err));
+ goto fatal;
+ }
+
+ //ksba_cert_release (instance->signer);
+
+ gcr_pkcs11_certificate_lookup_issuer_async(GCR_CERTIFICATE(instance->certificate), instance->signtext->cancellable, crypto_sign_lookup, instance);
+
+ gtk_widget_set_visible(GTK_WIDGET(instance->progress), TRUE);
+ gtk_progress_bar_pulse (instance->progress);
+
+ if (gerror) {
+ GtkWidget* dialog;
+
+fatal:
+ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
+ GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
+ "%s", ("Redwax SignText - Error"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ ("Error: %s"),
+ gerror->message);
+
+ g_error_free (gerror);
+
+ gtk_widget_show (dialog);
+
+ }
+
+// if (certificate) {
+// g_object_unref(certificate);
+// }
+
+}
+
+
Modified: redwax-signtext/trunk/src/linux/crypto.h
==============================================================================
--- redwax-signtext/trunk/src/linux/crypto.h (original)
+++ redwax-signtext/trunk/src/linux/crypto.h Thu Sep 8 21:41:34 2022
@@ -31,6 +31,9 @@
void
crypto_instance_start(SignTextInstance *instance, GcrCollection *certificates);
+void
+crypto_sign(SignTextInstance *instance);
+
#endif
Modified: redwax-signtext/trunk/src/linux/message.c
==============================================================================
--- redwax-signtext/trunk/src/linux/message.c (original)
+++ redwax-signtext/trunk/src/linux/message.c Thu Sep 8 21:41:34 2022
@@ -32,6 +32,8 @@
SignTextInstance *instance = user_data;
g_printerr("message_sign_clicked\n");
+
+ crypto_sign(instance);
}
@@ -205,6 +207,7 @@
crypto_instance_start(instance, certificates);
#ifdef HAVE_GTK_BOX_APPEND
+ gtk_box_append (instance->box, GTK_WIDGET(instance->progress));
gtk_box_append (instance->box, GTK_WIDGET(instance->label));
gtk_box_append (instance->box, GTK_WIDGET(instance->textview));
gtk_box_append (instance->box, GTK_WIDGET(instance->label_agree));
@@ -212,6 +215,7 @@
gtk_box_append (instance->box, GTK_WIDGET(instance->pin));
gtk_box_append (instance->box, GTK_WIDGET(instance->buttons));
#else
+ gtk_box_pack_start (instance->box, GTK_WIDGET(instance->progress), FALSE, FALSE, 0);
gtk_box_pack_start (instance->box, GTK_WIDGET(instance->label), FALSE, FALSE, 0);
gtk_box_pack_start (instance->box, GTK_WIDGET(instance->textview), TRUE, TRUE, 0);
gtk_box_pack_start (instance->box, GTK_WIDGET(instance->label_agree), FALSE, FALSE, 0);
@@ -227,10 +231,11 @@
g_signal_connect(instance->cancel, "clicked", (GCallback)message_cancel_clicked, instance);
g_signal_connect(instance->sign, "clicked", (GCallback)message_sign_clicked, instance);
- gtk_widget_show_all (GTK_WIDGET(instance->box));
+// gtk_widget_show_all (GTK_WIDGET(instance->box));
gtk_widget_show_all(GTK_WIDGET(signtext->window));
+ gtk_widget_set_visible(GTK_WIDGET(instance->progress), FALSE);
}
Modified: redwax-signtext/trunk/src/linux/signtext.c
==============================================================================
--- redwax-signtext/trunk/src/linux/signtext.c (original)
+++ redwax-signtext/trunk/src/linux/signtext.c Thu Sep 8 21:41:34 2022
@@ -79,6 +79,11 @@
instance->uuid = g_strdup(uuid);
instance->uri = uri;
+ instance->detached = TRUE;
+
+ instance->progress = GTK_PROGRESS_BAR(gtk_progress_bar_new());
+ gtk_widget_set_visible(GTK_WIDGET(instance->progress), FALSE);
+
instance->label = GTK_LABEL(gtk_label_new (NULL));
instance->label_text = g_markup_printf_escaped("The site <b>%s</b> has requested you sign the following text message.", g_uri_get_host(instance->uri));
gtk_label_set_markup(instance->label, instance->label_text);
@@ -139,6 +144,7 @@
// if (instance->cancel) g_object_unref(instance->cancel);
// if (instance->sign) g_object_unref(instance->sign);
if (instance->box) g_object_unref(instance->box);
+ if (instance->certificate) g_object_unref(instance->certificate);
}
g_free(instance);
}
Modified: redwax-signtext/trunk/src/linux/signtext.h
==============================================================================
--- redwax-signtext/trunk/src/linux/signtext.h (original)
+++ redwax-signtext/trunk/src/linux/signtext.h Thu Sep 8 21:41:34 2022
@@ -22,6 +22,9 @@
#include <gcr/gcr-base.h>
#include <ui/gcr-ui.h>
+#include <ksba.h>
+#include <gcrypt.h>
+
#ifndef SIGNTEXT_H
#define SIGNTEXT_H
@@ -42,6 +45,7 @@
RST_CORE_ERROR_MISSING_CONTENT_TYPE,
RST_CORE_ERROR_REQUEST_NOT_RECOGNISED,
RST_CORE_ERROR_NO_MODULES,
+ RST_CORE_ERROR_SIGN_ERROR,
} SignTextCoreError;
typedef struct SignTextData {
@@ -71,8 +75,10 @@
GUri *uri;
gchar *uuid;
gint64 id;
+ gboolean detached;
GtkStack *stack;
+ GtkProgressBar *progress;
GtkLabel *label;
gchar *label_text;
GtkBox *box;
@@ -85,6 +91,16 @@
GtkButtonBox *buttons;
GtkButton *cancel;
GtkButton *sign;
+
+ GcrPkcs11Certificate *certificate;
+ GckSession *session;
+ GckObject *key;
+
+ ksba_cms_t cms;
+ ksba_cert_t signer;
+ const char *hash_oid;
+ int hash_alg;
+ gcry_md_hd_t data_md;
} SignTextInstance;
SignTextData *signtext_data_new();
More information about the rs-commit
mailing list