[rs-commit] r73 - in /redwax-signtext/trunk/src/linux: crypto.c crypto.h message.c signtext.c signtext.h

rs-commit at redwax.eu rs-commit at redwax.eu
Tue Sep 20 14:28:10 CEST 2022


Author: minfrin at redwax.eu
Date: Tue Sep 20 14:28:08 2022
New Revision: 73

Log:
Wire in support for the CA strings.

Modified:
    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/crypto.c
==============================================================================
--- redwax-signtext/trunk/src/linux/crypto.c	(original)
+++ redwax-signtext/trunk/src/linux/crypto.c	Tue Sep 20 14:28:08 2022
@@ -27,67 +27,67 @@
 #define CK_CERTIFICATE_CATEGORY_TOKEN_USER 0x00000001UL
 #endif
 
+gboolean
+crypto_instance_append_ca(SignTextInstance *instance, const gchar *ca, GError **gerror)
+{
+  GBytes *bytes;
+  unsigned char *rder;
+  size_t rder_len;
+  gpg_error_t err;
+
+  g_printerr("crypto_instance_append_ca: %s\n", ca);
+
+  err = ksba_dn_str2der(ca, &rder, &rder_len);
+  if (err) {
+    *gerror = g_error_new(RST_CORE_ERROR, RST_CORE_ERROR_INVALID_CA, "Requested issuer '%s' cannot be parsed.", ca);
+    return FALSE;
+  }
+
+#if 0
+  g_printerr("crypto_instance_append_ca: len %d: ", (int)rder_len);
+for (size_t i = 0; i < rder_len; i++)
+  g_printerr("%02x", rder[i]);
+g_printerr("\n");
+
+char *str;
+ksba_dn_der2str(rder, rder_len, &str);
+  g_printerr("crypto_instance_append_ca: der2str %s\n", str);
+#endif
+
+  bytes = g_bytes_new_with_free_func(rder, rder_len, (GDestroyNotify)g_free, rder);
+
+  instance->cas = g_list_append(instance->cas, bytes);
+
+  return TRUE;
+}
+
 static gboolean
 crypto_filter_match (GObject *obj,
                     gpointer data)
 {
+  SignTextInstance *instance = data;
   GckAttributes *attrs;
-
-  ksba_cert_t cert;
-
-  const guint8 *der;
-  gsize der_len;
+  GcrCertificateChain *chain;
 
   gulong category;
-  gboolean is_ca;
-  unsigned int usage;
-
-  gpg_error_t err;
-
-  if (!GCR_IS_PKCS11_CERTIFICATE(obj)) {
+  GcrCertificateChainStatus status;
+
+  g_assert(GCR_IS_PKCS11_CERTIFICATE(obj));
+
+  g_printerr("crypto_filter_match\n");
+
+  chain = g_object_get_data(G_OBJECT (obj), "chain");
+
+  g_assert(GCR_IS_CERTIFICATE_CHAIN(chain));
+
+  status = gcr_certificate_chain_get_status(chain);
+
+  switch (status) {
+  case GCR_CERTIFICATE_CHAIN_ANCHORED:
+    break;
+  default:
     return FALSE;
   }
-
-
-  der = gcr_certificate_get_der_data(GCR_CERTIFICATE(obj), &der_len);
-  if (!der) {
-    return FALSE;
-  }
-
-  err = ksba_cert_new(&cert);
-  if (err) {
-    return FALSE;
-  }
-
-  err = ksba_cert_init_from_mem(cert, der, der_len);
-  if (err) {
-    ksba_cert_release(cert);
-    return FALSE;
-  }
-
-  /*
-   * Is the key usage section missing?
-   *
-   * If so, ignore this cert.
-   */
-  err = ksba_cert_get_key_usage(cert, &usage);
-  if (err) {
-    ksba_cert_release(cert);
-    return FALSE;
-  }
-
-  /*
-   * Does our certificate report a key usage of KSBA_KEYUSAGE_DIGITAL_SIGNATURE?
-   *
-   * If not, the cert needs to be ignored.
-   */
-  if (!(usage & KSBA_KEYUSAGE_DIGITAL_SIGNATURE)) {
-    ksba_cert_release(cert);
-    return FALSE;
-  }
-
-  ksba_cert_release(cert);
-
 
   attrs = gcr_pkcs11_certificate_get_attributes(GCR_PKCS11_CERTIFICATE(obj));
 
@@ -102,26 +102,66 @@
     }
   }
 
-  /*
-   * Is our certificate an intermediate? Filter them out at this stage.
-   */
-  if (gcr_certificate_get_basic_constraints(GCR_CERTIFICATE(obj), &is_ca, NULL)) {
-    if (is_ca) {
-      return FALSE;
-    }
+  g_printerr("crypto_filter_match: len %d\n", g_list_length(instance->cas));
+
+  if (instance->cas && g_list_length(instance->cas)) {
+
+    int i, len;
+
+    len = gcr_certificate_chain_get_length(chain);
+
+    for (i = 0; i < len; i++) {
+
+      GcrCertificate *certificate;
+      guchar *der;
+      gsize der_len;
+
+      GBytes *dn;
+
+      certificate = gcr_certificate_chain_get_certificate(chain, i);
+
+//  g_printerr("crypto_filter_match: consider cert issuer %s\n", gcr_certificate_get_issuer_dn(certificate));
+
+
+      der = gcr_certificate_get_issuer_raw(certificate, &der_len);
+      dn = g_bytes_new_with_free_func(der, der_len, (GDestroyNotify)g_free, der);
+
+#if 0
+  g_printerr("crypto_filter_match: len %d: ", (int)der_len);
+for (size_t i = 0; i < der_len; i++)
+  g_printerr("%02x", der[i]);
+g_printerr("\n");
+
+char *str;
+ksba_dn_der2str(der, der_len, &str);
+  g_printerr("crypto_filter_match: der2str %s\n", str);
+#endif
+
+      if (g_list_find_custom(instance->cas, dn, g_bytes_compare)) {
+        g_bytes_unref(dn);
+  g_printerr("crypto_filter_match: found\n");
+        return TRUE;
+      }
+
+      g_bytes_unref(dn);
+    }
+
+  g_printerr("crypto_filter_match: not found\n");
+
+    return FALSE;
   }
 
   return TRUE;
 }
 
 GcrCollection *
-crypto_filter(GcrCollection *certificates)
+crypto_filter(SignTextInstance *instance, GcrCollection *certificates)
 {
   GcrCollection *collection;
 
   collection = gcr_filter_collection_new_with_callback (GCR_COLLECTION (certificates),
 			crypto_filter_match,
-			NULL, NULL);
+			instance, NULL);
 
 
   return collection;
@@ -151,6 +191,108 @@
 static gboolean
 crypto_slot_do (gpointer user_data);
 
+static gboolean
+crypto_chain_do (gpointer user_data);
+
+static void
+crypto_chain_done (GObject *source_object,
+                  GAsyncResult *res,
+                  gpointer user_data)
+{
+  SignTextData *signtext = user_data;
+  GcrCertificateChain *chain = GCR_CERTIFICATE_CHAIN(source_object);
+  GcrCertificate *certificate;
+  GError *gerror = NULL;
+  GcrCertificateChainStatus status;
+
+  g_printerr("crypto_chain_done\n");
+
+  if (!gcr_certificate_chain_build_finish(chain, res, &gerror)) {
+    goto fatal;
+  }
+
+  certificate = gcr_certificate_chain_get_endpoint(chain);
+
+  g_object_set_data_full(G_OBJECT(certificate), "chain",
+                         g_object_ref(chain),
+                         (GDestroyNotify)g_object_unref);
+
+  status = gcr_certificate_chain_get_status(chain);
+
+  switch (status) {
+  case GCR_CERTIFICATE_CHAIN_ANCHORED:
+    g_printerr("crypto_chain_done: anchored\n");
+    break;
+  default:
+    g_printerr("crypto_chain_done: not anchored\n");
+    break;
+  }
+
+  signtext->incoming_len++;
+
+  if (signtext->incoming_len < gcr_collection_get_length(signtext->incoming)) {
+    g_idle_add((GSourceFunc)crypto_chain_do, signtext);
+  }
+  else {
+
+    GList *incoming, *current, *l;
+
+    incoming = gcr_collection_get_objects(signtext->incoming);
+
+    for (l = incoming; l; l = g_list_next (l)) {
+     if (!gcr_collection_contains(signtext->certificates, l->data)) {
+        g_object_ref(l->data);
+        gcr_simple_collection_add(GCR_SIMPLE_COLLECTION(signtext->certificates), l->data);
+g_printerr("crypto_chain_done: add\n");
+      }
+    }
+
+    current = gcr_collection_get_objects(signtext->certificates);
+
+    for (l = current; l; l = g_list_next (l)) {
+      if (!gcr_collection_contains(signtext->incoming, l->data)) {
+        gcr_simple_collection_remove(GCR_SIMPLE_COLLECTION(signtext->certificates), l->data);
+        g_object_unref(l->data);
+g_printerr("crypto_chain_done: remove\n");
+      }
+    }
+
+    g_object_unref(signtext->incoming);
+    signtext->incoming = gcr_simple_collection_new();
+
+    g_timeout_add_seconds(2, crypto_slots_do, signtext);
+  }
+
+  if (gerror) {
+fatal:
+    signtext_error (NULL, gerror);
+    g_error_free (gerror);
+  }
+
+}
+
+static gboolean
+crypto_chain_do (gpointer user_data)
+{
+  SignTextData *signtext = user_data;
+
+  GList *incoming = gcr_collection_get_objects (signtext->incoming);
+
+  GList *current = g_list_nth (incoming, signtext->incoming_len);
+
+  GcrCertificateChain *chain = gcr_certificate_chain_new();
+
+  g_printerr("crypto_chain_do\n");
+
+  gcr_certificate_chain_add (chain, current->data);
+
+  gcr_certificate_chain_build_async(chain, GCR_PURPOSE_CLIENT_AUTH, NULL, GCR_CERTIFICATE_CHAIN_NONE, signtext->cancellable, crypto_chain_done, signtext);
+
+  g_list_free(incoming);
+
+  return FALSE;
+}
+
 static void
 crypto_slot_done (GObject *source_object,
                   GAsyncResult *res,
@@ -158,7 +300,7 @@
 {
   SignTextToken *signtext_token = user_data;
   SignTextData *signtext = signtext_token->signtext;
-  GList *incoming, *current, *l;
+  GList *incoming, *l;
   GError *gerror = NULL;
   guint certificates_len;
 
@@ -167,6 +309,18 @@
   incoming = gck_enumerator_next_finish(GCK_ENUMERATOR(source_object), res, &gerror);
 
   for (l = incoming, certificates_len = 0; l; l = g_list_next (l), certificates_len++) {
+
+    gboolean is_ca;
+
+    /*
+     * Is our certificate an intermediate? Filter them out at this stage.
+     */
+    if (gcr_certificate_get_basic_constraints(GCR_CERTIFICATE(l->data), &is_ca, NULL)) {
+      if (is_ca) {
+        continue;
+      }
+    }
+
     if (!gcr_collection_contains(signtext->incoming, l->data)) {
       g_object_ref(l->data);
 
@@ -190,29 +344,7 @@
     g_idle_add((GSourceFunc)crypto_slot_do, signtext_token->next);
   }
   else {
-
-    incoming = gcr_collection_get_objects(signtext->incoming);
-
-    for (l = incoming; l; l = g_list_next (l)) {
-     if (!gcr_collection_contains(signtext->certificates, l->data)) {
-        g_object_ref(l->data);
-        gcr_simple_collection_add(GCR_SIMPLE_COLLECTION(signtext->certificates), l->data);
-      }
-    }
-
-    current = gcr_collection_get_objects(signtext->certificates);
-
-    for (l = current; l; l = g_list_next (l)) {
-      if (!gcr_collection_contains(signtext->incoming, l->data)) {
-        gcr_simple_collection_remove(GCR_SIMPLE_COLLECTION(signtext->certificates), l->data);
-        g_object_unref(l->data);
-      }
-    }
-
-    g_object_unref(signtext->incoming);
-    signtext->incoming = gcr_simple_collection_new();
-
-    g_timeout_add_seconds(2, crypto_slots_do, signtext_token->signtext);
+    g_idle_add((GSourceFunc)crypto_chain_do, signtext);
   }
 
   signtext_token_free(signtext_token);
@@ -293,6 +425,7 @@
 
     signtext->slots_len = slots_len;
     signtext->certificates_len = 0;
+    signtext->incoming_len = 0;
 
     return FALSE;
   }

Modified: redwax-signtext/trunk/src/linux/crypto.h
==============================================================================
--- redwax-signtext/trunk/src/linux/crypto.h	(original)
+++ redwax-signtext/trunk/src/linux/crypto.h	Tue Sep 20 14:28:08 2022
@@ -26,10 +26,13 @@
 crypto_start(SignTextData *signtext);
 
 GcrCollection *
-crypto_filter(GcrCollection *certificates);
+crypto_filter(SignTextInstance *instance, GcrCollection *certificates);
 
 void
 crypto_instance_start(SignTextInstance *instance, GcrCollection *certificates);
+
+gboolean
+crypto_instance_append_ca(SignTextInstance *instance, const gchar *ca, GError **gerror);
 
 void
 crypto_sign(SignTextInstance *instance);

Modified: redwax-signtext/trunk/src/linux/message.c
==============================================================================
--- redwax-signtext/trunk/src/linux/message.c	(original)
+++ redwax-signtext/trunk/src/linux/message.c	Tue Sep 20 14:28:08 2022
@@ -47,7 +47,7 @@
   /*
    * Send an error to show we cancelled.
    */
-  message_send_error(instance, "error:cancelled");
+  message_send_error(instance, "error:userCancel");
 
   signtext_instance_free(instance);
 
@@ -163,7 +163,23 @@
      */
     else if (json_node_get_node_type(request) == JSON_NODE_OBJECT) {
 
-        GcrCollection *certificates = crypto_filter(signtext->certificates);
+        GcrCollection *certificates;
+
+        JsonArray *cas = json_object_get_array_member(json_node_get_object(request), "CAs");
+
+        if (cas) {
+            guint len = json_array_get_length(cas);
+            guint i;
+
+            for (i = 0; i < len; i++) {
+                const gchar *ca = json_array_get_string_element(cas, i);
+
+                crypto_instance_append_ca(instance, ca, &gerror);
+            }
+
+        }
+
+        certificates = crypto_filter(instance, signtext->certificates);
 
         crypto_instance_start(instance, certificates);
  
@@ -470,7 +486,7 @@
   json_builder_set_member_name(builder, "id");
   json_builder_add_int_value(builder, instance->id);
   json_builder_set_member_name(builder, "error");
-  json_builder_add_string_value(builder, "error:cancelled");
+  json_builder_add_string_value(builder, "error:userCancel");
   json_builder_end_object(builder);
 
   root = json_builder_get_root(builder);

Modified: redwax-signtext/trunk/src/linux/signtext.c
==============================================================================
--- redwax-signtext/trunk/src/linux/signtext.c	(original)
+++ redwax-signtext/trunk/src/linux/signtext.c	Tue Sep 20 14:28:08 2022
@@ -173,6 +173,12 @@
     if (instance->w) {
       ksba_writer_release(instance->w);
     }
+
+    if (instance->cas) {
+      g_list_foreach(instance->cas, (GFunc)g_bytes_unref, NULL);
+      g_list_free (instance->cas);
+    }
+
   }
   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	Tue Sep 20 14:28:08 2022
@@ -44,6 +44,7 @@
   RST_CORE_ERROR_MISSING_REQUEST,
   RST_CORE_ERROR_MISSING_CONTENT_TYPE,
   RST_CORE_ERROR_REQUEST_NOT_RECOGNISED,
+  RST_CORE_ERROR_INVALID_CA,
   RST_CORE_ERROR_NO_MODULES,
   RST_CORE_ERROR_SIGN_ERROR,
 } SignTextCoreError;
@@ -61,6 +62,7 @@
   guint modules_len;
   guint slots_len;
   guint certificates_len;
+  guint incoming_len;
 } SignTextData;
 
 typedef struct SignTextToken SignTextToken;
@@ -78,6 +80,8 @@
   gchar *uuid;
   gint64 id;
   gboolean detached;
+
+  GList *cas;
 
   GtkStack *stack;
   GtkProgressBar *progress;



More information about the rs-commit mailing list