[gcr] gcr: Implement functions for loading and using SubjectPublicKeyInfo
- From: Stefan Walter <stefw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gcr] gcr: Implement functions for loading and using SubjectPublicKeyInfo
- Date: Thu, 24 Nov 2011 06:58:33 +0000 (UTC)
commit c2c73dfc3ff6c94aa5615c1c8047ed8b862f7b6f
Author: Stef Walter <stefw collabora co uk>
Date: Fri Nov 18 13:22:40 2011 +0100
gcr: Implement functions for loading and using SubjectPublicKeyInfo
* Move key calculation routines into gcr-subject-public-key.c
* Move creation of SPK from gcr-fingerprint.c into here
* Implement loading of SPK from PKCS#11 certificates, public keys,
private keys
* Add support for parsing SubjectPublicKeyInfo to parser. Generates
attributes for a CKO_PUBLIC_KEY
* Fix bugs in DER encoding related to this.
* More tweaks on testing infrastructure
docs/reference/gcr/gcr-sections.txt | 1 -
egg/egg-asn1x.c | 11 +-
egg/egg-testing.h | 2 +
gck/gck-mock.c | 7 +-
gcr/Makefile.am | 4 +-
gcr/gcr-base.symbols | 1 -
gcr/gcr-certificate-req-renderer.c | 16 +-
gcr/gcr-certificate.c | 4 +-
gcr/gcr-debug.c | 1 +
gcr/gcr-debug.h | 1 +
gcr/gcr-fingerprint.c | 327 +-------------
gcr/gcr-fingerprint.h | 4 -
gcr/gcr-key-size.c | 106 -----
gcr/gcr-key-size.h | 33 --
gcr/gcr-parser.c | 117 +++++
gcr/gcr-subject-public-key.c | 848 +++++++++++++++++++++++++++++++++++
gcr/gcr-subject-public-key.h | 55 +++
gcr/gcr-types.h | 2 +
gcr/tests/Makefile.am | 1 +
gcr/tests/files/client.spk | Bin 0 -> 294 bytes
gcr/tests/files/generic-dsa.spk | Bin 0 -> 443 bytes
gcr/tests/test-subject-public-key.c | 721 +++++++++++++++++++++++++++++
po/POTFILES.in | 1 +
23 files changed, 1785 insertions(+), 478 deletions(-)
---
diff --git a/docs/reference/gcr/gcr-sections.txt b/docs/reference/gcr/gcr-sections.txt
index 9e52421..adcb740 100644
--- a/docs/reference/gcr/gcr-sections.txt
+++ b/docs/reference/gcr/gcr-sections.txt
@@ -616,7 +616,6 @@ GcrSecretExchangePrivate
<SECTION>
<FILE>gcr-fingerprint</FILE>
gcr_fingerprint_from_attributes
-gcr_fingerprint_from_certificate_public_key
gcr_fingerprint_from_subject_public_key_info
</SECTION>
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index b7890e8..fc80d8f 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -1703,6 +1703,8 @@ anode_encoder_bit_string (gpointer user_data,
static gboolean
anode_encode_prepare_simple (GNode *node, gboolean want)
{
+ EggBytes *backing;
+ EggBytes *bytes;
Aenc *enc;
Atlv *tlv;
@@ -1713,8 +1715,13 @@ anode_encode_prepare_simple (GNode *node, gboolean want)
/* Transfer the tlv data over to enc */
enc = anode_get_enc_data (node);
if (enc == NULL) {
- anode_set_enc_data (node, anode_encoder_data,
- (guchar *)tlv->buf + tlv->off, NULL);
+ backing = anode_get_backing (node);
+ if (backing == NULL)
+ return FALSE;
+
+ bytes = egg_bytes_new_with_free_func ((guchar *)tlv->buf + tlv->off, tlv->len,
+ egg_bytes_unref, egg_bytes_ref (backing));
+ anode_set_enc_data (node, anode_encoder_bytes, bytes, egg_bytes_unref);
}
tlv->buf = tlv->end = NULL;
diff --git a/egg/egg-testing.h b/egg/egg-testing.h
index a08c34a..a15925a 100644
--- a/egg/egg-testing.h
+++ b/egg/egg-testing.h
@@ -67,6 +67,8 @@ gchar * egg_test_escape_data (const guchar *data,
void egg_test_wait_stop (void);
+#define egg_test_wait() g_assert (egg_test_wait_until (20000) != FALSE)
+
gboolean egg_test_wait_until (int timeout);
gint egg_tests_run_with_loop (void);
diff --git a/gck/gck-mock.c b/gck/gck-mock.c
index a1fdba9..716b149 100644
--- a/gck/gck-mock.c
+++ b/gck/gck-mock.c
@@ -913,13 +913,12 @@ gck_mock_C_GetAttributeValue (CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObje
CK_ULONG i;
session = g_hash_table_lookup (the_sessions, GUINT_TO_POINTER (hSession));
- g_return_val_if_fail (session, CKR_SESSION_HANDLE_INVALID);
+ if (session == NULL)
+ return CKR_SESSION_HANDLE_INVALID;
attrs = lookup_object (session, hObject);
- if (!attrs) {
- g_assert_not_reached (); /* "invalid object handle passed" */
+ if (!attrs)
return CKR_OBJECT_HANDLE_INVALID;
- }
for (i = 0; i < ulCount; ++i) {
result = pTemplate + i;
diff --git a/gcr/Makefile.am b/gcr/Makefile.am
index 2045125..addfca0 100644
--- a/gcr/Makefile.am
+++ b/gcr/Makefile.am
@@ -113,7 +113,6 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
gcr-importer.c gcr-importer.h \
gcr-import-interaction.c gcr-import-interaction.h \
gcr-internal.h \
- gcr-key-size.c gcr-key-size.h \
gcr-library.c gcr-library.h \
gcr-memory.c \
gcr-memory-icon.c gcr-memory-icon.h \
@@ -127,6 +126,7 @@ libgcr_base_ GCR_MAJOR@_la_SOURCES = \
gcr-simple-certificate.c gcr-simple-certificate.h \
gcr-simple-collection.c gcr-simple-collection.h \
gcr-single-collection.c gcr-single-collection.h \
+ gcr-subject-public-key.c gcr-subject-public-key.h \
gcr-trust.c gcr-trust.h \
gcr-types.h \
gcr-union-collection.c gcr-union-collection.h \
@@ -152,7 +152,6 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
gcr-gnupg-records.c gcr-gnupg-records.h \
gcr-import-button.c gcr-import-button.h \
gcr-key-renderer.c gcr-key-renderer.h \
- gcr-key-size.c gcr-key-size.h \
gcr-key-widget.c gcr-key-widget.h \
gcr-list-selector.c gcr-list-selector.h gcr-list-selector-private.h \
gcr-live-search.c gcr-live-search.h \
@@ -163,6 +162,7 @@ libgcr_ GCR_MAJOR@_la_SOURCES = \
gcr-pkcs11-import-dialog.c gcr-pkcs11-import-dialog.h \
gcr-record.c gcr-record.h \
gcr-renderer.c gcr-renderer.h \
+ gcr-subject-public-key.c gcr-subject-public-key.h \
gcr-tree-selector.c gcr-tree-selector.h \
gcr-unlock-options.h \
gcr-unlock-options-widget.c gcr-unlock-options-widget.h \
diff --git a/gcr/gcr-base.symbols b/gcr/gcr-base.symbols
index 7d0be13..8d96291 100644
--- a/gcr/gcr-base.symbols
+++ b/gcr/gcr-base.symbols
@@ -59,7 +59,6 @@ gcr_filter_collection_new_with_callback
gcr_filter_collection_refilter
gcr_filter_collection_set_callback
gcr_fingerprint_from_attributes
-gcr_fingerprint_from_certificate_public_key
gcr_fingerprint_from_subject_public_key_info
gcr_icon_for_token
gcr_importer_create_for_parsed
diff --git a/gcr/gcr-certificate-req-renderer.c b/gcr/gcr-certificate-req-renderer.c
index 4b41bee..a6b4f01 100644
--- a/gcr/gcr-certificate-req-renderer.c
+++ b/gcr/gcr-certificate-req-renderer.c
@@ -22,20 +22,8 @@
#include "gcr-certificate-renderer-private.h"
#include "gcr-certificate-req-renderer.h"
#include "gcr-display-view.h"
-#include "gcr-key-size.h"
#include "gcr-oids.h"
-
-#if 0
-#include "gcr-certificate.h"
-#include "gcr-certificate-exporter.h"
-#include "gcr-certificate-extensions.h"
-#include "gcr-certificate-renderer.h"
-#include "gcr-fingerprint.h"
-#include "gcr-icons.h"
-#include "gcr-oids.h"
-#include "gcr-simple-certificate.h"
-#include "gcr-renderer.h"
-#endif
+#include "gcr-subject-public-key.h"
#include "egg/egg-asn1x.h"
#include "egg/egg-asn1-defs.h"
@@ -299,7 +287,7 @@ ensure_key_size (GcrCertificateReqRenderer *self,
if (self->pv->key_size)
return self->pv->key_size;
- self->pv->key_size = _gcr_key_size_calculate (public_key);
+ self->pv->key_size = _gcr_subject_public_key_calculate_size (public_key);
return self->pv->key_size;
}
diff --git a/gcr/gcr-certificate.c b/gcr/gcr-certificate.c
index 1713692..d0ab5a6 100644
--- a/gcr/gcr-certificate.c
+++ b/gcr/gcr-certificate.c
@@ -25,8 +25,8 @@
#include "gcr-comparable.h"
#include "gcr-icons.h"
#include "gcr-internal.h"
-#include "gcr-key-size.h"
#include "gcr-oids.h"
+#include "gcr-subject-public-key.h"
#include "egg/egg-asn1x.h"
#include "egg/egg-asn1-defs.h"
@@ -735,7 +735,7 @@ gcr_certificate_get_key_size (GcrCertificate *self)
if (!info->key_size) {
subject_public_key = egg_asn1x_node (info->asn1, "tbsCertificate",
"subjectPublicKeyInfo", NULL);
- info->key_size = _gcr_key_size_calculate (subject_public_key);
+ info->key_size = _gcr_subject_public_key_calculate_size (subject_public_key);
}
return info->key_size;
diff --git a/gcr/gcr-debug.c b/gcr/gcr-debug.c
index fea8fee..9177e58 100644
--- a/gcr/gcr-debug.c
+++ b/gcr/gcr-debug.c
@@ -42,6 +42,7 @@ static GDebugKey keys[] = {
{ "gnupg", GCR_DEBUG_GNUPG },
{ "trust", GCR_DEBUG_TRUST },
{ "import", GCR_DEBUG_IMPORT },
+ { "key", GCR_DEBUG_KEY },
{ 0, }
};
diff --git a/gcr/gcr-debug.h b/gcr/gcr-debug.h
index 20bc35f..5063b77 100644
--- a/gcr/gcr-debug.h
+++ b/gcr/gcr-debug.h
@@ -34,6 +34,7 @@ typedef enum {
GCR_DEBUG_GNUPG = 1 << 4,
GCR_DEBUG_TRUST = 1 << 5,
GCR_DEBUG_IMPORT = 1 << 6,
+ GCR_DEBUG_KEY = 1 << 7,
} GcrDebugFlags;
gboolean _gcr_debug_flag_is_set (GcrDebugFlags flag);
diff --git a/gcr/gcr-fingerprint.c b/gcr/gcr-fingerprint.c
index 1011797..82b24c6 100644
--- a/gcr/gcr-fingerprint.c
+++ b/gcr/gcr-fingerprint.c
@@ -25,12 +25,12 @@
#include "gcr-fingerprint.h"
#include "gcr-oids.h"
+#include "gcr-subject-public-key.h"
#include "egg/egg-asn1x.h"
#include "egg/egg-asn1-defs.h"
#include <glib.h>
-#include <gcrypt.h>
/**
* SECTION:gcr-fingerprint
@@ -86,262 +86,6 @@ gcr_fingerprint_from_subject_public_key_info (const guchar *key_info,
return fingerprint;
}
-static gboolean
-rsa_subject_public_key_from_attributes (GckAttributes *attrs, GNode *info_asn)
-{
- GckAttribute *modulus;
- GckAttribute *exponent;
- EggBytes *key;
- EggBytes *params;
- GNode *key_asn;
- GNode *params_asn;
- EggBytes *usg;
-
- _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);
-
- usg = egg_bytes_new_with_free_func (modulus->value, modulus->length,
- gck_attributes_unref,
- gck_attributes_ref (attrs));
- egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "modulus", NULL), usg);
- egg_bytes_unref (usg);
-
- usg = egg_bytes_new_with_free_func (exponent->value, exponent->length,
- gck_attributes_unref,
- gck_attributes_ref (attrs));
- egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "publicExponent", NULL), usg);
- egg_bytes_unref (usg);
-
- key = egg_asn1x_encode (key_asn, NULL);
- egg_asn1x_destroy (key_asn);
-
- egg_asn1x_set_null (params_asn);
-
- params = egg_asn1x_encode (params_asn, g_realloc);
- egg_asn1x_destroy (params_asn);
-
- egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
- key, egg_bytes_get_size (key) * 8);
-
- egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_RSA);
- egg_asn1x_set_element_raw (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
-
- egg_bytes_unref (key);
- egg_bytes_unref (params);
- return TRUE;
-}
-
-static gboolean
-dsa_subject_public_key_from_private (GNode *key_asn, GckAttribute *ap,
- GckAttribute *aq, GckAttribute *ag, GckAttribute *ax)
-{
- gcry_mpi_t mp, mq, mg, mx, my;
- size_t n_buffer;
- gcry_error_t gcry;
- unsigned char *buffer;
-
- gcry = gcry_mpi_scan (&mp, GCRYMPI_FMT_USG, ap->value, ap->length, NULL);
- g_return_val_if_fail (gcry == 0, FALSE);
-
- gcry = gcry_mpi_scan (&mq, GCRYMPI_FMT_USG, aq->value, aq->length, NULL);
- g_return_val_if_fail (gcry == 0, FALSE);
-
- gcry = gcry_mpi_scan (&mg, GCRYMPI_FMT_USG, ag->value, ag->length, NULL);
- g_return_val_if_fail (gcry == 0, FALSE);
-
- gcry = gcry_mpi_scan (&mx, GCRYMPI_FMT_USG, ax->value, ax->length, NULL);
- g_return_val_if_fail (gcry == 0, FALSE);
-
- /* Calculate the public part from the private */
- my = gcry_mpi_snew (gcry_mpi_get_nbits (mx));
- g_return_val_if_fail (my, FALSE);
- gcry_mpi_powm (my, mg, mx, mp);
-
- gcry = gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &n_buffer, my);
- g_return_val_if_fail (gcry == 0, FALSE);
- egg_asn1x_take_integer_as_raw (key_asn, egg_bytes_new_with_free_func (buffer, n_buffer,
- gcry_free, buffer));
-
- gcry_mpi_release (mp);
- gcry_mpi_release (mq);
- gcry_mpi_release (mg);
- gcry_mpi_release (mx);
- gcry_mpi_release (my);
-
- return TRUE;
-}
-
-static gboolean
-dsa_subject_public_key_from_attributes (GckAttributes *attrs,
- gulong klass,
- GNode *info_asn)
-{
- GckAttribute *value, *g, *q, *p;
- GNode *key_asn, *params_asn;
- EggBytes *key;
- EggBytes *params;
-
- _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);
-
- egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "p", NULL),
- egg_bytes_new_with_free_func (p->value, p->length,
- gck_attributes_unref,
- gck_attributes_ref (attrs)));
- egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "q", NULL),
- egg_bytes_new_with_free_func (q->value, q->length,
- gck_attributes_unref,
- gck_attributes_ref (attrs)));
- egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "g", NULL),
- egg_bytes_new_with_free_func (g->value, g->length,
- gck_attributes_unref,
- gck_attributes_ref (attrs)));
-
- /* Are these attributes for a public or private key? */
- if (klass == CKO_PRIVATE_KEY) {
-
- /* We need to calculate the public from the private key */
- if (!dsa_subject_public_key_from_private (key_asn, p, q, g, value))
- g_return_val_if_reached (FALSE);
-
- } else if (klass == CKO_PUBLIC_KEY) {
- egg_asn1x_take_integer_as_usg (key_asn,
- egg_bytes_new_with_free_func (value->value, value->length,
- gck_attributes_unref,
- gck_attributes_ref (attrs)));
-
- } else {
- g_assert_not_reached ();
- }
-
- key = egg_asn1x_encode (key_asn, NULL);
- egg_asn1x_destroy (key_asn);
-
- params = egg_asn1x_encode (params_asn, NULL);
- egg_asn1x_destroy (params_asn);
-
- egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
- key, egg_bytes_get_size (key) * 8);
- egg_asn1x_set_element_raw (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
-
- egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_DSA);
-
- egg_bytes_unref (key);
- egg_bytes_unref (params);
- return TRUE;
-}
-
-static gpointer
-fingerprint_from_key_attributes (GckAttributes *attrs,
- gulong klass,
- GChecksumType checksum_type,
- gsize *n_fingerprint)
-{
- gpointer fingerprint = NULL;
- gboolean ret = FALSE;
- GNode *info_asn;
- EggBytes *info;
- gulong key_type;
-
- if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &key_type))
- return NULL;
-
- info_asn = egg_asn1x_create (pkix_asn1_tab, "SubjectPublicKeyInfo");
- 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, klass, info_asn);
-
- else
- ret = FALSE;
-
- if (ret) {
- info = egg_asn1x_encode (info_asn, NULL);
- fingerprint = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (info),
- egg_bytes_get_size (info),
- checksum_type,
- n_fingerprint);
- egg_bytes_unref (info);
- }
-
- egg_asn1x_destroy (info_asn);
- return fingerprint;
-}
-
-static guchar *
-fingerprint_from_cert_value (EggBytes *der_data,
- GChecksumType checksum_type,
- gsize *n_fingerprint)
-{
- guchar *fingerprint;
- GNode *cert_asn;
- EggBytes *info;
-
- cert_asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", der_data);
- if (cert_asn == NULL)
- return NULL;
-
- info = egg_asn1x_get_element_raw (egg_asn1x_node (cert_asn, "tbsCertificate", "subjectPublicKeyInfo", NULL));
- g_return_val_if_fail (info != NULL, NULL);
-
- fingerprint = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (info),
- egg_bytes_get_size (info),
- checksum_type,
- n_fingerprint);
-
- egg_bytes_unref (info);
- egg_asn1x_destroy (cert_asn);
- return fingerprint;
-}
-
-static guchar *
-fingerprint_from_cert_attributes (GckAttributes *attrs,
- GChecksumType checksum_type,
- gsize *n_fingerprint)
-{
- GckAttribute *attr;
- EggBytes *bytes;
- guchar *fingerprint;
-
- attr = gck_attributes_find (attrs, CKA_VALUE);
- if (attr == NULL)
- return NULL;
-
- bytes = egg_bytes_new_with_free_func (attr->value, attr->length,
- gck_attributes_unref,
- gck_attributes_ref (attrs));
- fingerprint = fingerprint_from_cert_value (bytes, checksum_type, n_fingerprint);
-
- egg_bytes_unref (bytes);
- return fingerprint;
-}
-
/**
* gcr_fingerprint_from_attributes:
* @attrs: attributes for key or certificate
@@ -357,62 +101,27 @@ fingerprint_from_cert_attributes (GckAttributes *attrs,
*/
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_certificate_public_key:
- * @certificate: the 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)
+ GChecksumType checksum_type,
+ gsize *n_fingerprint)
{
- const guchar *der_data;
- gsize n_der_data;
- EggBytes *bytes;
- guchar *fingerprint;
+ gpointer fingerprint = NULL;
+ EggBytes *info;
+ GNode *asn;
- g_return_val_if_fail (GCR_IS_CERTIFICATE (certificate), NULL);
+ g_return_val_if_fail (attrs != NULL, NULL);
+ g_return_val_if_fail (n_fingerprint, NULL);
- der_data = gcr_certificate_get_der_data (certificate, &n_der_data);
- g_return_val_if_fail (der_data != NULL, NULL);
+ asn = _gcr_subject_public_key_for_attributes (attrs);
- bytes = egg_bytes_new_with_free_func (der_data, n_der_data, g_object_unref,
- g_object_ref (certificate));
- fingerprint = fingerprint_from_cert_value (bytes, checksum_type, n_fingerprint);
- egg_bytes_unref (bytes);
+ if (asn != NULL) {
+ info = egg_asn1x_encode (asn, NULL);
+ fingerprint = gcr_fingerprint_from_subject_public_key_info (egg_bytes_get_data (info),
+ egg_bytes_get_size (info),
+ checksum_type,
+ n_fingerprint);
+ egg_bytes_unref (info);
+ }
+ egg_asn1x_destroy (asn);
return fingerprint;
}
diff --git a/gcr/gcr-fingerprint.h b/gcr/gcr-fingerprint.h
index 84cc41f..b48f170 100644
--- a/gcr/gcr-fingerprint.h
+++ b/gcr/gcr-fingerprint.h
@@ -42,8 +42,4 @@ guchar * gcr_fingerprint_from_attributes (GckAttributes *
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_ */
diff --git a/gcr/gcr-parser.c b/gcr/gcr-parser.c
index e8a5116..7b4ea88 100644
--- a/gcr/gcr-parser.c
+++ b/gcr/gcr-parser.c
@@ -622,6 +622,120 @@ parse_der_private_key (GcrParser *self,
}
/* -----------------------------------------------------------------------------
+ * SUBJECT PUBLIC KEY
+ */
+
+static gint
+handle_subject_public_key_rsa (GcrParser *self,
+ GcrParsed *parsed,
+ EggBytes *key,
+ EggBytes *params)
+{
+ gint res = GCR_ERROR_FAILURE;
+ GNode *asn = NULL;
+
+ asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", key);
+ if (!asn)
+ goto done;
+
+ parsing_object (parsed, CKO_PUBLIC_KEY);
+ parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_RSA);
+
+ if (!parsed_asn1_number (parsed, asn, "modulus", CKA_MODULUS) ||
+ !parsed_asn1_number (parsed, asn, "publicExponent", CKA_PUBLIC_EXPONENT))
+ goto done;
+
+ res = SUCCESS;
+
+done:
+ egg_asn1x_destroy (asn);
+ return res;
+}
+
+static gint
+handle_subject_public_key_dsa (GcrParser *self,
+ GcrParsed *parsed,
+ EggBytes *key,
+ EggBytes *params)
+{
+ gint res = GCR_ERROR_FAILURE;
+ GNode *key_asn = NULL;
+ GNode *param_asn = NULL;
+
+ key_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPublicPart", key);
+ param_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params);
+
+ if (!key_asn || !param_asn)
+ goto done;
+
+ parsing_object (parsed, CKO_PUBLIC_KEY);
+ parsed_ulong_attribute (parsed, CKA_KEY_TYPE, CKK_DSA);
+
+ if (!parsed_asn1_number (parsed, param_asn, "p", CKA_PRIME) ||
+ !parsed_asn1_number (parsed, param_asn, "q", CKA_SUBPRIME) ||
+ !parsed_asn1_number (parsed, param_asn, "g", CKA_BASE) ||
+ !parsed_asn1_number (parsed, key_asn, NULL, CKA_VALUE))
+ goto done;
+
+ res = SUCCESS;
+
+done:
+ egg_asn1x_destroy (key_asn);
+ egg_asn1x_destroy (param_asn);
+ return res;
+}
+
+static gint
+parse_der_subject_public_key (GcrParser *self,
+ EggBytes *data)
+{
+ GcrParsed *parsed;
+ EggBytes *params;
+ EggBytes *key;
+ GNode *asn = NULL;
+ GNode *node;
+ GQuark oid;
+ guint bits;
+ gint ret;
+
+ asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data);
+ if (asn == NULL)
+ return GCR_ERROR_UNRECOGNIZED;
+
+ parsed = push_parsed (self, TRUE);
+ parsing_block (parsed, GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY, data);
+
+ node = egg_asn1x_node (asn, "algorithm", "algorithm", NULL);
+ oid = egg_asn1x_get_oid_as_quark (node);
+
+ node = egg_asn1x_node (asn, "algorithm", "parameters", NULL);
+ params = egg_asn1x_get_element_raw (node);
+
+ node = egg_asn1x_node (asn, "subjectPublicKey", NULL);
+ key = egg_asn1x_get_bits_as_raw (node, &bits);
+
+ if (oid == GCR_OID_PKIX1_RSA)
+ ret = handle_subject_public_key_rsa (self, parsed, key, params);
+
+ else if (oid == GCR_OID_PKIX1_DSA)
+ ret = handle_subject_public_key_dsa (self, parsed, key, params);
+
+ else
+ ret = GCR_ERROR_UNRECOGNIZED;
+
+ egg_bytes_unref (key);
+ egg_bytes_unref (params);
+
+ if (ret == SUCCESS)
+ parsed_fire (self, parsed);
+
+ pop_parsed (self, parsed);
+
+ egg_asn1x_destroy (asn);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
* PKCS8
*/
@@ -1968,6 +2082,7 @@ parse_openssh_public (GcrParser *self,
* @GCR_FORMAT_DER_PRIVATE_KEY: DER encoded private key
* @GCR_FORMAT_DER_PRIVATE_KEY_RSA: DER encoded RSA private key
* @GCR_FORMAT_DER_PRIVATE_KEY_DSA: DER encoded DSA private key
+ * @GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY: DER encoded SubjectPublicKeyInfo
* @GCR_FORMAT_DER_CERTIFICATE_X509: DER encoded X.509 certificate
* @GCR_FORMAT_DER_PKCS7: DER encoded PKCS\#7 container file which can contain certificates
* @GCR_FORMAT_DER_PKCS8: DER encoded PKCS\#8 file which can contain a key
@@ -2004,6 +2119,7 @@ static const ParserFormat parser_normal[] = {
{ GCR_FORMAT_BASE64_SPKAC, parse_base64_spkac },
{ GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa },
{ GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa },
+ { GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY, parse_der_subject_public_key },
{ GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate },
{ GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 },
{ GCR_FORMAT_DER_PKCS8_PLAIN, parse_der_pkcs8_plain },
@@ -2021,6 +2137,7 @@ static const ParserFormat parser_formats[] = {
{ GCR_FORMAT_DER_PRIVATE_KEY, parse_der_private_key },
{ GCR_FORMAT_DER_PRIVATE_KEY_RSA, parse_der_private_key_rsa },
{ GCR_FORMAT_DER_PRIVATE_KEY_DSA, parse_der_private_key_dsa },
+ { GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY, parse_der_subject_public_key },
{ GCR_FORMAT_DER_CERTIFICATE_X509, parse_der_certificate },
{ GCR_FORMAT_DER_PKCS7, parse_der_pkcs7 },
{ GCR_FORMAT_DER_PKCS8, parse_der_pkcs8 },
diff --git a/gcr/gcr-subject-public-key.c b/gcr/gcr-subject-public-key.c
new file mode 100644
index 0000000..fb93b56
--- /dev/null
+++ b/gcr/gcr-subject-public-key.c
@@ -0,0 +1,848 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+#include "config.h"
+
+#define DEBUG_FLAG GCR_DEBUG_KEY
+#include "gcr-debug.h"
+#include "gcr-oids.h"
+#include "gcr-subject-public-key.h"
+#include "gcr-types.h"
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-error.h"
+
+#include <glib/gi18n-lib.h>
+
+#include <gcrypt.h>
+
+static gboolean
+check_object_basics (GckAttributes *attributes,
+ gulong *klass,
+ gulong *type)
+{
+ g_assert (klass != NULL);
+ g_assert (type != NULL);
+
+ if (!gck_attributes_find_ulong (attributes, CKA_CLASS, klass))
+ return FALSE;
+
+ if (*klass == CKO_PUBLIC_KEY || *klass == CKO_PRIVATE_KEY)
+ return gck_attributes_find_ulong (attributes, CKA_KEY_TYPE, type);
+
+ else if (*klass == CKO_CERTIFICATE)
+ return gck_attributes_find_ulong (attributes, CKA_CERTIFICATE_TYPE, type);
+
+ *type = GCK_INVALID;
+ return FALSE;
+}
+
+static gboolean
+load_object_basics (GckObject *object,
+ GckAttributes *attributes,
+ GCancellable *cancellable,
+ gulong *klass,
+ gulong *type,
+ GError **lerror)
+{
+ GckAttributes *attrs;
+ GError *error = NULL;
+
+ g_assert (klass != NULL);
+ g_assert (type != NULL);
+
+ if (check_object_basics (attributes, klass, type)) {
+ _gcr_debug ("already loaded: class = %lu, type = %lu", *klass, *type);
+ return TRUE;
+ }
+
+ attrs = gck_object_get (object, cancellable, &error,
+ CKA_CLASS, CKA_KEY_TYPE, CKA_CERTIFICATE_TYPE, GCK_INVALID);
+ if (error != NULL) {
+ _gcr_debug ("couldn't load: %s", error->message);
+ g_propagate_error (lerror, error);
+ return FALSE;
+ }
+
+ gck_attributes_set_all (attributes, attrs);
+ gck_attributes_unref (attrs);
+
+ if (!check_object_basics (attributes, klass, type))
+ return FALSE;
+
+ _gcr_debug ("loaded: class = %lu, type = %lu", *klass, *type);
+ return TRUE;
+}
+
+static gboolean
+check_x509_attributes (GckAttributes *attributes)
+{
+ GckAttribute *value = gck_attributes_find (attributes, CKA_VALUE);
+ return (value && !gck_attribute_is_invalid (value));
+}
+
+static gboolean
+load_x509_attributes (GckObject *object,
+ GckAttributes *attributes,
+ GCancellable *cancellable,
+ GError **lerror)
+{
+ GckAttributes *attrs;
+ GError *error = NULL;
+
+ if (check_x509_attributes (attributes)) {
+ _gcr_debug ("already loaded");
+ return TRUE;
+ }
+
+ attrs = gck_object_get (object, cancellable, &error,
+ CKA_VALUE, GCK_INVALID);
+ if (error != NULL) {
+ _gcr_debug ("couldn't load: %s", error->message);
+ g_propagate_error (lerror, error);
+ return FALSE;
+ }
+
+ gck_attributes_set_all (attributes, attrs);
+ gck_attributes_unref (attrs);
+
+ return check_x509_attributes (attributes);
+}
+
+static gboolean
+check_rsa_attributes (GckAttributes *attributes)
+{
+ GckAttribute *modulus;
+ GckAttribute *exponent;
+
+ modulus = gck_attributes_find (attributes, CKA_MODULUS);
+ exponent = gck_attributes_find (attributes, CKA_PUBLIC_EXPONENT);
+
+ return (modulus && !gck_attribute_is_invalid (modulus) &&
+ exponent && !gck_attribute_is_invalid (exponent));
+}
+
+static gboolean
+load_rsa_attributes (GckObject *object,
+ GckAttributes *attributes,
+ GCancellable *cancellable,
+ GError **lerror)
+{
+ GckAttributes *attrs;
+ GError *error = NULL;
+
+ if (check_rsa_attributes (attributes)) {
+ _gcr_debug ("rsa attributes already loaded");
+ return TRUE;
+ }
+
+ attrs = gck_object_get (object, cancellable, &error,
+ CKA_MODULUS, CKA_PUBLIC_EXPONENT, GCK_INVALID);
+ if (error != NULL) {
+ _gcr_debug ("couldn't load rsa attributes: %s", error->message);
+ g_propagate_error (lerror, error);
+ return FALSE;
+ }
+
+ gck_attributes_set_all (attributes, attrs);
+ gck_attributes_unref (attrs);
+
+ return check_rsa_attributes (attributes);
+}
+
+static GckObject *
+lookup_public_key (GckObject *object,
+ GCancellable *cancellable,
+ GError **lerror)
+{
+ GckAttributes *match;
+ GError *error = NULL;
+ GckSession *session;
+ GckObject *result;
+ GList *objects;
+ guchar *id;
+ gsize n_id;
+
+ id = gck_object_get_data (object, CKA_ID, cancellable, &n_id, &error);
+ if (error != NULL) {
+ _gcr_debug ("couldn't load private key id: %s", error->message);
+ g_propagate_error (lerror, error);
+ return NULL;
+ }
+
+ match = gck_attributes_new ();
+ gck_attributes_add_ulong (match, CKA_CLASS, CKO_PUBLIC_KEY);
+ gck_attributes_add_data (match, CKA_ID, id, n_id);
+ session = gck_object_get_session (object);
+ g_free (id);
+
+ objects = gck_session_find_objects (session, match, cancellable, &error);
+
+ gck_attributes_unref (match);
+ g_object_unref (session);
+
+ if (error != NULL) {
+ _gcr_debug ("couldn't lookup public key: %s", error->message);
+ g_propagate_error (lerror, error);
+ return NULL;
+ }
+
+ if (!objects)
+ return NULL;
+
+ result = g_object_ref (objects->data);
+ gck_list_unref_free (objects);
+
+ return result;
+}
+
+static gboolean
+check_dsa_attributes (GckAttributes *attributes)
+{
+ GckAttribute *prime;
+ GckAttribute *subprime;
+ GckAttribute *base;
+ GckAttribute *value;
+
+ prime = gck_attributes_find (attributes, CKA_PRIME);
+ subprime = gck_attributes_find (attributes, CKA_SUBPRIME);
+ base = gck_attributes_find (attributes, CKA_BASE);
+ value = gck_attributes_find (attributes, CKA_VALUE);
+
+ return (prime && !gck_attribute_is_invalid (prime) &&
+ subprime && !gck_attribute_is_invalid (subprime) &&
+ base && !gck_attribute_is_invalid (base) &&
+ value && !gck_attribute_is_invalid (value));
+}
+
+static gboolean
+load_dsa_attributes (GckObject *object,
+ GckAttributes *attributes,
+ GCancellable *cancellable,
+ GError **lerror)
+{
+ GError *error = NULL;
+ GckAttributes *loaded;
+ GckObject *publi;
+ gulong klass;
+
+ if (check_dsa_attributes (attributes))
+ return TRUE;
+
+ if (!gck_attributes_find_ulong (attributes, CKA_CLASS, &klass))
+ g_return_val_if_reached (FALSE);
+
+ /* If it's a private key, find the public one */
+ if (klass == CKO_PRIVATE_KEY)
+ publi = lookup_public_key (object, cancellable, lerror);
+
+ else
+ publi = g_object_ref (object);
+
+ if (!publi)
+ return FALSE;
+
+ loaded = gck_object_get (publi, cancellable, &error,
+ CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_VALUE,
+ GCK_INVALID);
+ g_object_unref (publi);
+
+ if (error != NULL) {
+ _gcr_debug ("couldn't load rsa attributes: %s", error->message);
+ g_propagate_error (lerror, error);
+ return FALSE;
+ }
+
+ /* We've made sure to load info from the public key, so change class */
+ gck_attributes_set_ulong (attributes, CKA_CLASS, CKO_PUBLIC_KEY);
+
+ gck_attributes_set_all (attributes, loaded);
+ gck_attributes_unref (loaded);
+
+ return check_dsa_attributes (attributes);
+}
+
+static gboolean
+load_attributes (GckObject *object,
+ GckAttributes *attributes,
+ GCancellable *cancellable,
+ GError **lerror)
+{
+ gboolean ret = FALSE;
+ gulong klass;
+ gulong type;
+
+ if (!load_object_basics (object, attributes, cancellable,
+ &klass, &type, lerror))
+ return FALSE;
+
+ switch (klass) {
+
+ case CKO_CERTIFICATE:
+ switch (type) {
+ case CKC_X_509:
+ ret = load_x509_attributes (object, attributes, cancellable, lerror);
+ break;
+ default:
+ _gcr_debug ("unsupported certificate type: %lu", type);
+ break;
+ }
+ break;
+
+ case CKO_PUBLIC_KEY:
+ case CKO_PRIVATE_KEY:
+ switch (type) {
+ case CKK_RSA:
+ ret = load_rsa_attributes (object, attributes, cancellable, lerror);
+ break;
+ case CKK_DSA:
+ ret = load_dsa_attributes (object, attributes, cancellable, lerror);
+ break;
+ default:
+ _gcr_debug ("unsupported key type: %lu", type);
+ break;
+ }
+ break;
+
+ default:
+ _gcr_debug ("unsupported class: %lu", type);
+ break;
+ }
+
+ if (ret == FALSE && lerror != NULL && *lerror == NULL) {
+ g_set_error_literal (lerror, GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED,
+ _("Unrecognized or unavailable attributes for key"));
+ }
+
+ return ret;
+}
+
+static gboolean
+check_attributes (GckAttributes *attributes)
+{
+ gulong klass;
+ gulong type;
+
+ if (!check_object_basics (attributes, &klass, &type))
+ return FALSE;
+
+ switch (klass) {
+
+ case CKO_CERTIFICATE:
+ switch (type) {
+ case CKC_X_509:
+ return check_x509_attributes (attributes);
+ default:
+ return FALSE;
+ }
+
+ case CKO_PUBLIC_KEY:
+ case CKO_PRIVATE_KEY:
+ switch (type) {
+ case CKK_RSA:
+ return check_rsa_attributes (attributes);
+ case CKK_DSA:
+ return check_dsa_attributes (attributes);
+ default:
+ return FALSE;
+ }
+
+ default:
+ return FALSE;
+ }
+}
+
+static GckAttributes *
+lookup_attributes (GckObject *object)
+{
+ GckObjectAttributes *oakey;
+
+ if (GCK_IS_OBJECT_ATTRIBUTES (object)) {
+ oakey = GCK_OBJECT_ATTRIBUTES (object);
+ return gck_object_attributes_get_attributes (oakey);
+ }
+
+ return NULL;
+}
+
+static void
+attributes_replace_with_copy_or_new (GckAttributes **attributes)
+{
+ g_assert (attributes);
+
+ if (*attributes) {
+ GckAttributes *copy = gck_attributes_dup (*attributes);
+ gck_attributes_unref (*attributes);
+ *attributes = copy;
+ } else {
+ *attributes = gck_attributes_new ();
+ }
+}
+
+GNode *
+_gcr_subject_public_key_load (GckObject *key,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GckAttributes *attributes;
+ GNode *asn;
+
+ g_return_val_if_fail (GCK_IS_OBJECT (key), NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ attributes = lookup_attributes (key);
+
+ if (!attributes || !check_attributes (attributes)) {
+ attributes_replace_with_copy_or_new (&attributes);
+
+ if (!load_attributes (key, attributes, cancellable, error)) {
+ gck_attributes_unref (attributes);
+ return NULL;
+ }
+ }
+
+ asn = _gcr_subject_public_key_for_attributes (attributes);
+ if (asn == NULL) {
+ g_set_error_literal (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT,
+ _("Couldn't build public key"));
+ }
+
+ gck_attributes_unref (attributes);
+ return asn;
+}
+
+typedef struct {
+ GckObject *object;
+ GckAttributes *attributes;
+} LoadClosure;
+
+static void
+load_closure_free (gpointer data)
+{
+ LoadClosure *closure = data;
+ g_object_unref (closure->object);
+ gck_attributes_unref (closure->attributes);
+ g_slice_free (LoadClosure, closure);
+}
+
+static void
+thread_key_attributes (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ LoadClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
+ GError *error = NULL;
+
+ if (!load_attributes (closure->object, closure->attributes, cancellable, &error))
+ g_simple_async_result_take_error (res, error);
+}
+
+void
+_gcr_subject_public_key_load_async (GckObject *key,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *res;
+ LoadClosure *closure;
+
+ g_return_if_fail (GCK_IS_OBJECT (key));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ res = g_simple_async_result_new (NULL, callback, user_data,
+ _gcr_subject_public_key_load_async);
+
+ closure = g_slice_new0 (LoadClosure);
+ closure->object = g_object_ref (key);
+ closure->attributes = lookup_attributes (key);
+ g_simple_async_result_set_op_res_gpointer (res, closure, load_closure_free);
+
+ if (closure->attributes && check_attributes (closure->attributes)) {
+ g_simple_async_result_complete_in_idle (res);
+ g_object_unref (res);
+ return;
+ }
+
+ attributes_replace_with_copy_or_new (&closure->attributes);
+ g_simple_async_result_run_in_thread (res, thread_key_attributes,
+ G_PRIORITY_DEFAULT, cancellable);
+ g_object_unref (res);
+}
+
+GNode *
+_gcr_subject_public_key_load_finish (GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *res;
+ LoadClosure *closure;
+ GNode *asn;
+
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
+ _gcr_subject_public_key_load_async), NULL);
+
+ res = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (res, error))
+ return NULL;
+
+ closure = g_simple_async_result_get_op_res_gpointer (res);
+ asn = _gcr_subject_public_key_for_attributes (closure->attributes);
+ if (asn == NULL) {
+ g_set_error_literal (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT,
+ _("Couldn't build public key"));
+ }
+
+ return asn;
+}
+
+static gboolean
+rsa_subject_public_key_from_attributes (GckAttributes *attrs,
+ GNode *info_asn)
+{
+ GckAttribute *modulus;
+ GckAttribute *exponent;
+ GNode *key_asn;
+ GNode *params_asn;
+ EggBytes *key;
+ EggBytes *params;
+ EggBytes *usg;
+
+ _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);
+
+ usg = egg_bytes_new_with_free_func (modulus->value, modulus->length,
+ gck_attributes_unref,
+ gck_attributes_ref (attrs));
+ egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "modulus", NULL), usg);
+ egg_bytes_unref (usg);
+
+ usg = egg_bytes_new_with_free_func (exponent->value, exponent->length,
+ gck_attributes_unref,
+ gck_attributes_ref (attrs));
+ egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "publicExponent", NULL), usg);
+ egg_bytes_unref (usg);
+
+ key = egg_asn1x_encode (key_asn, NULL);
+ egg_asn1x_destroy (key_asn);
+
+ egg_asn1x_set_null (params_asn);
+
+ params = egg_asn1x_encode (params_asn, g_realloc);
+ egg_asn1x_destroy (params_asn);
+
+ egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
+ key, egg_bytes_get_size (key) * 8);
+
+ egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_RSA);
+ egg_asn1x_set_element_raw (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
+
+ egg_bytes_unref (key);
+ egg_bytes_unref (params);
+ return TRUE;
+}
+
+static gboolean
+dsa_subject_public_key_from_private (GNode *key_asn,
+ GckAttribute *ap,
+ GckAttribute *aq,
+ GckAttribute *ag,
+ GckAttribute *ax)
+{
+ gcry_mpi_t mp, mq, mg, mx, my;
+ size_t n_buffer;
+ gcry_error_t gcry;
+ unsigned char *buffer;
+
+ gcry = gcry_mpi_scan (&mp, GCRYMPI_FMT_USG, ap->value, ap->length, NULL);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ gcry = gcry_mpi_scan (&mq, GCRYMPI_FMT_USG, aq->value, aq->length, NULL);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ gcry = gcry_mpi_scan (&mg, GCRYMPI_FMT_USG, ag->value, ag->length, NULL);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ gcry = gcry_mpi_scan (&mx, GCRYMPI_FMT_USG, ax->value, ax->length, NULL);
+ g_return_val_if_fail (gcry == 0, FALSE);
+
+ /* Calculate the public part from the private */
+ my = gcry_mpi_snew (gcry_mpi_get_nbits (mx));
+ g_return_val_if_fail (my, FALSE);
+ gcry_mpi_powm (my, mg, mx, mp);
+
+ gcry = gcry_mpi_aprint (GCRYMPI_FMT_STD, &buffer, &n_buffer, my);
+ g_return_val_if_fail (gcry == 0, FALSE);
+ egg_asn1x_take_integer_as_raw (key_asn, egg_bytes_new_with_free_func (buffer, n_buffer,
+ gcry_free, buffer));
+
+ gcry_mpi_release (mp);
+ gcry_mpi_release (mq);
+ gcry_mpi_release (mg);
+ gcry_mpi_release (mx);
+ gcry_mpi_release (my);
+
+ return TRUE;
+}
+
+static gboolean
+dsa_subject_public_key_from_attributes (GckAttributes *attrs,
+ gulong klass,
+ GNode *info_asn)
+{
+ GckAttribute *value, *g, *q, *p;
+ GNode *key_asn, *params_asn;
+ EggBytes *key;
+ EggBytes *params;
+
+ _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);
+
+ egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "p", NULL),
+ egg_bytes_new_with_free_func (p->value, p->length,
+ gck_attributes_unref,
+ gck_attributes_ref (attrs)));
+ egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "q", NULL),
+ egg_bytes_new_with_free_func (q->value, q->length,
+ gck_attributes_unref,
+ gck_attributes_ref (attrs)));
+ egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "g", NULL),
+ egg_bytes_new_with_free_func (g->value, g->length,
+ gck_attributes_unref,
+ gck_attributes_ref (attrs)));
+
+ /* Are these attributes for a public or private key? */
+ if (klass == CKO_PRIVATE_KEY) {
+
+ /* We need to calculate the public from the private key */
+ if (!dsa_subject_public_key_from_private (key_asn, p, q, g, value))
+ g_return_val_if_reached (FALSE);
+
+ } else if (klass == CKO_PUBLIC_KEY) {
+ egg_asn1x_take_integer_as_usg (key_asn,
+ egg_bytes_new_with_free_func (value->value, value->length,
+ gck_attributes_unref,
+ gck_attributes_ref (attrs)));
+ } else {
+ g_assert_not_reached ();
+ }
+
+ key = egg_asn1x_encode (key_asn, NULL);
+ egg_asn1x_destroy (key_asn);
+
+ params = egg_asn1x_encode (params_asn, NULL);
+ egg_asn1x_destroy (params_asn);
+
+ egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
+ key, egg_bytes_get_size (key) * 8);
+ egg_asn1x_set_element_raw (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params);
+
+ egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_DSA);
+
+ egg_bytes_unref (key);
+ egg_bytes_unref (params);
+ return TRUE;
+}
+
+static GNode *
+cert_subject_public_key_from_attributes (GckAttributes *attributes)
+{
+ GckAttribute *attr;
+ EggBytes *bytes;
+ GNode *cert;
+ GNode *asn;
+
+ attr = gck_attributes_find (attributes, CKA_VALUE);
+ if (attr == NULL) {
+ _gcr_debug ("no value attribute for certificate");
+ return NULL;
+ }
+
+ bytes = egg_bytes_new_with_free_func (attr->value, attr->length,
+ gck_attributes_unref,
+ gck_attributes_ref (attributes));
+ cert = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
+ egg_bytes_unref (bytes);
+
+ if (cert == NULL) {
+ _gcr_debug ("couldn't parse certificate value");
+ return NULL;
+ }
+
+ asn = egg_asn1x_node (cert, "tbsCertificate", "subjectPublicKeyInfo", NULL);
+ g_return_val_if_fail (asn != NULL, NULL);
+
+ /* Remove the subject public key out of the certificate */
+ g_node_unlink (asn);
+ egg_asn1x_destroy (cert);
+
+ return asn;
+}
+
+GNode *
+_gcr_subject_public_key_for_attributes (GckAttributes *attributes)
+{
+ gboolean ret = FALSE;
+ gulong key_type;
+ gulong klass;
+ GNode *asn;
+
+ if (!gck_attributes_find_ulong (attributes, CKA_CLASS, &klass)) {
+ _gcr_debug ("no class in attributes");
+ return NULL;
+ }
+
+ if (klass == CKO_CERTIFICATE) {
+ return cert_subject_public_key_from_attributes (attributes);
+
+ } else if (klass == CKO_PUBLIC_KEY || klass == CKO_PRIVATE_KEY) {
+ if (!gck_attributes_find_ulong (attributes, CKA_KEY_TYPE, &key_type)) {
+ _gcr_debug ("no key type in attributes");
+ return NULL;
+ }
+
+ asn = egg_asn1x_create (pkix_asn1_tab, "SubjectPublicKeyInfo");
+ g_return_val_if_fail (asn, NULL);
+
+ if (key_type == CKK_RSA) {
+ ret = rsa_subject_public_key_from_attributes (attributes, asn);
+
+ } else if (key_type == CKK_DSA) {
+ ret = dsa_subject_public_key_from_attributes (attributes, klass, asn);
+
+ } else {
+ _gcr_debug ("unsupported key type: %lu", key_type);
+ ret = FALSE;
+ }
+
+
+ if (ret == FALSE) {
+ egg_asn1x_destroy (asn);
+ asn = NULL;
+ }
+ }
+
+ return asn;
+}
+
+static guint
+calculate_rsa_key_size (EggBytes *data)
+{
+ GNode *asn;
+ EggBytes *content;
+ guint key_size;
+
+ asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
+ g_return_val_if_fail (asn, 0);
+
+ content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL));
+ if (!content)
+ g_return_val_if_reached (0);
+
+ egg_asn1x_destroy (asn);
+
+ /* Removes the complement */
+ key_size = (egg_bytes_get_size (content) / 2) * 2 * 8;
+
+ egg_bytes_unref (content);
+ return key_size;
+}
+
+static guint
+calculate_dsa_params_size (EggBytes *data)
+{
+ GNode *asn;
+ EggBytes *content;
+ guint key_size;
+
+ asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data);
+ g_return_val_if_fail (asn, 0);
+
+ content = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "p", NULL));
+ if (!content)
+ g_return_val_if_reached (0);
+
+ egg_asn1x_destroy (asn);
+
+ /* Removes the complement */
+ key_size = (egg_bytes_get_size (content) / 2) * 2 * 8;
+
+ egg_bytes_unref (content);
+ return key_size;
+}
+
+guint
+_gcr_subject_public_key_calculate_size (GNode *subject_public_key)
+{
+ EggBytes *key;
+ guint key_size = 0;
+ guint n_bits;
+ GQuark oid;
+
+ /* Figure out the algorithm */
+ oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
+ "algorithm", "algorithm", NULL));
+ g_return_val_if_fail (oid != 0, 0);
+
+ /* RSA keys are stored in the main subjectPublicKey field */
+ if (oid == GCR_OID_PKIX1_RSA) {
+ key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL), &n_bits);
+ g_return_val_if_fail (key != NULL, 0);
+ key_size = calculate_rsa_key_size (key);
+ egg_bytes_unref (key);
+
+ /* The DSA key size is discovered by the prime in params */
+ } else if (oid == GCR_OID_PKIX1_DSA) {
+ key = egg_asn1x_get_element_raw (egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL));
+ key_size = calculate_dsa_params_size (key);
+ egg_bytes_unref (key);
+
+ } else {
+ g_message ("unsupported key algorithm: %s", g_quark_to_string (oid));
+ }
+
+ return key_size;
+}
diff --git a/gcr/gcr-subject-public-key.h b/gcr/gcr-subject-public-key.h
new file mode 100644
index 0000000..bfee315
--- /dev/null
+++ b/gcr/gcr-subject-public-key.h
@@ -0,0 +1,55 @@
+/*
+ * gnome-keyring
+ *
+ * Copyright (C) 2011 Collabora Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Author: Stef Walter <stefw collabora co uk>
+ */
+
+#if !defined (__GCR_INSIDE_HEADER__) && !defined (GCR_COMPILATION)
+#error "Only <gcr/gcr.h> or <gcr/gcr-base.h> can be included directly."
+#endif
+
+#ifndef GCR_SUBJECT_PUBLIC_KEY_H
+#define GCR_SUBJECT_PUBLIC_KEY_H
+
+#include <glib.h>
+
+#include <gck/gck.h>
+
+G_BEGIN_DECLS
+
+GNode * _gcr_subject_public_key_for_attributes (GckAttributes *attributes);
+
+GNode * _gcr_subject_public_key_load (GckObject *key,
+ GCancellable *cancellable,
+ GError **error);
+
+void _gcr_subject_public_key_load_async (GckObject *key,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+GNode * _gcr_subject_public_key_load_finish (GAsyncResult *result,
+ GError **error);
+
+guint _gcr_subject_public_key_calculate_size (GNode *subject_public_key);
+
+G_END_DECLS
+
+#endif /* GCR_CERTIFICATE_H */
diff --git a/gcr/gcr-types.h b/gcr/gcr-types.h
index dd522be..e8a01c5 100644
--- a/gcr/gcr-types.h
+++ b/gcr/gcr-types.h
@@ -75,6 +75,8 @@ typedef enum {
GCR_FORMAT_DER_PRIVATE_KEY_RSA,
GCR_FORMAT_DER_PRIVATE_KEY_DSA,
+ GCR_FORMAT_DER_SUBJECT_PUBLIC_KEY = 150,
+
GCR_FORMAT_DER_CERTIFICATE_X509 = 200,
GCR_FORMAT_DER_PKCS7 = 300,
diff --git a/gcr/tests/Makefile.am b/gcr/tests/Makefile.am
index c133c17..5e611f7 100644
--- a/gcr/tests/Makefile.am
+++ b/gcr/tests/Makefile.am
@@ -27,6 +27,7 @@ TEST_PROGS = \
test-simple-certificate \
test-certificate \
test-certificate-chain \
+ test-subject-public-key \
test-fingerprint \
test-pkcs11-certificate \
test-openpgp \
diff --git a/gcr/tests/files/client.spk b/gcr/tests/files/client.spk
new file mode 100644
index 0000000..09ab6b9
Binary files /dev/null and b/gcr/tests/files/client.spk differ
diff --git a/gcr/tests/files/generic-dsa.spk b/gcr/tests/files/generic-dsa.spk
new file mode 100644
index 0000000..161391c
Binary files /dev/null and b/gcr/tests/files/generic-dsa.spk differ
diff --git a/gcr/tests/test-subject-public-key.c b/gcr/tests/test-subject-public-key.c
new file mode 100644
index 0000000..0e99563
--- /dev/null
+++ b/gcr/tests/test-subject-public-key.c
@@ -0,0 +1,721 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ Copyright (C) 2010 Collabora Ltd
+
+ The Gnome Keyring Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome Keyring Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ Author: Stef Walter <stefw collabora co uk>
+*/
+
+#include "config.h"
+
+#include "gcr/gcr-base.h"
+#include "gcr/gcr-subject-public-key.h"
+
+#include "gck/gck-mock.h"
+#include "gck/gck-test.h"
+
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-testing.h"
+
+#include <glib.h>
+
+#include <errno.h>
+
+typedef struct {
+ const gchar *name;
+ const gchar *basename;
+ guint key_size;
+} TestFixture;
+
+typedef struct {
+ EggBytes *crt_data;
+ GckAttributes *crt_attrs;
+ EggBytes *key_data;
+ GckAttributes *prv_attrs;
+ EggBytes *spk_data;
+ GckAttributes *pub_attrs;
+} TestAttributes;
+
+static void
+on_parser_parsed (GcrParser *parser,
+ gpointer user_data)
+{
+ GckAttributes **attrs = user_data;
+ g_assert (*attrs == NULL);
+ *attrs = gcr_parser_get_parsed_attributes (parser);
+ g_assert (*attrs != NULL);
+ gck_attributes_ref (*attrs);
+}
+
+static GckAttributes *
+parse_attributes (EggBytes *data)
+{
+ GcrParser *parser;
+ GckAttributes *attrs = NULL;
+ GError *error = NULL;
+
+ parser = gcr_parser_new ();
+ g_signal_connect (parser, "parsed", G_CALLBACK (on_parser_parsed), &attrs);
+ gcr_parser_parse_data (parser, egg_bytes_get_data (data),
+ egg_bytes_get_size (data), &error);
+ g_assert_no_error (error);
+ g_object_unref (parser);
+
+ g_assert (attrs);
+ return attrs;
+}
+
+static void
+setup_attributes (TestAttributes *test,
+ gconstpointer data)
+{
+ const TestFixture *fixture = data;
+ GError *error = NULL;
+ gchar *contents;
+ gchar *filename;
+ gsize length;
+ gulong klass;
+
+ filename = g_strdup_printf (SRCDIR "/files/%s.crt", fixture->basename);
+ g_file_get_contents (filename, &contents, &length, &error);
+ g_assert_no_error (error);
+ test->crt_data = egg_bytes_new_take (contents, length);
+ test->crt_attrs = parse_attributes (test->crt_data);
+ g_assert (gck_attributes_find_ulong (test->crt_attrs, CKA_CLASS, &klass));
+ gck_assert_cmpulong (klass, ==, CKO_CERTIFICATE);
+ g_free (filename);
+
+ filename = g_strdup_printf (SRCDIR "/files/%s.key", fixture->basename);
+ g_file_get_contents (filename, &contents, &length, &error);
+ g_assert_no_error (error);
+ test->key_data = egg_bytes_new_take (contents, length);
+ test->prv_attrs = parse_attributes (test->key_data);
+ g_assert (gck_attributes_find_ulong (test->prv_attrs, CKA_CLASS, &klass));
+ gck_assert_cmpulong (klass, ==, CKO_PRIVATE_KEY);
+ g_free (filename);
+
+ filename = g_strdup_printf (SRCDIR "/files/%s.spk", fixture->basename);
+ g_file_get_contents (filename, &contents, &length, &error);
+ g_assert_no_error (error);
+ test->spk_data = egg_bytes_new_take (contents, length);
+ test->pub_attrs = parse_attributes (test->spk_data);
+ g_assert (gck_attributes_find_ulong (test->pub_attrs, CKA_CLASS, &klass));
+ gck_assert_cmpulong (klass, ==, CKO_PUBLIC_KEY);
+ g_free (filename);
+}
+
+static void
+teardown_attributes (TestAttributes *test,
+ gconstpointer unused)
+{
+ egg_bytes_unref (test->crt_data);
+ egg_bytes_unref (test->key_data);
+ egg_bytes_unref (test->spk_data);
+ gck_attributes_unref (test->crt_attrs);
+ gck_attributes_unref (test->prv_attrs);
+ gck_attributes_unref (test->pub_attrs);
+}
+
+static void
+perform_for_attributes (TestAttributes *test,
+ GckAttributes *attrs)
+{
+ GNode *info;
+ EggBytes *data;
+
+ info = _gcr_subject_public_key_for_attributes (attrs);
+ g_assert (info != NULL);
+
+ data = egg_asn1x_encode (info, NULL);
+ egg_assert_cmpbytes (data, ==, egg_bytes_get_data (test->spk_data),
+ egg_bytes_get_size (test->spk_data));
+
+ egg_bytes_unref (data);
+ egg_asn1x_destroy (info);
+
+}
+
+static void
+test_for_cert_attributes (TestAttributes *test,
+ gconstpointer unused)
+{
+ perform_for_attributes (test, test->crt_attrs);
+}
+
+static void
+test_for_private_key_attributes (TestAttributes *test,
+ gconstpointer unused)
+{
+ perform_for_attributes (test, test->prv_attrs);
+}
+
+static void
+test_for_public_key_attributes (TestAttributes *test,
+ gconstpointer unused)
+{
+ perform_for_attributes (test, test->pub_attrs);
+}
+
+static void
+perform_calculate_size (TestAttributes *test,
+ GckAttributes *attrs,
+ const TestFixture *fixture)
+{
+ GNode *info;
+ guint size;
+
+ info = _gcr_subject_public_key_for_attributes (attrs);
+ g_assert (info != NULL);
+
+ /* TODO: until encoding, we don't have readable attributes */
+ egg_bytes_unref (egg_asn1x_encode (info, NULL));
+
+ size = _gcr_subject_public_key_calculate_size (info);
+ g_assert_cmpuint (size, ==, fixture->key_size);
+
+ egg_asn1x_destroy (info);
+
+}
+
+static void
+test_certificate_calculate_size (TestAttributes *test,
+ gconstpointer fixture)
+{
+ perform_calculate_size (test, test->crt_attrs, fixture);
+}
+
+static void
+test_public_key_calculate_size (TestAttributes *test,
+ gconstpointer fixture)
+{
+ perform_calculate_size (test, test->pub_attrs, fixture);
+}
+
+static void
+test_private_key_calculate_size (TestAttributes *test,
+ gconstpointer fixture)
+{
+ perform_calculate_size (test, test->prv_attrs, fixture);
+}
+
+typedef struct {
+ CK_FUNCTION_LIST funcs;
+ GckModule *module;
+ GckSession *session;
+} TestModule;
+
+static void
+setup_module (TestModule *test,
+ gconstpointer unused)
+{
+ CK_FUNCTION_LIST_PTR f;
+ GError *error = NULL;
+ GckSlot *slot;
+ CK_RV rv;
+
+ rv = gck_mock_C_GetFunctionList (&f);
+ gck_assert_cmprv (rv, ==, CKR_OK);
+ memcpy (&test->funcs, f, sizeof (test->funcs));
+
+ /* Open a session */
+ rv = (test->funcs.C_Initialize) (NULL);
+ gck_assert_cmprv (rv, ==, CKR_OK);
+
+ test->module = gck_module_new (&test->funcs);
+ slot = gck_slot_from_handle (test->module, GCK_MOCK_SLOT_ONE_ID);
+ test->session = gck_session_open (slot, GCK_SESSION_READ_ONLY, NULL, NULL, &error);
+ g_assert_no_error (error);
+
+ g_object_unref (slot);
+}
+
+static void
+teardown_module (TestModule *test,
+ gconstpointer fixture)
+{
+ CK_RV rv;
+
+ g_object_unref (test->session);
+ egg_assert_not_object (test->session);
+
+ g_object_unref (test->module);
+ egg_assert_not_object (test->module);
+
+ rv = (test->funcs.C_Finalize) (NULL);
+ gck_assert_cmprv (rv, ==, CKR_OK);
+}
+
+typedef struct {
+ TestAttributes at;
+ TestModule mo;
+ GckObject *crt_object;
+ GckObject *pub_object;
+ GckObject *prv_object;
+} TestLoading;
+
+static void
+setup_loading (TestLoading *test,
+ gconstpointer fixture)
+{
+ const gchar *id = "test-id";
+ gulong handle;
+
+ setup_attributes (&test->at, fixture);
+ setup_module (&test->mo, NULL);
+
+ gck_attributes_add_string (test->at.crt_attrs, CKA_ID, id);
+ handle = gck_mock_module_take_object (gck_attributes_ref (test->at.crt_attrs));
+ test->crt_object = gck_object_from_handle (test->mo.session, handle);
+
+ gck_attributes_add_string (test->at.pub_attrs, CKA_ID, id);
+ handle = gck_mock_module_take_object (gck_attributes_ref (test->at.pub_attrs));
+ test->pub_object = gck_object_from_handle (test->mo.session, handle);
+
+ gck_attributes_add_string (test->at.prv_attrs, CKA_ID, id);
+ handle = gck_mock_module_take_object (gck_attributes_ref (test->at.prv_attrs));
+ test->prv_object = gck_object_from_handle (test->mo.session, handle);
+}
+
+static void
+teardown_loading (TestLoading *test,
+ gconstpointer fixture)
+{
+ g_object_unref (test->crt_object);
+ egg_assert_not_object (test->crt_object);
+
+ g_object_unref (test->prv_object);
+ egg_assert_not_object (test->prv_object);
+
+ g_object_unref (test->pub_object);
+ egg_assert_not_object (test->pub_object);
+
+ teardown_module (&test->mo, NULL);
+ teardown_attributes (&test->at, fixture);
+}
+
+static void
+perform_load (TestLoading *test,
+ GckObject *object)
+{
+ GError *error = NULL;
+ EggBytes *data;
+ GNode *info;
+
+ info = _gcr_subject_public_key_load (object, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (info != NULL);
+
+ data = egg_asn1x_encode (info, NULL);
+ egg_assert_cmpbytes (data, ==, egg_bytes_get_data (test->at.spk_data),
+ egg_bytes_get_size (test->at.spk_data));
+
+ egg_bytes_unref (data);
+ egg_asn1x_destroy (info);
+}
+
+static void
+test_certificate_load (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load (test, test->crt_object);
+}
+
+static void
+test_public_key_load (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load (test, test->pub_object);
+}
+
+static void
+test_private_key_load (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load (test, test->prv_object);
+}
+
+static void
+on_async_result (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GAsyncResult **ret = user_data;
+ g_assert (ret != NULL);
+ g_assert (*ret == NULL);
+ g_assert (G_IS_ASYNC_RESULT (result));
+ *ret = g_object_ref (result);
+ egg_test_wait_stop ();
+}
+
+static void
+perform_load_async (TestLoading *test,
+ GckObject *object)
+{
+ GAsyncResult *result = NULL;
+ GError *error = NULL;
+ EggBytes *data;
+ GNode *info;
+
+ _gcr_subject_public_key_load_async (object, NULL, on_async_result, &result);
+ g_assert (result == NULL);
+ egg_test_wait ();
+
+ g_assert (result != NULL);
+ info = _gcr_subject_public_key_load_finish (result, &error);
+ g_assert_no_error (error);
+ g_assert (info != NULL);
+ g_object_unref (result);
+
+ data = egg_asn1x_encode (info, NULL);
+ egg_assert_cmpbytes (data, ==, egg_bytes_get_data (test->at.spk_data),
+ egg_bytes_get_size (test->at.spk_data));
+
+ egg_bytes_unref (data);
+ egg_asn1x_destroy (info);
+}
+
+static void
+test_certificate_load_async (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_async (test, test->crt_object);
+}
+
+static void
+test_public_key_load_async (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_async (test, test->pub_object);
+}
+
+static void
+test_private_key_load_async (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_async (test, test->prv_object);
+}
+
+enum { PROP_ATTRIBUTES = 1 };
+typedef struct { GckObject parent; GckAttributes *attrs; } MockObject;
+typedef struct { GckObjectClass parent; } MockObjectClass;
+
+GType mock_object_get_type (void) G_GNUC_CONST;
+static void mock_object_attributes_init (GckObjectAttributesIface *iface);
+G_DEFINE_TYPE_WITH_CODE (MockObject, mock_object, GCK_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GCK_TYPE_OBJECT_ATTRIBUTES, mock_object_attributes_init)
+);
+
+static void
+mock_object_init (MockObject *self)
+{
+
+}
+
+static void
+mock_object_get_property (GObject *obj,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ g_assert (prop_id == PROP_ATTRIBUTES);
+ g_value_set_boxed (value, ((MockObject *)obj)->attrs);
+}
+
+static void
+mock_object_set_property (GObject *obj,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ g_assert (prop_id == PROP_ATTRIBUTES);
+ ((MockObject *)obj)->attrs = g_value_dup_boxed (value);
+}
+
+static void
+mock_object_finalize (GObject *obj)
+{
+ MockObject *self = (MockObject *)obj;
+ gck_attributes_unref (self->attrs);
+ G_OBJECT_CLASS (mock_object_parent_class)->finalize (obj);
+}
+
+static void
+mock_object_class_init (MockObjectClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->get_property = mock_object_get_property;
+ gobject_class->set_property = mock_object_set_property;
+ gobject_class->finalize = mock_object_finalize;
+ g_object_class_override_property (gobject_class, PROP_ATTRIBUTES, "attributes");
+}
+
+static void
+mock_object_attributes_init (GckObjectAttributesIface *iface)
+{
+ iface->attribute_types = NULL;
+ iface->n_attribute_types = 0;
+}
+
+static void
+perform_load_already (TestLoading *test,
+ GckAttributes *attributes)
+{
+ const gulong INVALID = 0xFFF00FF; /* invalid handle, should not be used */
+ GckObject *object;
+ GError *error = NULL;
+ EggBytes *data;
+ GNode *info;
+
+ object = g_object_new (mock_object_get_type (),
+ "module", test->mo.module,
+ "session", test->mo.session,
+ "handle", INVALID,
+ "attributes", attributes,
+ NULL);
+
+ info = _gcr_subject_public_key_load (object, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (info != NULL);
+
+ data = egg_asn1x_encode (info, NULL);
+ egg_assert_cmpbytes (data, ==, egg_bytes_get_data (test->at.spk_data),
+ egg_bytes_get_size (test->at.spk_data));
+
+ egg_bytes_unref (data);
+ egg_asn1x_destroy (info);
+ g_object_unref (object);
+}
+
+static void
+test_certificate_load_already (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_already (test, test->at.crt_attrs);
+}
+
+static void
+test_public_key_load_already (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_already (test, test->at.pub_attrs);
+}
+
+static void
+test_private_key_load_already (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_already (test, test->at.prv_attrs);
+}
+
+static void
+perform_load_partial (TestLoading *test,
+ GckObject *original,
+ GckAttributes *attributes)
+{
+ GckAttributes *partial;
+ GckObject *object;
+ GError *error = NULL;
+ EggBytes *data;
+ GNode *info;
+ guint i;
+
+ partial = gck_attributes_new ();
+ for (i = 0; i < gck_attributes_count (attributes); i += 2)
+ gck_attributes_add (partial, gck_attributes_at (attributes, i));
+
+ object = g_object_new (mock_object_get_type (),
+ "module", test->mo.module,
+ "session", test->mo.session,
+ "handle", gck_object_get_handle (original),
+ "attributes", partial,
+ NULL);
+ gck_attributes_unref (partial);
+
+ info = _gcr_subject_public_key_load (object, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (info != NULL);
+
+ data = egg_asn1x_encode (info, NULL);
+ egg_assert_cmpbytes (data, ==, egg_bytes_get_data (test->at.spk_data),
+ egg_bytes_get_size (test->at.spk_data));
+
+ egg_bytes_unref (data);
+ egg_asn1x_destroy (info);
+ g_object_unref (object);
+}
+
+static void
+test_certificate_load_partial (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_partial (test, test->crt_object, test->at.crt_attrs);
+}
+
+static void
+test_public_key_load_partial (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_partial (test, test->pub_object, test->at.pub_attrs);
+}
+
+static void
+test_private_key_load_partial (TestLoading *test,
+ gconstpointer unused)
+{
+ perform_load_partial (test, test->prv_object, test->at.prv_attrs);
+}
+
+static void
+test_load_failure_lookup (TestModule *test,
+ gconstpointer fixture)
+{
+ const gulong INVALID = 0xFFF00FF; /* invalid handle, should fail */
+ GckObject *object;
+ GError *error = NULL;
+ GNode *info;
+
+ object = g_object_new (mock_object_get_type (),
+ "module", test->module,
+ "session", test->session,
+ "handle", INVALID,
+ NULL);
+
+ info = _gcr_subject_public_key_load (object, NULL, &error);
+ g_assert_error (error, GCK_ERROR, CKR_OBJECT_HANDLE_INVALID);
+ g_assert (info == NULL);
+ g_error_free (error);
+
+ g_object_unref (object);
+}
+
+static void
+test_load_failure_build (TestModule *test,
+ gconstpointer fixture)
+{
+ GckAttributes *attributes;
+ const gulong INVALID = 0xFFF00FF; /* invalid handle, shouldn't be used */
+ GckObject *object;
+ GError *error = NULL;
+ GNode *info;
+
+ attributes = gck_attributes_new ();
+ gck_attributes_add_ulong (attributes, CKA_CLASS, CKO_CERTIFICATE);
+ gck_attributes_add_ulong (attributes, CKA_CERTIFICATE_TYPE, CKC_X_509);
+ gck_attributes_add_string (attributes, CKA_VALUE, "invalid value");
+
+ object = g_object_new (mock_object_get_type (),
+ "module", test->module,
+ "session", test->session,
+ "handle", INVALID,
+ "attributes", attributes,
+ NULL);
+
+ gck_attributes_unref (attributes);
+
+ info = _gcr_subject_public_key_load (object, NULL, &error);
+ g_assert_error (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT);
+ g_assert (info == NULL);
+ g_error_free (error);
+
+ g_object_unref (object);
+}
+
+static const TestFixture FIXTURES[] = {
+ { "rsa", "client", 2048 },
+ { "dsa", "generic-dsa", 1024 },
+};
+
+static GPtrArray *test_names = NULL;
+
+static const gchar *
+test_name (const gchar *format,
+ const gchar *basename)
+{
+ gchar *name = g_strdup_printf (format, basename);
+ g_ptr_array_add (test_names, name);
+ return name;
+}
+
+int
+main (int argc, char **argv)
+{
+ const TestFixture *fixture;
+ gint ret;
+ guint i;
+
+ g_type_init ();
+ g_test_init (&argc, &argv, NULL);
+
+ test_names = g_ptr_array_new_with_free_func (g_free);
+
+ for (i = 0; i < G_N_ELEMENTS (FIXTURES); i++) {
+ fixture = &FIXTURES[i];
+
+ g_test_add (test_name ("/gcr/subject-public-key/%s/cert-attributes", fixture->name), TestAttributes, fixture,
+ setup_attributes, test_for_cert_attributes, teardown_attributes);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/public-key-attributes", fixture->name), TestAttributes, fixture,
+ setup_attributes, test_for_public_key_attributes, teardown_attributes);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/private-key-attributes", fixture->name), TestAttributes, fixture,
+ setup_attributes, test_for_private_key_attributes, teardown_attributes);
+
+ g_test_add (test_name ("/gcr/subject-public-key/%s/certificate-size", fixture->name), TestAttributes, fixture,
+ setup_attributes, test_certificate_calculate_size, teardown_attributes);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/public-key-size", fixture->name), TestAttributes, fixture,
+ setup_attributes, test_public_key_calculate_size, teardown_attributes);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/private-key-size", fixture->name), TestAttributes, fixture,
+ setup_attributes, test_private_key_calculate_size, teardown_attributes);
+
+ g_test_add (test_name ("/gcr/subject-public-key/%s/certificate-load", fixture->name), TestLoading, fixture,
+ setup_loading, test_certificate_load, teardown_loading);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/public-key-load", fixture->name), TestLoading, fixture,
+ setup_loading, test_public_key_load, teardown_loading);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/private-key-load", fixture->name), TestLoading, fixture,
+ setup_loading, test_private_key_load, teardown_loading);
+
+ g_test_add (test_name ("/gcr/subject-public-key/%s/certificate-load-async", fixture->name), TestLoading, fixture,
+ setup_loading, test_certificate_load_async, teardown_loading);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/public-key-load-async", fixture->name), TestLoading, fixture,
+ setup_loading, test_public_key_load_async, teardown_loading);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/private-key-load-async", fixture->name), TestLoading, fixture,
+ setup_loading, test_private_key_load_async, teardown_loading);
+
+ g_test_add (test_name ("/gcr/subject-public-key/%s/certificate-load-already", fixture->name), TestLoading, fixture,
+ setup_loading, test_certificate_load_already, teardown_loading);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/public-key-load-already", fixture->name), TestLoading, fixture,
+ setup_loading, test_public_key_load_already, teardown_loading);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/private-key-load-already", fixture->name), TestLoading, fixture,
+ setup_loading, test_private_key_load_already, teardown_loading);
+
+ g_test_add (test_name ("/gcr/subject-public-key/%s/certificate-load-partial", fixture->name), TestLoading, fixture,
+ setup_loading, test_certificate_load_partial, teardown_loading);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/public-key-load-partial", fixture->name), TestLoading, fixture,
+ setup_loading, test_public_key_load_partial, teardown_loading);
+ g_test_add (test_name ("/gcr/subject-public-key/%s/private-key-load-partial", fixture->name), TestLoading, fixture,
+ setup_loading, test_private_key_load_partial, teardown_loading);
+ }
+
+ g_test_add ("/gcr/subject-public-key/load-failure-lookup", TestModule, NULL,
+ setup_module, test_load_failure_lookup, teardown_module);
+ g_test_add ("/gcr/subject-public-key/load-failure-build", TestModule, NULL,
+ setup_module, test_load_failure_build, teardown_module);
+
+ ret = egg_tests_run_with_loop ();
+
+ g_ptr_array_free (test_names, TRUE);
+ return ret;
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index c5c8b38..b8f5733 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -24,6 +24,7 @@ gcr/gcr-parser.c
gcr/gcr-pkcs11-import-dialog.c
[type: gettext/glade]gcr/gcr-pkcs11-import-dialog.ui
gcr/gcr-pkcs11-import-interaction.c
+gcr/gcr-subject-public-key.c
gcr/gcr-trust.c
[type: gettext/glade]gcr/gcr-unlock-options-widget.ui
gcr/gcr-unlock-renderer.c
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]