gcr: Complete and make gcr_fingerprint_xxx functions public
authorStef Walter <stefw@collabora.co.uk>
Wed, 5 Oct 2011 07:07:15 +0000 (09:07 +0200)
committerStef Walter <stefw@collabora.co.uk>
Wed, 5 Oct 2011 07:07:15 +0000 (09:07 +0200)
 * These functions create consistent key fingerpints for
   public, private and certificates.

docs/reference/gcr/gcr-docs.sgml
docs/reference/gcr/gcr-sections.txt
gcr/Makefile.am
gcr/gcr-certificate-renderer.c
gcr/gcr-fingerprint.c
gcr/gcr-fingerprint.h
gcr/gcr-key-renderer.c
gcr/tests/test-fingerprint.c

index 4746d57..3af9837 100644 (file)
@@ -57,6 +57,7 @@
        <part id="misc">
                <title>Miscellaneous</title>
                <xi:include href="xml/gcr-library.xml"/>
+               <xi:include href="xml/gcr-fingerprint.xml"/>
                <xi:include href="xml/gcr-secret-exchange.xml"/>
                <xi:include href="xml/gcr-misc.xml"/>
        </part>
index 6cf19bc..63372f9 100644 (file)
@@ -575,6 +575,13 @@ GcrSecretExchangePrivate
 </SECTION>
 
 <SECTION>
+<FILE>gcr-fingerprint</FILE>
+gcr_fingerprint_from_attributes
+gcr_fingerprint_from_certificate_public_key
+gcr_fingerprint_from_subject_public_key_info
+</SECTION>
+
+<SECTION>
 <FILE>gcr-private</FILE>
 <SUBSECTION Private>
 GCR_GNUPG_COLLECTION
index 436f725..06ba726 100644 (file)
@@ -20,6 +20,7 @@ HEADER_BASE_FILES = \
        gcr-collection.h \
        gcr-comparable.h \
        gcr-deprecated-base.h \
+       gcr-fingerprint.h \
        gcr-icons.h \
        gcr-importer.h \
        gcr-import-interaction.h \
@@ -100,6 +101,7 @@ libgcr_base_@GCR_MAJOR@_la_SOURCES = \
        gcr-collection.c gcr-collection.h \
        gcr-comparable.c gcr-comparable.h \
        gcr-debug.c gcr-debug.h \
+       gcr-fingerprint.c gcr-fingerprint.h \
        gcr-gnupg-collection.c gcr-gnupg-collection.h \
        gcr-gnupg-importer.c gcr-gnupg-importer.h \
        gcr-gnupg-key.c gcr-gnupg-key.h \
@@ -143,7 +145,6 @@ libgcr_@GCR_MAJOR@_la_SOURCES = \
        gcr-display-scrolled.c gcr-display-scrolled.h \
        gcr-display-view.c gcr-display-view.h \
        gcr-failure-renderer.c gcr-failure-renderer.h \
-       gcr-fingerprint.c gcr-fingerprint.h \
        gcr-gnupg-renderer.c gcr-gnupg-renderer.h \
        gcr-gnupg-records.c gcr-gnupg-records.h \
        gcr-import-button.c gcr-import-button.h \
index e6d5df7..7995917 100644 (file)
@@ -708,7 +708,7 @@ gcr_certificate_renderer_render (GcrRenderer *renderer, GcrViewer *viewer)
 
        value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "tbsCertificate",
                                                           "subjectPublicKeyInfo", NULL), &n_value);
-       raw = _gcr_fingerprint_from_subject_public_key_info (value, n_value, G_CHECKSUM_SHA1, &n_raw);
+       raw = gcr_fingerprint_from_subject_public_key_info (value, n_value, G_CHECKSUM_SHA1, &n_raw);
        _gcr_display_view_append_hex (view, renderer, _("Key SHA1 Fingerprint"), raw, n_raw);
        g_free (raw);
 
index 37a1df6..9b43dca 100644 (file)
 #include <glib.h>
 #include <gcrypt.h>
 
-gpointer
-_gcr_fingerprint_from_subject_public_key_info (gconstpointer key_info, gsize n_key_info,
-                                               GChecksumType checksum_type,
-                                               gsize *n_fingerprint)
+/**
+ * SECTION:gcr-fingerprint
+ * @title: Key Fingerprints
+ * @short_description: Fingerprints for public and private keys
+ *
+ * These functions generate key fingerprints for public keys, certificates and
+ * key data. The fingerprints are created so that they they will be identical
+ * for a key and its corresponding certificate.
+ *
+ * Note that in the case of certificates these are not fingerprints of the
+ * actual certificate data, but rather of the public key contained in a
+ * certificate.
+ *
+ * These fingerprints are created using the subjectPublicKeyInfo ASN.1 structure.
+ */
+
+/**
+ * gcr_fingerprint_from_subject_public_key_info:
+ * @key_info: (array length=n_key_info): DER encoded subjectPublicKeyInfo structure
+ * @n_key_info: length of DER encoded structure
+ * @checksum_type: the type of fingerprint to create
+ * @n_fingerprint: the length of fingerprint returned
+ *
+ * Create a key fingerprint for a DER encoded subjectPublicKeyInfo.
+ *
+ * Returns: (transfer full) (allow-none) (array length=n_fingerprint): the
+ *          fingerprint or %NULL if the input was invalid.
+ */
+guchar *
+gcr_fingerprint_from_subject_public_key_info (const guchar *key_info,
+                                              gsize n_key_info,
+                                              GChecksumType checksum_type,
+                                              gsize *n_fingerprint)
 {
        GChecksum *check;
        guint8 *fingerprint;
@@ -60,7 +89,8 @@ _gcr_fingerprint_from_subject_public_key_info (gconstpointer key_info, gsize n_k
 static gboolean
 rsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
 {
-       GckAttribute *attr;
+       GckAttribute *modulus;
+       GckAttribute *exponent;
        GNode *key_asn;
        GNode *params_asn;
        gpointer key, params;
@@ -68,21 +98,22 @@ rsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
 
        _gcr_oids_init ();
 
+       modulus = gck_attributes_find (attrs, CKA_MODULUS);
+       exponent = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
+       if (modulus == NULL || exponent == NULL)
+               return FALSE;
+
        key_asn = egg_asn1x_create (pk_asn1_tab, "RSAPublicKey");
        g_return_val_if_fail (key_asn, FALSE);
 
        params_asn = egg_asn1x_create (pk_asn1_tab, "RSAParameters");
        g_return_val_if_fail (params_asn, FALSE);
 
-       attr = gck_attributes_find (attrs, CKA_MODULUS);
-       g_return_val_if_fail (attr, FALSE);
        egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "modulus", NULL),
-                                     attr->value, attr->length, NULL);
+                                     modulus->value, modulus->length, NULL);
 
-       attr = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
-       g_return_val_if_fail (attr, FALSE);
        egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "publicExponent", NULL),
-                                     attr->value, attr->length, NULL);
+                                     exponent->value, exponent->length, NULL);
 
        key = egg_asn1x_encode (key_asn, g_realloc, &n_key);
        egg_asn1x_destroy (key_asn);
@@ -142,40 +173,35 @@ dsa_subject_public_key_from_private (GNode *key_asn, GckAttribute *ap,
 }
 
 static gboolean
-dsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
+dsa_subject_public_key_from_attributes (GckAttributes *attrs,
+                                        gulong klass,
+                                        GNode *info_asn)
 {
        GckAttribute *value, *g, *q, *p;
        GNode *key_asn, *params_asn;
        gpointer key, params;
        gsize n_key, n_params;
-       gulong klass;
 
        _gcr_oids_init ();
 
+       p = gck_attributes_find (attrs, CKA_PRIME);
+       q = gck_attributes_find (attrs, CKA_SUBPRIME);
+       g = gck_attributes_find (attrs, CKA_BASE);
+       value = gck_attributes_find (attrs, CKA_VALUE);
+
+       if (p == NULL || q == NULL || g == NULL || value == NULL)
+               return FALSE;
+
        key_asn = egg_asn1x_create (pk_asn1_tab, "DSAPublicPart");
        g_return_val_if_fail (key_asn, FALSE);
 
        params_asn = egg_asn1x_create (pk_asn1_tab, "DSAParameters");
        g_return_val_if_fail (params_asn, FALSE);
 
-       if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
-               klass = CKO_PUBLIC_KEY;
-
-       p = gck_attributes_find (attrs, CKA_PRIME);
-       g_return_val_if_fail (p, FALSE);
        egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "p", NULL), p->value, p->length, NULL);
-
-       q = gck_attributes_find (attrs, CKA_SUBPRIME);
-       g_return_val_if_fail (q, FALSE);
        egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "q", NULL), q->value, q->length, NULL);
-
-       g = gck_attributes_find (attrs, CKA_BASE);
-       g_return_val_if_fail (g, FALSE);
        egg_asn1x_set_integer_as_usg (egg_asn1x_node (params_asn, "g", NULL), g->value, g->length, NULL);
 
-       value = gck_attributes_find (attrs, CKA_VALUE);
-       g_return_val_if_fail (value, FALSE);
-
        /* Are these attributes for a public or private key? */
        if (klass == CKO_PRIVATE_KEY) {
 
@@ -185,6 +211,9 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
 
        } else if (klass == CKO_PUBLIC_KEY) {
                egg_asn1x_set_integer_as_usg (key_asn, value->value, value->length, NULL);
+
+       } else {
+               g_assert_not_reached ();
        }
 
        key = egg_asn1x_encode (key_asn, g_realloc, &n_key);
@@ -203,9 +232,11 @@ dsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
        return TRUE;
 }
 
-gpointer
-_gcr_fingerprint_from_attributes (GckAttributes *attrs, GChecksumType checksum_type,
-                                  gsize *n_fingerprint)
+static gpointer
+fingerprint_from_key_attributes (GckAttributes *attrs,
+                                 gulong klass,
+                                 GChecksumType checksum_type,
+                                 gsize *n_fingerprint)
 {
        gpointer fingerprint = NULL;
        gboolean ret = FALSE;
@@ -214,32 +245,140 @@ _gcr_fingerprint_from_attributes (GckAttributes *attrs, GChecksumType checksum_t
        gulong key_type;
        gsize n_info;
 
-       g_return_val_if_fail (attrs, FALSE);
-       g_return_val_if_fail (n_fingerprint, FALSE);
-
        if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &key_type))
-               g_return_val_if_reached (FALSE);
+               return NULL;
 
        info_asn = egg_asn1x_create (pkix_asn1_tab, "SubjectPublicKeyInfo");
-       g_return_val_if_fail (info_asn, FALSE);
+       g_return_val_if_fail (info_asn, NULL);
 
        if (key_type == CKK_RSA)
                ret = rsa_subject_public_key_from_attributes (attrs, info_asn);
 
        else if (key_type == CKK_DSA)
-               ret = dsa_subject_public_key_from_attributes (attrs, info_asn);
+               ret = dsa_subject_public_key_from_attributes (attrs, klass, info_asn);
 
        else
-               g_return_val_if_reached (FALSE);
+               ret = FALSE;
 
        if (ret) {
                info = egg_asn1x_encode (info_asn, g_realloc, &n_info);
-               fingerprint = _gcr_fingerprint_from_subject_public_key_info (info, n_info,
-                                                                            checksum_type,
-                                                                            n_fingerprint);
+               fingerprint = gcr_fingerprint_from_subject_public_key_info (info, n_info,
+                                                                           checksum_type,
+                                                                           n_fingerprint);
                g_free (info);
        }
 
        egg_asn1x_destroy (info_asn);
        return fingerprint;
 }
+
+static guchar *
+fingerprint_from_cert_value (const guchar *der_data,
+                             gsize n_der_data,
+                             GChecksumType checksum_type,
+                             gsize *n_fingerprint)
+{
+       guchar *fingerprint;
+       GNode *cert_asn;
+       gconstpointer info;
+       gsize n_info;
+
+       cert_asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate",
+                                               der_data, n_der_data);
+       if (cert_asn == NULL)
+               return NULL;
+
+       info = egg_asn1x_get_raw_element (egg_asn1x_node (cert_asn, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_info);
+       g_return_val_if_fail (info != NULL, NULL);
+
+       fingerprint = gcr_fingerprint_from_subject_public_key_info (info, n_info,
+                                                                   checksum_type,
+                                                                   n_fingerprint);
+
+       egg_asn1x_destroy (cert_asn);
+       return fingerprint;
+}
+
+static guchar *
+fingerprint_from_cert_attributes (GckAttributes *attrs,
+                                  GChecksumType checksum_type,
+                                  gsize *n_fingerprint)
+{
+       GckAttribute *attr;
+
+       attr = gck_attributes_find (attrs, CKA_VALUE);
+       if (attr == NULL)
+               return NULL;
+
+       return fingerprint_from_cert_value (attr->value, attr->length, checksum_type,
+                                           n_fingerprint);
+}
+
+/**
+ * gcr_fingerprint_from_attributes:
+ * @attrs: attributes for key or certificate
+ * @checksum_type: the type of fingerprint to create
+ * @n_fingerprint: the length of fingerprint returned
+ *
+ * Create a key fingerprint for a certificate, public key or private key.
+ * Note that this is not a fingerprint of certificate data, which you would
+ * use gcr_certificate_get_fingerprint() for.
+ *
+ * Returns: (transfer full) (allow-none) (array length=n_fingerprint): the
+ *          fingerprint or %NULL if the input was invalid.
+ */
+guchar *
+gcr_fingerprint_from_attributes (GckAttributes *attrs,
+                                  GChecksumType checksum_type,
+                                  gsize *n_fingerprint)
+{
+       gulong klass;
+
+       g_return_val_if_fail (attrs, FALSE);
+       g_return_val_if_fail (n_fingerprint, FALSE);
+
+       if (!gck_attributes_find_ulong (attrs, CKA_CLASS, &klass))
+               return NULL;
+
+       if (klass == CKO_CERTIFICATE)
+               return fingerprint_from_cert_attributes (attrs, checksum_type,
+                                                        n_fingerprint);
+
+       else if (klass == CKO_PUBLIC_KEY || klass == CKO_PRIVATE_KEY)
+               return fingerprint_from_key_attributes (attrs, klass,
+                                                       checksum_type,
+                                                       n_fingerprint);
+
+       else
+               return NULL;
+}
+
+/**
+ * gcr_fingerprint_from_attributes:
+ * @attrs: attributes for key or certificate
+ * @checksum_type: the type of fingerprint to create
+ * @n_fingerprint: the length of fingerprint returned
+ *
+ * Create a key fingerprint for a certificate's public key. Note that this is
+ * not a fingerprint of certificate data, which you would use
+ * gcr_certificate_get_fingerprint() for.
+ *
+ * Returns: (transfer full) (allow-none) (array length=n_fingerprint): the
+ *          fingerprint or %NULL if the input was invalid.
+ */
+guchar *
+gcr_fingerprint_from_certificate_public_key (GcrCertificate *certificate,
+                                             GChecksumType checksum_type,
+                                             gsize *n_fingerprint)
+{
+       const guchar *der_data;
+       gsize n_der_data;
+
+       g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), NULL);
+
+       der_data = gcr_certificate_get_der_data (certificate, &n_der_data);
+       g_return_val_if_fail (der_data != NULL, NULL);
+
+       return fingerprint_from_cert_value (der_data, n_der_data, checksum_type,
+                                           n_fingerprint);
+}
index 091bd81..84cc41f 100644 (file)
  * 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_FINGERPRINT_H
 #define GCR_FINGERPRINT_H
 
 #include <glib.h>
 
 #include "gcr-types.h"
+#include "gcr-certificate.h"
+
+guchar *        gcr_fingerprint_from_subject_public_key_info    (const guchar *key_info,
+                                                                 gsize n_key_info,
+                                                                 GChecksumType checksum_type,
+                                                                 gsize *n_fingerprint);
 
-gpointer        _gcr_fingerprint_from_subject_public_key_info    (gconstpointer key_info,
-                                                                  gsize n_key_info,
-                                                                  GChecksumType checksum_type,
-                                                                  gsize *n_fingerprint);
+guchar *        gcr_fingerprint_from_attributes                 (GckAttributes *attrs,
+                                                                 GChecksumType checksum_type,
+                                                                 gsize *n_fingerprint);
 
-gpointer        _gcr_fingerprint_from_attributes                 (GckAttributes *attrs,
-                                                                  GChecksumType checksum_type,
-                                                                  gsize *n_fingerprint);
+guchar *        gcr_fingerprint_from_certificate_public_key     (GcrCertificate *certificate,
+                                                                 GChecksumType checksum_type,
+                                                                 gsize *n_fingerprint);
 
 #endif /* GCR_FINGERPRINT_H_ */
index c23d77c..9102069 100644 (file)
@@ -323,14 +323,14 @@ gcr_key_renderer_real_render (GcrRenderer *renderer, GcrViewer *viewer)
        /* Fingerprints */
        _gcr_display_view_append_heading (view, renderer, _("Fingerprints"));
 
-       fingerprint = _gcr_fingerprint_from_attributes (self->pv->attributes,
-                                                       G_CHECKSUM_SHA1, &n_fingerprint);
+       fingerprint = gcr_fingerprint_from_attributes (self->pv->attributes,
+                                                      G_CHECKSUM_SHA1, &n_fingerprint);
        if (fingerprint) {
                _gcr_display_view_append_hex (view, renderer, _("SHA1"), fingerprint, n_fingerprint);
                g_free (fingerprint);
        }
-       fingerprint = _gcr_fingerprint_from_attributes (self->pv->attributes,
-                                                       G_CHECKSUM_SHA256, &n_fingerprint);
+       fingerprint = gcr_fingerprint_from_attributes (self->pv->attributes,
+                                                      G_CHECKSUM_SHA256, &n_fingerprint);
        if (fingerprint) {
                _gcr_display_view_append_hex (view, renderer, _("SHA256"), fingerprint, n_fingerprint);
                g_free (fingerprint);
index 1c5dcf9..0270758 100644 (file)
@@ -113,6 +113,20 @@ parse_attributes_for_key (gpointer data, gsize n_data)
        return attrs;
 }
 
+static GckAttributes *
+build_attributes_for_cert (guchar *data,
+                           gsize n_data)
+{
+       GckAttributes *attrs;
+
+       attrs = gck_attributes_new ();
+       gck_attributes_add_data (attrs, CKA_VALUE, data, n_data);
+       gck_attributes_add_ulong (attrs, CKA_CLASS, CKO_CERTIFICATE);
+       gck_attributes_add_ulong (attrs, CKA_CERTIFICATE_TYPE, CKC_X_509);
+
+       return attrs;
+}
+
 static gconstpointer
 parse_subject_public_key_info_for_cert (gpointer data, gsize n_data, gsize *n_info)
 {
@@ -132,45 +146,57 @@ parse_subject_public_key_info_for_cert (gpointer data, gsize n_data, gsize *n_in
 static void
 test_rsa (Test *test, gconstpointer unused)
 {
-       GckAttributes *key;
+       GckAttributes *key, *cert;
        gconstpointer info;
        gsize n_info;
-       gpointer fingerprint1, fingerprint2;
-       gsize n_fingerprint1, n_fingerprint2;
+       guchar *fingerprint1, *fingerprint2, *fingerprint3;
+       gsize n_fingerprint1, n_fingerprint2, n_fingerprint3;
 
        key = parse_attributes_for_key (test->key_rsa, test->n_key_rsa);
        info = parse_subject_public_key_info_for_cert (test->cert_rsa, test->n_cert_rsa, &n_info);
+       cert = build_attributes_for_cert (test->cert_rsa, test->n_cert_rsa);
 
-       fingerprint1 = _gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1);
-       fingerprint2 = _gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2);
+       fingerprint1 = gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1);
+       fingerprint2 = gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2);
+       fingerprint3 = gcr_fingerprint_from_attributes (cert, G_CHECKSUM_SHA1, &n_fingerprint3);
 
        egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint2, n_fingerprint2);
+       egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint3, n_fingerprint3);
 
        g_free (fingerprint1);
        g_free (fingerprint2);
+       g_free (fingerprint3);
+
        gck_attributes_unref (key);
+       gck_attributes_unref (cert);
 }
 
 static void
 test_dsa (Test *test, gconstpointer unused)
 {
-       GckAttributes *key;
+       GckAttributes *key, *cert;
        gconstpointer info;
        gsize n_info;
-       gpointer fingerprint1, fingerprint2;
-       gsize n_fingerprint1, n_fingerprint2;
+       guchar *fingerprint1, *fingerprint2, *fingerprint3;
+       gsize n_fingerprint1, n_fingerprint2, n_fingerprint3;
 
        key = parse_attributes_for_key (test->key_dsa, test->n_key_dsa);
        info = parse_subject_public_key_info_for_cert (test->cert_dsa, test->n_cert_dsa, &n_info);
+       cert = build_attributes_for_cert (test->cert_dsa, test->n_cert_dsa);
 
-       fingerprint1 = _gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1);
-       fingerprint2 = _gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2);
+       fingerprint1 = gcr_fingerprint_from_subject_public_key_info (info, n_info, G_CHECKSUM_SHA1, &n_fingerprint1);
+       fingerprint2 = gcr_fingerprint_from_attributes (key, G_CHECKSUM_SHA1, &n_fingerprint2);
+       fingerprint3 = gcr_fingerprint_from_attributes (cert, G_CHECKSUM_SHA1, &n_fingerprint3);
 
        egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint2, n_fingerprint2);
+       egg_assert_cmpmem (fingerprint1, n_fingerprint1, ==, fingerprint3, n_fingerprint3);
 
        g_free (fingerprint1);
        g_free (fingerprint2);
+       g_free (fingerprint3);
+
        gck_attributes_unref (key);
+       gck_attributes_unref (cert);
 }
 
 int