[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