Blame gcr/gcr-subject-public-key.c

Packit b00eeb
/*
Packit b00eeb
 * gnome-keyring
Packit b00eeb
 *
Packit b00eeb
 * Copyright (C) 2011 Collabora Ltd.
Packit b00eeb
 *
Packit b00eeb
 * This program is free software; you can redistribute it and/or modify
Packit b00eeb
 * it under the terms of the GNU Lesser General Public License as
Packit b00eeb
 * published by the Free Software Foundation; either version 2.1 of
Packit b00eeb
 * the License, or (at your option) any later version.
Packit b00eeb
 *
Packit b00eeb
 * This program is distributed in the hope that it will be useful, but
Packit b00eeb
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit b00eeb
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit b00eeb
 * Lesser General Public License for more details.
Packit b00eeb
 *
Packit b00eeb
 * You should have received a copy of the GNU Lesser General Public
Packit b00eeb
 * License along with this program; if not, see <http://www.gnu.org/licenses/>.
Packit b00eeb
 *
Packit b00eeb
 * Author: Stef Walter <stefw@collabora.co.uk>
Packit b00eeb
 */
Packit b00eeb
#include "config.h"
Packit b00eeb
Packit b00eeb
#include "gcr-subject-public-key.h"
Packit b00eeb
#include "gcr-types.h"
Packit b00eeb
Packit b00eeb
#include "gcr/gcr-oids.h"
Packit b00eeb
Packit b00eeb
#include "egg/egg-asn1x.h"
Packit b00eeb
#include "egg/egg-asn1-defs.h"
Packit b00eeb
#include "egg/egg-error.h"
Packit b00eeb
Packit b00eeb
#include <glib/gi18n-lib.h>
Packit b00eeb
Packit b00eeb
#include <gcrypt.h>
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
check_object_basics (GckBuilder *builder,
Packit b00eeb
                     gulong *klass,
Packit b00eeb
                     gulong *type)
Packit b00eeb
{
Packit b00eeb
	g_assert (klass != NULL);
Packit b00eeb
	g_assert (type != NULL);
Packit b00eeb
Packit b00eeb
	if (!gck_builder_find_ulong (builder, CKA_CLASS, klass))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	if (*klass == CKO_PUBLIC_KEY || *klass == CKO_PRIVATE_KEY)
Packit b00eeb
		return gck_builder_find_ulong (builder, CKA_KEY_TYPE, type);
Packit b00eeb
Packit b00eeb
	else if (*klass == CKO_CERTIFICATE)
Packit b00eeb
		return gck_builder_find_ulong (builder, CKA_CERTIFICATE_TYPE, type);
Packit b00eeb
Packit b00eeb
	*type = GCK_INVALID;
Packit b00eeb
	return FALSE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
load_object_basics (GckObject *object,
Packit b00eeb
                    GckBuilder *builder,
Packit b00eeb
                    GCancellable *cancellable,
Packit b00eeb
                    gulong *klass,
Packit b00eeb
                    gulong *type,
Packit b00eeb
                    GError **lerror)
Packit b00eeb
{
Packit b00eeb
	gulong attr_types[] = { CKA_CLASS, CKA_KEY_TYPE, CKA_CERTIFICATE_TYPE };
Packit b00eeb
	GckAttributes *attrs;
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
Packit b00eeb
	g_assert (klass != NULL);
Packit b00eeb
	g_assert (type != NULL);
Packit b00eeb
Packit b00eeb
	if (check_object_basics (builder, klass, type)) {
Packit b00eeb
		g_debug ("already loaded: class = %lu, type = %lu", *klass, *type);
Packit b00eeb
		return TRUE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	attrs = gck_object_cache_lookup (object, attr_types, G_N_ELEMENTS (attr_types),
Packit b00eeb
	                                 cancellable, &error);
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("couldn't load: %s", error->message);
Packit b00eeb
		g_propagate_error (lerror, error);
Packit b00eeb
		return FALSE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	gck_builder_set_all (builder, attrs);
Packit b00eeb
	gck_attributes_unref (attrs);
Packit b00eeb
Packit b00eeb
	if (!check_object_basics (builder, klass, type))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	g_debug ("loaded: class = %lu, type = %lu", *klass, *type);
Packit b00eeb
	return TRUE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
check_x509_attributes (GckBuilder *builder)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *value = gck_builder_find (builder, CKA_VALUE);
Packit b00eeb
	return (value && !gck_attribute_is_invalid (value));
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
load_x509_attributes (GckObject *object,
Packit b00eeb
                      GckBuilder *builder,
Packit b00eeb
                      GCancellable *cancellable,
Packit b00eeb
                      GError **lerror)
Packit b00eeb
{
Packit b00eeb
	gulong attr_types[] = { CKA_VALUE };
Packit b00eeb
	GckAttributes *attrs;
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
Packit b00eeb
	if (check_x509_attributes (builder)) {
Packit b00eeb
		g_debug ("already loaded");
Packit b00eeb
		return TRUE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	attrs = gck_object_cache_lookup (object, attr_types, G_N_ELEMENTS (attr_types),
Packit b00eeb
	                                 cancellable, &error);
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("couldn't load: %s", error->message);
Packit b00eeb
		g_propagate_error (lerror, error);
Packit b00eeb
		return FALSE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	gck_builder_set_all (builder, attrs);
Packit b00eeb
	gck_attributes_unref (attrs);
Packit b00eeb
Packit b00eeb
	return check_x509_attributes (builder);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
check_rsa_attributes (GckBuilder *builder)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *modulus;
Packit b00eeb
	const GckAttribute *exponent;
Packit b00eeb
Packit b00eeb
	modulus = gck_builder_find (builder, CKA_MODULUS);
Packit b00eeb
	exponent = gck_builder_find (builder, CKA_PUBLIC_EXPONENT);
Packit b00eeb
Packit b00eeb
	return (modulus && !gck_attribute_is_invalid (modulus) &&
Packit b00eeb
	        exponent && !gck_attribute_is_invalid (exponent));
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
load_rsa_attributes (GckObject *object,
Packit b00eeb
                     GckBuilder *builder,
Packit b00eeb
                     GCancellable *cancellable,
Packit b00eeb
                     GError **lerror)
Packit b00eeb
{
Packit b00eeb
	gulong attr_types[] = { CKA_MODULUS, CKA_PUBLIC_EXPONENT };
Packit b00eeb
	GckAttributes *attrs;
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
Packit b00eeb
	if (check_rsa_attributes (builder)) {
Packit b00eeb
		g_debug ("rsa attributes already loaded");
Packit b00eeb
		return TRUE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	attrs = gck_object_cache_lookup (object, attr_types, G_N_ELEMENTS (attr_types),
Packit b00eeb
	                                 cancellable, &error);
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("couldn't load rsa attributes: %s", error->message);
Packit b00eeb
		g_propagate_error (lerror, error);
Packit b00eeb
		return FALSE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	gck_builder_set_all (builder, attrs);
Packit b00eeb
	gck_attributes_unref (attrs);
Packit b00eeb
Packit b00eeb
	return check_rsa_attributes (builder);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GckObject *
Packit b00eeb
lookup_public_key (GckObject *object,
Packit b00eeb
                   GCancellable *cancellable,
Packit b00eeb
                   GError **lerror)
Packit b00eeb
{
Packit b00eeb
	GckBuilder builder = GCK_BUILDER_INIT;
Packit b00eeb
	gulong attr_types[] = { CKA_ID };
Packit b00eeb
	GckAttributes *attrs;
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
	GckSession *session;
Packit b00eeb
	GckObject *result;
Packit b00eeb
	const GckAttribute *id;
Packit b00eeb
	GList *objects;
Packit b00eeb
Packit b00eeb
	attrs = gck_object_cache_lookup (object, attr_types, G_N_ELEMENTS (attr_types),
Packit b00eeb
	                                 cancellable, &error);
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("couldn't load private key id: %s", error->message);
Packit b00eeb
		g_propagate_error (lerror, error);
Packit b00eeb
		return NULL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	id = gck_attributes_find (attrs, CKA_ID);
Packit b00eeb
	if (id == NULL || gck_attribute_is_invalid (id)) {
Packit b00eeb
		gck_attributes_unref (attrs);
Packit b00eeb
		g_debug ("couldn't load private key id");
Packit b00eeb
		g_set_error_literal (lerror, GCK_ERROR, CKR_ATTRIBUTE_TYPE_INVALID,
Packit b00eeb
		                     gck_message_from_rv (CKR_ATTRIBUTE_TYPE_INVALID));
Packit b00eeb
		return NULL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	gck_builder_add_ulong (&builder, CKA_CLASS, CKO_PUBLIC_KEY);
Packit b00eeb
	gck_builder_add_attribute (&builder, id);
Packit b00eeb
	gck_attributes_unref (attrs);
Packit b00eeb
Packit b00eeb
	session = gck_object_get_session (object);
Packit b00eeb
	objects = gck_session_find_objects (session, gck_builder_end (&builder), cancellable, &error);
Packit b00eeb
	g_object_unref (session);
Packit b00eeb
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("couldn't lookup public key: %s", error->message);
Packit b00eeb
		g_propagate_error (lerror, error);
Packit b00eeb
		return NULL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (!objects)
Packit b00eeb
		return NULL;
Packit b00eeb
Packit b00eeb
	result = g_object_ref (objects->data);
Packit b00eeb
	gck_list_unref_free (objects);
Packit b00eeb
Packit b00eeb
	return result;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
check_dsa_attributes (GckBuilder *builder)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *prime;
Packit b00eeb
	const GckAttribute *subprime;
Packit b00eeb
	const GckAttribute *base;
Packit b00eeb
	const GckAttribute *value;
Packit b00eeb
Packit b00eeb
	prime = gck_builder_find (builder, CKA_PRIME);
Packit b00eeb
	subprime = gck_builder_find (builder, CKA_SUBPRIME);
Packit b00eeb
	base = gck_builder_find (builder, CKA_BASE);
Packit b00eeb
	value = gck_builder_find (builder, CKA_VALUE);
Packit b00eeb
Packit b00eeb
	return (prime && !gck_attribute_is_invalid (prime) &&
Packit b00eeb
	        subprime && !gck_attribute_is_invalid (subprime) &&
Packit b00eeb
	        base && !gck_attribute_is_invalid (base) &&
Packit b00eeb
	        value && !gck_attribute_is_invalid (value));
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
load_dsa_attributes (GckObject *object,
Packit b00eeb
                     GckBuilder *builder,
Packit b00eeb
                     GCancellable *cancellable,
Packit b00eeb
                     GError **lerror)
Packit b00eeb
{
Packit b00eeb
	gulong attr_types[] = { CKA_PRIME, CKA_SUBPRIME, CKA_BASE, CKA_VALUE };
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
	GckAttributes *loaded;
Packit b00eeb
	GckObject *publi;
Packit b00eeb
	gulong klass;
Packit b00eeb
Packit b00eeb
	if (check_dsa_attributes (builder))
Packit b00eeb
		return TRUE;
Packit b00eeb
Packit b00eeb
	if (!gck_builder_find_ulong (builder, CKA_CLASS, &klass))
Packit b00eeb
		g_return_val_if_reached (FALSE);
Packit b00eeb
Packit b00eeb
	/* If it's a private key, find the public one */
Packit b00eeb
	if (klass == CKO_PRIVATE_KEY)
Packit b00eeb
		publi = lookup_public_key (object, cancellable, lerror);
Packit b00eeb
Packit b00eeb
	else
Packit b00eeb
		publi = g_object_ref (object);
Packit b00eeb
Packit b00eeb
	if (!publi)
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	loaded = gck_object_cache_lookup (publi, attr_types, G_N_ELEMENTS (attr_types),
Packit b00eeb
	                                  cancellable, &error);
Packit b00eeb
	g_object_unref (publi);
Packit b00eeb
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("couldn't load rsa attributes: %s", error->message);
Packit b00eeb
		g_propagate_error (lerror, error);
Packit b00eeb
		return FALSE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	/* We've made sure to load info from the public key, so change class */
Packit b00eeb
	gck_builder_set_ulong (builder, CKA_CLASS, CKO_PUBLIC_KEY);
Packit b00eeb
Packit b00eeb
	gck_builder_set_all (builder, loaded);
Packit b00eeb
	gck_attributes_unref (loaded);
Packit b00eeb
Packit b00eeb
	return check_dsa_attributes (builder);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
check_ec_attributes (GckBuilder *builder)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *ec_params;
Packit b00eeb
	const GckAttribute *ec_point;
Packit b00eeb
Packit b00eeb
	ec_params = gck_builder_find (builder, CKA_EC_PARAMS);
Packit b00eeb
	ec_point = gck_builder_find (builder, CKA_EC_POINT);
Packit b00eeb
Packit b00eeb
	return (ec_params && !gck_attribute_is_invalid (ec_params) &&
Packit b00eeb
	        ec_point && !gck_attribute_is_invalid (ec_point));
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
load_ec_attributes (GckObject *object,
Packit b00eeb
                    GckBuilder *builder,
Packit b00eeb
                    GCancellable *cancellable,
Packit b00eeb
                    GError **lerror)
Packit b00eeb
{
Packit b00eeb
	gulong attr_types[] = { CKA_EC_PARAMS, CKA_EC_POINT };
Packit b00eeb
	GckAttributes *attrs;
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
	GckObject *publi;
Packit b00eeb
	gulong klass;
Packit b00eeb
Packit b00eeb
	if (check_ec_attributes (builder)) {
Packit b00eeb
		g_debug ("ec attributes already loaded");
Packit b00eeb
		return TRUE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (!gck_builder_find_ulong (builder, CKA_CLASS, &klass))
Packit b00eeb
		g_return_val_if_reached (FALSE);
Packit b00eeb
Packit b00eeb
	/* If it's a private key, find the public one */
Packit b00eeb
	if (klass == CKO_PRIVATE_KEY)
Packit b00eeb
		publi = lookup_public_key (object, cancellable, lerror);
Packit b00eeb
Packit b00eeb
	else
Packit b00eeb
		publi = g_object_ref (object);
Packit b00eeb
Packit b00eeb
	if (!publi)
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	attrs = gck_object_cache_lookup (publi, attr_types, G_N_ELEMENTS (attr_types),
Packit b00eeb
	                                 cancellable, &error);
Packit b00eeb
	g_object_unref (publi);
Packit b00eeb
Packit b00eeb
	if (error != NULL) {
Packit b00eeb
		g_debug ("couldn't load ec attributes: %s", error->message);
Packit b00eeb
		g_propagate_error (lerror, error);
Packit b00eeb
		return FALSE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	gck_builder_set_all (builder, attrs);
Packit b00eeb
	gck_attributes_unref (attrs);
Packit b00eeb
Packit b00eeb
	return check_ec_attributes (builder);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
load_attributes (GckObject *object,
Packit b00eeb
                 GckBuilder *builder,
Packit b00eeb
                 GCancellable *cancellable,
Packit b00eeb
                 GError **lerror)
Packit b00eeb
{
Packit b00eeb
	gboolean ret = FALSE;
Packit b00eeb
	gulong klass;
Packit b00eeb
	gulong type;
Packit b00eeb
Packit b00eeb
	if (!load_object_basics (object, builder, cancellable,
Packit b00eeb
	                         &klass, &type, lerror))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	switch (klass) {
Packit b00eeb
Packit b00eeb
	case CKO_CERTIFICATE:
Packit b00eeb
		switch (type) {
Packit b00eeb
		case CKC_X_509:
Packit b00eeb
			ret = load_x509_attributes (object, builder, cancellable, lerror);
Packit b00eeb
			break;
Packit b00eeb
		default:
Packit b00eeb
			g_debug ("unsupported certificate type: %lu", type);
Packit b00eeb
			break;
Packit b00eeb
		}
Packit b00eeb
		break;
Packit b00eeb
Packit b00eeb
	case CKO_PUBLIC_KEY:
Packit b00eeb
	case CKO_PRIVATE_KEY:
Packit b00eeb
		switch (type) {
Packit b00eeb
		case CKK_RSA:
Packit b00eeb
			ret = load_rsa_attributes (object, builder, cancellable, lerror);
Packit b00eeb
			break;
Packit b00eeb
		case CKK_DSA:
Packit b00eeb
			ret = load_dsa_attributes (object, builder, cancellable, lerror);
Packit b00eeb
			break;
Packit b00eeb
		case CKK_EC:
Packit b00eeb
			ret = load_ec_attributes (object, builder, cancellable, lerror);
Packit b00eeb
			break;
Packit b00eeb
		default:
Packit b00eeb
			g_debug ("unsupported key type: %lu", type);
Packit b00eeb
			break;
Packit b00eeb
		}
Packit b00eeb
		break;
Packit b00eeb
Packit b00eeb
	default:
Packit b00eeb
		g_debug ("unsupported class: %lu", type);
Packit b00eeb
		break;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (ret == FALSE && lerror != NULL && *lerror == NULL) {
Packit b00eeb
		g_set_error_literal (lerror, GCR_DATA_ERROR, GCR_ERROR_UNRECOGNIZED,
Packit b00eeb
		                     _("Unrecognized or unavailable attributes for key"));
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return ret;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
check_attributes (GckBuilder *builder)
Packit b00eeb
{
Packit b00eeb
	gulong klass;
Packit b00eeb
	gulong type;
Packit b00eeb
Packit b00eeb
	if (!check_object_basics (builder, &klass, &type))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	switch (klass) {
Packit b00eeb
Packit b00eeb
	case CKO_CERTIFICATE:
Packit b00eeb
		switch (type) {
Packit b00eeb
		case CKC_X_509:
Packit b00eeb
			return check_x509_attributes (builder);
Packit b00eeb
		default:
Packit b00eeb
			return FALSE;
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
	case CKO_PUBLIC_KEY:
Packit b00eeb
	case CKO_PRIVATE_KEY:
Packit b00eeb
		switch (type) {
Packit b00eeb
		case CKK_RSA:
Packit b00eeb
			return check_rsa_attributes (builder);
Packit b00eeb
		case CKK_DSA:
Packit b00eeb
			return check_dsa_attributes (builder);
Packit b00eeb
		case CKK_EC:
Packit b00eeb
			return check_ec_attributes (builder);
Packit b00eeb
		default:
Packit b00eeb
			return FALSE;
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
	default:
Packit b00eeb
		return FALSE;
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
lookup_attributes (GckObject *object,
Packit b00eeb
                   GckBuilder *builder)
Packit b00eeb
{
Packit b00eeb
	GckObjectCache *oakey;
Packit b00eeb
	GckAttributes *attrs;
Packit b00eeb
Packit b00eeb
	if (GCK_IS_OBJECT_CACHE (object)) {
Packit b00eeb
		oakey = GCK_OBJECT_CACHE (object);
Packit b00eeb
		attrs = gck_object_cache_get_attributes (oakey);
Packit b00eeb
		if (attrs != NULL) {
Packit b00eeb
			gck_builder_add_all (builder, attrs);
Packit b00eeb
			gck_attributes_unref (attrs);
Packit b00eeb
		}
Packit b00eeb
	}
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
GNode *
Packit b00eeb
_gcr_subject_public_key_load (GckObject *key,
Packit b00eeb
                              GCancellable *cancellable,
Packit b00eeb
                              GError **error)
Packit b00eeb
{
Packit b00eeb
	GckBuilder builder = GCK_BUILDER_INIT;
Packit b00eeb
	GckAttributes *attributes;
Packit b00eeb
	GNode *asn;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (GCK_IS_OBJECT (key), NULL);
Packit b00eeb
	g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
Packit b00eeb
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit b00eeb
Packit b00eeb
	lookup_attributes (key, &builder);
Packit b00eeb
Packit b00eeb
	if (!check_attributes (&builder)) {
Packit b00eeb
		if (!load_attributes (key, &builder, cancellable, error)) {
Packit b00eeb
			gck_builder_clear (&builder);
Packit b00eeb
			return NULL;
Packit b00eeb
		}
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	attributes = gck_builder_end (&builder);
Packit b00eeb
	asn = _gcr_subject_public_key_for_attributes (attributes);
Packit b00eeb
	if (asn == NULL) {
Packit b00eeb
		g_set_error_literal (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT,
Packit b00eeb
		                     _("Couldn’t build public key"));
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	gck_attributes_unref (attributes);
Packit b00eeb
	return asn;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
typedef struct {
Packit b00eeb
	GckObject *object;
Packit b00eeb
	GckBuilder builder;
Packit b00eeb
} LoadClosure;
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
load_closure_free (gpointer data)
Packit b00eeb
{
Packit b00eeb
	LoadClosure *closure = data;
Packit b00eeb
	g_object_unref (closure->object);
Packit b00eeb
	gck_builder_clear (&closure->builder);
Packit b00eeb
	g_slice_free (LoadClosure, closure);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static void
Packit b00eeb
thread_key_attributes (GSimpleAsyncResult *res,
Packit b00eeb
                       GObject *object,
Packit b00eeb
                       GCancellable *cancellable)
Packit b00eeb
{
Packit b00eeb
	LoadClosure *closure = g_simple_async_result_get_op_res_gpointer (res);
Packit b00eeb
	GError *error = NULL;
Packit b00eeb
Packit b00eeb
	if (!load_attributes (closure->object, &closure->builder, cancellable, &error))
Packit b00eeb
		g_simple_async_result_take_error (res, error);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
void
Packit b00eeb
_gcr_subject_public_key_load_async (GckObject *key,
Packit b00eeb
                                    GCancellable *cancellable,
Packit b00eeb
                                    GAsyncReadyCallback callback,
Packit b00eeb
                                    gpointer user_data)
Packit b00eeb
{
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	LoadClosure *closure;
Packit b00eeb
Packit b00eeb
	g_return_if_fail (GCK_IS_OBJECT (key));
Packit b00eeb
	g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
Packit b00eeb
Packit b00eeb
	res = g_simple_async_result_new (NULL, callback, user_data,
Packit b00eeb
	                                 _gcr_subject_public_key_load_async);
Packit b00eeb
Packit b00eeb
	closure = g_slice_new0 (LoadClosure);
Packit b00eeb
	closure->object = g_object_ref (key);
Packit b00eeb
	lookup_attributes (key, &closure->builder);
Packit b00eeb
	g_simple_async_result_set_op_res_gpointer (res, closure, load_closure_free);
Packit b00eeb
Packit b00eeb
	if (check_attributes (&closure->builder)) {
Packit b00eeb
		g_simple_async_result_complete_in_idle (res);
Packit b00eeb
		g_object_unref (res);
Packit b00eeb
		return;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	g_simple_async_result_run_in_thread (res, thread_key_attributes,
Packit b00eeb
	                                     G_PRIORITY_DEFAULT, cancellable);
Packit b00eeb
	g_object_unref (res);
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
GNode *
Packit b00eeb
_gcr_subject_public_key_load_finish (GAsyncResult *result,
Packit b00eeb
                                     GError **error)
Packit b00eeb
{
Packit b00eeb
	GckAttributes *attributes;
Packit b00eeb
	GSimpleAsyncResult *res;
Packit b00eeb
	LoadClosure *closure;
Packit b00eeb
	GNode *asn;
Packit b00eeb
Packit b00eeb
	g_return_val_if_fail (error == NULL || *error == NULL, NULL);
Packit b00eeb
	g_return_val_if_fail (g_simple_async_result_is_valid (result, NULL,
Packit b00eeb
	                      _gcr_subject_public_key_load_async), NULL);
Packit b00eeb
Packit b00eeb
	res = G_SIMPLE_ASYNC_RESULT (result);
Packit b00eeb
	if (g_simple_async_result_propagate_error (res, error))
Packit b00eeb
		return NULL;
Packit b00eeb
Packit b00eeb
	closure = g_simple_async_result_get_op_res_gpointer (res);
Packit b00eeb
	attributes = gck_attributes_ref_sink (gck_builder_end (&closure->builder));
Packit b00eeb
	asn = _gcr_subject_public_key_for_attributes (attributes);
Packit b00eeb
	if (asn == NULL) {
Packit b00eeb
		g_set_error_literal (error, GCK_ERROR, CKR_TEMPLATE_INCONSISTENT,
Packit b00eeb
		                     _("Couldn’t build public key"));
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	gck_attributes_unref (attributes);
Packit b00eeb
	return asn;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
rsa_subject_public_key_from_attributes (GckAttributes *attrs,
Packit b00eeb
                                        GNode *info_asn)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *modulus;
Packit b00eeb
	const GckAttribute *exponent;
Packit b00eeb
	GNode *key_asn;
Packit b00eeb
	GNode *params_asn;
Packit b00eeb
	GBytes *key;
Packit b00eeb
	GBytes *usg;
Packit b00eeb
Packit b00eeb
	modulus = gck_attributes_find (attrs, CKA_MODULUS);
Packit b00eeb
	exponent = gck_attributes_find (attrs, CKA_PUBLIC_EXPONENT);
Packit b00eeb
	if (modulus == NULL || gck_attribute_is_invalid (modulus) ||
Packit b00eeb
	    exponent == NULL || gck_attribute_is_invalid (exponent))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	key_asn = egg_asn1x_create (pk_asn1_tab, "RSAPublicKey");
Packit b00eeb
	g_return_val_if_fail (key_asn, FALSE);
Packit b00eeb
Packit b00eeb
	params_asn = egg_asn1x_create (pk_asn1_tab, "RSAParameters");
Packit b00eeb
	g_return_val_if_fail (params_asn, FALSE);
Packit b00eeb
Packit b00eeb
	usg = g_bytes_new_with_free_func (modulus->value, modulus->length,
Packit b00eeb
	                                    gck_attributes_unref,
Packit b00eeb
	                                    gck_attributes_ref (attrs));
Packit b00eeb
	egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "modulus", NULL), usg);
Packit b00eeb
	g_bytes_unref (usg);
Packit b00eeb
Packit b00eeb
	usg = g_bytes_new_with_free_func (exponent->value, exponent->length,
Packit b00eeb
	                                    gck_attributes_unref,
Packit b00eeb
	                                    gck_attributes_ref (attrs));
Packit b00eeb
	egg_asn1x_set_integer_as_usg (egg_asn1x_node (key_asn, "publicExponent", NULL), usg);
Packit b00eeb
	g_bytes_unref (usg);
Packit b00eeb
Packit b00eeb
	key = egg_asn1x_encode (key_asn, NULL);
Packit b00eeb
	egg_asn1x_destroy (key_asn);
Packit b00eeb
Packit b00eeb
	egg_asn1x_set_null (params_asn);
Packit b00eeb
Packit b00eeb
	egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
Packit b00eeb
	                           key, g_bytes_get_size (key) * 8);
Packit b00eeb
Packit b00eeb
	egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_RSA);
Packit b00eeb
	egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn);
Packit b00eeb
Packit b00eeb
	egg_asn1x_destroy (params_asn);
Packit b00eeb
	g_bytes_unref (key);
Packit b00eeb
	return TRUE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
dsa_subject_public_key_from_private (GNode *key_asn,
Packit b00eeb
                                     const GckAttribute *ap,
Packit b00eeb
                                     const GckAttribute *aq,
Packit b00eeb
                                     const GckAttribute *ag,
Packit b00eeb
                                     const GckAttribute *ax)
Packit b00eeb
{
Packit b00eeb
	gcry_mpi_t mp, mq, mg, mx, my;
Packit b00eeb
	size_t n_buffer;
Packit b00eeb
	gcry_error_t gcry;
Packit b00eeb
	unsigned char *buffer;
Packit b00eeb
Packit b00eeb
	gcry = gcry_mpi_scan (&mp, GCRYMPI_FMT_USG, ap->value, ap->length, NULL);
Packit b00eeb
	g_return_val_if_fail (gcry == 0, FALSE);
Packit b00eeb
Packit b00eeb
	gcry = gcry_mpi_scan (&mq, GCRYMPI_FMT_USG, aq->value, aq->length, NULL);
Packit b00eeb
	g_return_val_if_fail (gcry == 0, FALSE);
Packit b00eeb
Packit b00eeb
	gcry = gcry_mpi_scan (&mg, GCRYMPI_FMT_USG, ag->value, ag->length, NULL);
Packit b00eeb
	g_return_val_if_fail (gcry == 0, FALSE);
Packit b00eeb
Packit b00eeb
	gcry = gcry_mpi_scan (&mx, GCRYMPI_FMT_USG, ax->value, ax->length, NULL);
Packit b00eeb
	g_return_val_if_fail (gcry == 0, FALSE);
Packit b00eeb
Packit b00eeb
	/* Calculate the public part from the private */
Packit b00eeb
	my = gcry_mpi_snew (gcry_mpi_get_nbits (mx));
Packit b00eeb
	g_return_val_if_fail (my, FALSE);
Packit b00eeb
	gcry_mpi_powm (my, mg, mx, mp);
Packit b00eeb
Packit b00eeb
	gcry = gcry_mpi_aprint (GCRYMPI_FMT_STD, &buffer, &n_buffer, my);
Packit b00eeb
	g_return_val_if_fail (gcry == 0, FALSE);
Packit b00eeb
	egg_asn1x_take_integer_as_raw (key_asn, g_bytes_new_with_free_func (buffer, n_buffer,
Packit b00eeb
	                                                                      gcry_free, buffer));
Packit b00eeb
Packit b00eeb
	gcry_mpi_release (mp);
Packit b00eeb
	gcry_mpi_release (mq);
Packit b00eeb
	gcry_mpi_release (mg);
Packit b00eeb
	gcry_mpi_release (mx);
Packit b00eeb
	gcry_mpi_release (my);
Packit b00eeb
Packit b00eeb
	return TRUE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
dsa_subject_public_key_from_attributes (GckAttributes *attrs,
Packit b00eeb
                                        gulong klass,
Packit b00eeb
                                        GNode *info_asn)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *value, *g, *q, *p;
Packit b00eeb
	GNode *key_asn, *params_asn;
Packit b00eeb
	GBytes *key;
Packit b00eeb
Packit b00eeb
	p = gck_attributes_find (attrs, CKA_PRIME);
Packit b00eeb
	q = gck_attributes_find (attrs, CKA_SUBPRIME);
Packit b00eeb
	g = gck_attributes_find (attrs, CKA_BASE);
Packit b00eeb
	value = gck_attributes_find (attrs, CKA_VALUE);
Packit b00eeb
Packit b00eeb
	if (p == NULL || gck_attribute_is_invalid (p) ||
Packit b00eeb
	    q == NULL || gck_attribute_is_invalid (q) ||
Packit b00eeb
	    g == NULL || gck_attribute_is_invalid (g) ||
Packit b00eeb
	    value == NULL || gck_attribute_is_invalid (value))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	key_asn = egg_asn1x_create (pk_asn1_tab, "DSAPublicPart");
Packit b00eeb
	g_return_val_if_fail (key_asn, FALSE);
Packit b00eeb
Packit b00eeb
	params_asn = egg_asn1x_create (pk_asn1_tab, "DSAParameters");
Packit b00eeb
	g_return_val_if_fail (params_asn, FALSE);
Packit b00eeb
Packit b00eeb
	egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "p", NULL),
Packit b00eeb
	                               g_bytes_new_with_free_func (p->value, p->length,
Packit b00eeb
	                                                             gck_attributes_unref,
Packit b00eeb
	                                                             gck_attributes_ref (attrs)));
Packit b00eeb
	egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "q", NULL),
Packit b00eeb
	                               g_bytes_new_with_free_func (q->value, q->length,
Packit b00eeb
	                                                             gck_attributes_unref,
Packit b00eeb
	                                                             gck_attributes_ref (attrs)));
Packit b00eeb
	egg_asn1x_take_integer_as_usg (egg_asn1x_node (params_asn, "g", NULL),
Packit b00eeb
	                               g_bytes_new_with_free_func (g->value, g->length,
Packit b00eeb
	                                                             gck_attributes_unref,
Packit b00eeb
	                                                             gck_attributes_ref (attrs)));
Packit b00eeb
Packit b00eeb
	/* Are these attributes for a public or private key? */
Packit b00eeb
	if (klass == CKO_PRIVATE_KEY) {
Packit b00eeb
Packit b00eeb
		/* We need to calculate the public from the private key */
Packit b00eeb
		if (!dsa_subject_public_key_from_private (key_asn, p, q, g, value))
Packit b00eeb
			g_return_val_if_reached (FALSE);
Packit b00eeb
Packit b00eeb
	} else if (klass == CKO_PUBLIC_KEY) {
Packit b00eeb
		egg_asn1x_take_integer_as_usg (key_asn,
Packit b00eeb
		                               g_bytes_new_with_free_func (value->value, value->length,
Packit b00eeb
		                                                             gck_attributes_unref,
Packit b00eeb
		                                                             gck_attributes_ref (attrs)));
Packit b00eeb
	} else {
Packit b00eeb
		g_assert_not_reached ();
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	key = egg_asn1x_encode (key_asn, NULL);
Packit b00eeb
	egg_asn1x_destroy (key_asn);
Packit b00eeb
Packit b00eeb
	egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
Packit b00eeb
	                           key, g_bytes_get_size (key) * 8);
Packit b00eeb
	egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn);
Packit b00eeb
Packit b00eeb
	egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_DSA);
Packit b00eeb
Packit b00eeb
	g_bytes_unref (key);
Packit b00eeb
	egg_asn1x_destroy (params_asn);
Packit b00eeb
	return TRUE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static gboolean
Packit b00eeb
ec_subject_public_key_from_attributes (GckAttributes *attrs,
Packit b00eeb
                                       gulong klass,
Packit b00eeb
                                       GNode *info_asn)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *ec_params, *ec_point;
Packit b00eeb
	GNode *params_asn, *point_asn;
Packit b00eeb
	GBytes *bytes, *key_bytes;
Packit b00eeb
Packit b00eeb
	ec_params = gck_attributes_find (attrs, CKA_EC_PARAMS);
Packit b00eeb
	ec_point = gck_attributes_find (attrs, CKA_EC_POINT);
Packit b00eeb
Packit b00eeb
	if (ec_params == NULL || gck_attribute_is_invalid (ec_params) ||
Packit b00eeb
	    ec_point == NULL || gck_attribute_is_invalid (ec_point))
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	bytes = g_bytes_new_with_free_func (ec_params->value, ec_params->length,
Packit b00eeb
	                                    gck_attributes_unref, gck_attributes_ref (attrs));
Packit b00eeb
	params_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECParameters", bytes);
Packit b00eeb
	g_bytes_unref (bytes);
Packit b00eeb
Packit b00eeb
	if (params_asn == NULL)
Packit b00eeb
		return FALSE;
Packit b00eeb
Packit b00eeb
	bytes = g_bytes_new_with_free_func (ec_point->value, ec_point->length,
Packit b00eeb
	                                    gck_attributes_unref, gck_attributes_ref (attrs));
Packit b00eeb
	point_asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECPoint", bytes);
Packit b00eeb
	g_bytes_unref (bytes);
Packit b00eeb
Packit b00eeb
	if (point_asn == NULL) {
Packit b00eeb
		egg_asn1x_destroy (params_asn);
Packit b00eeb
		return FALSE;
Packit b00eeb
	}
Packit b00eeb
	key_bytes = egg_asn1x_get_string_as_bytes (point_asn);
Packit b00eeb
	egg_asn1x_destroy (point_asn);
Packit b00eeb
	if (key_bytes == NULL) {
Packit b00eeb
		egg_asn1x_destroy (params_asn);
Packit b00eeb
		return FALSE;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	egg_asn1x_set_bits_as_raw (egg_asn1x_node (info_asn, "subjectPublicKey", NULL),
Packit b00eeb
	                           key_bytes, g_bytes_get_size (key_bytes) * 8);
Packit b00eeb
	egg_asn1x_set_any_from (egg_asn1x_node (info_asn, "algorithm", "parameters", NULL), params_asn);
Packit b00eeb
Packit b00eeb
	egg_asn1x_set_oid_as_quark (egg_asn1x_node (info_asn, "algorithm", "algorithm", NULL), GCR_OID_PKIX1_EC);
Packit b00eeb
Packit b00eeb
	g_bytes_unref (key_bytes);
Packit b00eeb
	egg_asn1x_destroy (params_asn);
Packit b00eeb
	return TRUE;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static GNode *
Packit b00eeb
cert_subject_public_key_from_attributes (GckAttributes *attributes)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *attr;
Packit b00eeb
	GBytes *bytes;
Packit b00eeb
	GNode *cert;
Packit b00eeb
	GNode *asn;
Packit b00eeb
Packit b00eeb
	attr = gck_attributes_find (attributes, CKA_VALUE);
Packit b00eeb
	if (attr == NULL || gck_attribute_is_invalid (attr)) {
Packit b00eeb
		g_debug ("no value attribute for certificate");
Packit b00eeb
		return NULL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	bytes = g_bytes_new_with_free_func (attr->value, attr->length,
Packit b00eeb
	                                      gck_attributes_unref,
Packit b00eeb
	                                      gck_attributes_ref (attributes));
Packit b00eeb
	cert = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", bytes);
Packit b00eeb
	g_bytes_unref (bytes);
Packit b00eeb
Packit b00eeb
	if (cert == NULL) {
Packit b00eeb
		g_debug ("couldn't parse certificate value");
Packit b00eeb
		return NULL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	asn = egg_asn1x_node (cert, "tbsCertificate", "subjectPublicKeyInfo", NULL);
Packit b00eeb
	g_return_val_if_fail (asn != NULL, NULL);
Packit b00eeb
Packit b00eeb
	/* Remove the subject public key out of the certificate */
Packit b00eeb
	g_node_unlink (asn);
Packit b00eeb
	egg_asn1x_destroy (cert);
Packit b00eeb
Packit b00eeb
	return asn;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
GNode *
Packit b00eeb
_gcr_subject_public_key_for_attributes (GckAttributes *attributes)
Packit b00eeb
{
Packit b00eeb
	gboolean ret = FALSE;
Packit b00eeb
	gulong key_type;
Packit b00eeb
	gulong klass;
Packit b00eeb
	GNode *asn = NULL;
Packit b00eeb
Packit b00eeb
	if (!gck_attributes_find_ulong (attributes, CKA_CLASS, &klass)) {
Packit b00eeb
		g_debug ("no class in attributes");
Packit b00eeb
		return NULL;
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	if (klass == CKO_CERTIFICATE) {
Packit b00eeb
		return cert_subject_public_key_from_attributes (attributes);
Packit b00eeb
Packit b00eeb
	} else if (klass == CKO_PUBLIC_KEY || klass == CKO_PRIVATE_KEY) {
Packit b00eeb
		if (!gck_attributes_find_ulong (attributes, CKA_KEY_TYPE, &key_type)) {
Packit b00eeb
			g_debug ("no key type in attributes");
Packit b00eeb
			return NULL;
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
		asn = egg_asn1x_create (pkix_asn1_tab, "SubjectPublicKeyInfo");
Packit b00eeb
		g_return_val_if_fail (asn, NULL);
Packit b00eeb
Packit b00eeb
		if (key_type == CKK_RSA) {
Packit b00eeb
			ret = rsa_subject_public_key_from_attributes (attributes, asn);
Packit b00eeb
Packit b00eeb
		} else if (key_type == CKK_DSA) {
Packit b00eeb
			ret = dsa_subject_public_key_from_attributes (attributes, klass, asn);
Packit b00eeb
Packit b00eeb
		} else if (key_type == CKK_ECDSA) {
Packit b00eeb
			ret = ec_subject_public_key_from_attributes (attributes, klass, asn);
Packit b00eeb
Packit b00eeb
		} else {
Packit b00eeb
			g_debug ("unsupported key type: %lu", key_type);
Packit b00eeb
			ret = FALSE;
Packit b00eeb
		}
Packit b00eeb
Packit b00eeb
Packit b00eeb
		if (ret == FALSE) {
Packit b00eeb
			egg_asn1x_destroy (asn);
Packit b00eeb
			asn = NULL;
Packit b00eeb
		}
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return asn;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static guint
Packit b00eeb
calculate_rsa_key_size (GBytes *data)
Packit b00eeb
{
Packit b00eeb
	GNode *asn;
Packit b00eeb
	GBytes *content;
Packit b00eeb
	guint key_size;
Packit b00eeb
Packit b00eeb
	asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data);
Packit b00eeb
	g_return_val_if_fail (asn, 0);
Packit b00eeb
Packit b00eeb
	content = egg_asn1x_get_value_raw (egg_asn1x_node (asn, "modulus", NULL));
Packit b00eeb
	if (!content)
Packit b00eeb
		g_return_val_if_reached (0);
Packit b00eeb
Packit b00eeb
	egg_asn1x_destroy (asn);
Packit b00eeb
Packit b00eeb
	/* Removes the complement */
Packit b00eeb
	key_size = (g_bytes_get_size (content) / 2) * 2 * 8;
Packit b00eeb
Packit b00eeb
	g_bytes_unref (content);
Packit b00eeb
	return key_size;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static guint
Packit b00eeb
attributes_rsa_key_size (GckAttributes *attrs)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *attr;
Packit b00eeb
	gulong bits;
Packit b00eeb
Packit b00eeb
	attr = gck_attributes_find (attrs, CKA_MODULUS);
Packit b00eeb
Packit b00eeb
	/* Calculate the bit length, and remove the complement */
Packit b00eeb
	if (attr != NULL)
Packit b00eeb
		return (attr->length / 2) * 2 * 8;
Packit b00eeb
Packit b00eeb
	if (gck_attributes_find_ulong (attrs, CKA_MODULUS_BITS, &bits))
Packit b00eeb
		return (gint)bits;
Packit b00eeb
Packit b00eeb
	return 0;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static guint
Packit b00eeb
calculate_dsa_params_size (GNode *params)
Packit b00eeb
{
Packit b00eeb
	GNode *asn;
Packit b00eeb
	GBytes *content;
Packit b00eeb
	guint key_size;
Packit b00eeb
Packit b00eeb
	asn = egg_asn1x_get_any_as (params, pk_asn1_tab, "DSAParameters");
Packit b00eeb
	g_return_val_if_fail (asn, 0);
Packit b00eeb
Packit b00eeb
	content = egg_asn1x_get_value_raw (egg_asn1x_node (asn, "p", NULL));
Packit b00eeb
	if (!content)
Packit b00eeb
		g_return_val_if_reached (0);
Packit b00eeb
Packit b00eeb
	egg_asn1x_destroy (asn);
Packit b00eeb
Packit b00eeb
	/* Removes the complement */
Packit b00eeb
	key_size = (g_bytes_get_size (content) / 2) * 2 * 8;
Packit b00eeb
Packit b00eeb
	g_bytes_unref (content);
Packit b00eeb
	return key_size;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static guint
Packit b00eeb
attributes_dsa_key_size (GckAttributes *attrs)
Packit b00eeb
{
Packit b00eeb
	const GckAttribute *attr;
Packit b00eeb
	gulong bits;
Packit b00eeb
Packit b00eeb
	attr = gck_attributes_find (attrs, CKA_PRIME);
Packit b00eeb
Packit b00eeb
	/* Calculate the bit length, and remove the complement */
Packit b00eeb
	if (attr != NULL)
Packit b00eeb
		return (attr->length / 2) * 2 * 8;
Packit b00eeb
Packit b00eeb
	if (gck_attributes_find_ulong (attrs, CKA_PRIME_BITS, &bits))
Packit b00eeb
		return (gint)bits;
Packit b00eeb
Packit b00eeb
	return 0;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static guint
Packit b00eeb
named_curve_size (GNode *params)
Packit b00eeb
{
Packit b00eeb
	GQuark oid;
Packit b00eeb
	guint size;
Packit b00eeb
Packit b00eeb
	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (params, "namedCurve", NULL));
Packit b00eeb
	if (oid == GCR_OID_EC_SECP192R1)
Packit b00eeb
		size = 192;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT163K1)
Packit b00eeb
		size = 163;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT163R2)
Packit b00eeb
		size = 163;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECP224R1)
Packit b00eeb
		size = 224;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT233K1)
Packit b00eeb
		size = 233;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT233R1)
Packit b00eeb
		size = 233;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECP256R1)
Packit b00eeb
		size = 256;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT283K1)
Packit b00eeb
		size = 283;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT283R1)
Packit b00eeb
		size = 283;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECP384R1)
Packit b00eeb
		size = 384;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT409K1)
Packit b00eeb
		size = 409;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT409R1)
Packit b00eeb
		size = 409;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECP521R1)
Packit b00eeb
		size = 521;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECP571K1)
Packit b00eeb
		size = 571;
Packit b00eeb
	else if (oid == GCR_OID_EC_SECT571R1)
Packit b00eeb
		size = 571;
Packit b00eeb
	else
Packit b00eeb
		size = 0;
Packit b00eeb
	return size;
Packit b00eeb
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static guint
Packit b00eeb
calculate_ec_params_size (GNode *params)
Packit b00eeb
{
Packit b00eeb
	GNode *asn;
Packit b00eeb
	guint size;
Packit b00eeb
Packit b00eeb
	asn = egg_asn1x_get_any_as (params, pk_asn1_tab, "ECParameters");
Packit b00eeb
	g_return_val_if_fail (asn, 0);
Packit b00eeb
Packit b00eeb
	size = named_curve_size (asn);
Packit b00eeb
	egg_asn1x_destroy (asn);
Packit b00eeb
Packit b00eeb
	return size;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
static guint
Packit b00eeb
attributes_ec_params_size (GckAttributes *attrs)
Packit b00eeb
{
Packit b00eeb
	GNode *asn;
Packit b00eeb
	const GckAttribute *attr;
Packit b00eeb
	GBytes *bytes;
Packit b00eeb
	guint size = 0;
Packit b00eeb
Packit b00eeb
	attr = gck_attributes_find (attrs, CKA_EC_PARAMS);
Packit b00eeb
Packit b00eeb
	/* Calculate the bit length, and remove the complement */
Packit b00eeb
	if (attr && !gck_attribute_is_invalid (attr)) {
Packit b00eeb
		bytes = g_bytes_new_with_free_func (attr->value, attr->length,
Packit b00eeb
		                                    gck_attributes_unref,
Packit b00eeb
		                                    gck_attributes_ref (attrs));
Packit b00eeb
		asn = egg_asn1x_create_and_decode (pk_asn1_tab, "ECParameters", bytes);
Packit b00eeb
		g_bytes_unref (bytes);
Packit b00eeb
Packit b00eeb
		if (asn)
Packit b00eeb
			size = named_curve_size (asn);
Packit b00eeb
		egg_asn1x_destroy (asn);
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return size;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
guint
Packit b00eeb
_gcr_subject_public_key_calculate_size (GNode *subject_public_key)
Packit b00eeb
{
Packit b00eeb
	GBytes *key;
Packit b00eeb
	GNode *params;
Packit b00eeb
	guint key_size = 0;
Packit b00eeb
	guint n_bits;
Packit b00eeb
	GQuark oid;
Packit b00eeb
Packit b00eeb
	/* Figure out the algorithm */
Packit b00eeb
	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (subject_public_key,
Packit b00eeb
	                                                  "algorithm", "algorithm", NULL));
Packit b00eeb
	g_return_val_if_fail (oid != 0, 0);
Packit b00eeb
Packit b00eeb
	/* RSA keys are stored in the main subjectPublicKey field */
Packit b00eeb
	if (oid == GCR_OID_PKIX1_RSA) {
Packit b00eeb
		key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (subject_public_key, "subjectPublicKey", NULL), &n_bits);
Packit b00eeb
		g_return_val_if_fail (key != NULL, 0);
Packit b00eeb
		key_size = calculate_rsa_key_size (key);
Packit b00eeb
		g_bytes_unref (key);
Packit b00eeb
Packit b00eeb
	/* The DSA key size is discovered by the prime in params */
Packit b00eeb
	} else if (oid == GCR_OID_PKIX1_DSA) {
Packit b00eeb
		params = egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL);
Packit b00eeb
		key_size = calculate_dsa_params_size (params);
Packit b00eeb
Packit b00eeb
	} else if (oid == GCR_OID_PKIX1_EC) {
Packit b00eeb
		params = egg_asn1x_node (subject_public_key, "algorithm", "parameters", NULL);
Packit b00eeb
		key_size = calculate_ec_params_size (params);
Packit b00eeb
Packit b00eeb
	} else {
Packit b00eeb
		g_message ("unsupported key algorithm: %s", g_quark_to_string (oid));
Packit b00eeb
	}
Packit b00eeb
Packit b00eeb
	return key_size;
Packit b00eeb
}
Packit b00eeb
Packit b00eeb
guint
Packit b00eeb
_gcr_subject_public_key_attributes_size (GckAttributes *attrs)
Packit b00eeb
{
Packit b00eeb
	gulong key_type;
Packit b00eeb
Packit b00eeb
	if (!gck_attributes_find_ulong (attrs, CKA_KEY_TYPE, &key_type))
Packit b00eeb
		return 0;
Packit b00eeb
Packit b00eeb
	switch (key_type) {
Packit b00eeb
	case CKK_RSA:
Packit b00eeb
		return attributes_rsa_key_size (attrs);
Packit b00eeb
	case CKK_DSA:
Packit b00eeb
		return attributes_dsa_key_size (attrs);
Packit b00eeb
	case CKK_EC:
Packit b00eeb
		return attributes_ec_params_size (attrs);
Packit b00eeb
	default:
Packit b00eeb
		g_message ("unsupported key algorithm: %lu", key_type);
Packit b00eeb
		return 0;
Packit b00eeb
	}
Packit b00eeb
}