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

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