Blame egg/egg-dn.c

Packit Service f02b19
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
Packit Service f02b19
/* egg-asn1.c - ASN.1 helper routines
Packit Service f02b19
Packit Service f02b19
   Copyright (C) 2007 Stefan Walter
Packit Service f02b19
Packit Service f02b19
   The Gnome Keyring Library is free software; you can redistribute it and/or
Packit Service f02b19
   modify it under the terms of the GNU Library General Public License as
Packit Service f02b19
   published by the Free Software Foundation; either version 2 of the
Packit Service f02b19
   License, or (at your option) any later version.
Packit Service f02b19
Packit Service f02b19
   The Gnome Keyring Library is distributed in the hope that it will be useful,
Packit Service f02b19
   but 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
   Library General Public License for more details.
Packit Service f02b19
Packit Service f02b19
   You should have received a copy of the GNU Library General Public
Packit Service f02b19
   License along with the Gnome Library; see the file COPYING.LIB.  If not,
Packit Service f02b19
   see <http://www.gnu.org/licenses/>.
Packit Service f02b19
Packit Service f02b19
   Author: Stef Walter <stef@memberwebs.com>
Packit Service f02b19
*/
Packit Service f02b19
Packit Service f02b19
#include "config.h"
Packit Service f02b19
Packit Service f02b19
#include "egg-asn1-defs.h"
Packit Service f02b19
#include "egg-asn1x.h"
Packit Service f02b19
#include "egg-dn.h"
Packit Service f02b19
#include "egg-oid.h"
Packit Service f02b19
Packit Service f02b19
#include <string.h>
Packit Service f02b19
Packit Service f02b19
static const char HEXC[] = "0123456789ABCDEF";
Packit Service f02b19
Packit Service f02b19
static gchar*
Packit Service f02b19
dn_print_hex_value (GBytes *val)
Packit Service f02b19
{
Packit Service f02b19
	const gchar *data = g_bytes_get_data (val, NULL);
Packit Service f02b19
	gsize size = g_bytes_get_size (val);
Packit Service f02b19
	GString *result = g_string_sized_new (size * 2 + 1);
Packit Service f02b19
	gsize i;
Packit Service f02b19
Packit Service f02b19
	g_string_append_c (result, '#');
Packit Service f02b19
	for (i = 0; i < size; ++i) {
Packit Service f02b19
		g_string_append_c (result, HEXC[data[i] >> 4 & 0xf]);
Packit Service f02b19
		g_string_append_c (result, HEXC[data[i] & 0xf]);
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	return g_string_free (result, FALSE);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static gchar*
Packit Service f02b19
dn_print_oid_value_parsed (GQuark oid,
Packit Service f02b19
                           guint flags,
Packit Service f02b19
                           GNode *val)
Packit Service f02b19
{
Packit Service f02b19
	GNode *asn1, *node;
Packit Service f02b19
	GBytes *value;
Packit Service f02b19
	const gchar *data;
Packit Service f02b19
	gsize size;
Packit Service f02b19
	gchar *result;
Packit Service f02b19
Packit Service f02b19
	g_assert (val != NULL);
Packit Service f02b19
Packit Service f02b19
	asn1 = egg_asn1x_create_quark (pkix_asn1_tab, oid);
Packit Service f02b19
	g_return_val_if_fail (asn1, NULL);
Packit Service f02b19
Packit Service f02b19
	if (!egg_asn1x_get_any_into (val, asn1)) {
Packit Service f02b19
		g_message ("couldn't decode value for OID: %s: %s",
Packit Service f02b19
		           g_quark_to_string (oid), egg_asn1x_message (asn1));
Packit Service f02b19
		egg_asn1x_destroy (asn1);
Packit Service f02b19
		return NULL;
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	/*
Packit Service f02b19
	 * If it's a choice element, then we have to read depending
Packit Service f02b19
	 * on what's there.
Packit Service f02b19
	 */
Packit Service f02b19
	if (flags & EGG_OID_IS_CHOICE)
Packit Service f02b19
		node = egg_asn1x_get_choice (asn1);
Packit Service f02b19
	else
Packit Service f02b19
		node = asn1;
Packit Service f02b19
Packit Service f02b19
	value = egg_asn1x_get_value_raw (node);
Packit Service f02b19
	data = g_bytes_get_data (value, &size);
Packit Service f02b19
Packit Service f02b19
	/*
Packit Service f02b19
	 * Now we make sure it's UTF-8.
Packit Service f02b19
	 */
Packit Service f02b19
Packit Service f02b19
	if (!value) {
Packit Service f02b19
		g_message ("couldn't read value for OID: %s", g_quark_to_string (oid));
Packit Service f02b19
		result = NULL;
Packit Service f02b19
Packit Service f02b19
	} else if (!g_utf8_validate (data, size, NULL)) {
Packit Service f02b19
		result = dn_print_hex_value (value);
Packit Service f02b19
Packit Service f02b19
	} else {
Packit Service f02b19
		result = g_strndup (data, size);
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	g_bytes_unref (value);
Packit Service f02b19
	egg_asn1x_destroy (asn1);
Packit Service f02b19
Packit Service f02b19
	return result;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static gchar*
Packit Service f02b19
dn_print_oid_value (GQuark oid,
Packit Service f02b19
                    guint flags,
Packit Service f02b19
                    GNode *val)
Packit Service f02b19
{
Packit Service f02b19
	GBytes *der;
Packit Service f02b19
	gchar *value;
Packit Service f02b19
Packit Service f02b19
	g_assert (val != NULL);
Packit Service f02b19
Packit Service f02b19
	if (flags & EGG_OID_PRINTABLE) {
Packit Service f02b19
		value = dn_print_oid_value_parsed (oid, flags, val);
Packit Service f02b19
		if (value != NULL)
Packit Service f02b19
			return value;
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	der = egg_asn1x_get_element_raw (val);
Packit Service f02b19
	value = dn_print_hex_value (der);
Packit Service f02b19
	g_bytes_unref (der);
Packit Service f02b19
Packit Service f02b19
	return value;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static gchar*
Packit Service f02b19
dn_parse_rdn (GNode *asn)
Packit Service f02b19
{
Packit Service f02b19
	const gchar *name;
Packit Service f02b19
	guint flags;
Packit Service f02b19
	GQuark oid;
Packit Service f02b19
	GNode *value;
Packit Service f02b19
	gchar *display;
Packit Service f02b19
	gchar *result;
Packit Service f02b19
Packit Service f02b19
	g_assert (asn);
Packit Service f02b19
Packit Service f02b19
	oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "type", NULL));
Packit Service f02b19
	g_return_val_if_fail (oid, NULL);
Packit Service f02b19
Packit Service f02b19
	flags = egg_oid_get_flags (oid);
Packit Service f02b19
	name = egg_oid_get_name (oid);
Packit Service f02b19
Packit Service f02b19
	value = egg_asn1x_node (asn, "value", NULL);
Packit Service f02b19
	g_return_val_if_fail (value, NULL);
Packit Service f02b19
Packit Service f02b19
	display = dn_print_oid_value (oid, flags, value);
Packit Service f02b19
	result = g_strconcat ((flags & EGG_OID_PRINTABLE) ? name : g_quark_to_string (oid),
Packit Service f02b19
	                      "=", display, NULL);
Packit Service f02b19
	g_free (display);
Packit Service f02b19
Packit Service f02b19
	return result;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
gchar*
Packit Service f02b19
egg_dn_read (GNode* asn)
Packit Service f02b19
{
Packit Service f02b19
	gboolean done = FALSE;
Packit Service f02b19
	GString *result;
Packit Service f02b19
	GNode *node;
Packit Service f02b19
	gchar *rdn;
Packit Service f02b19
	gint i, j;
Packit Service f02b19
Packit Service f02b19
	g_return_val_if_fail (asn, NULL);
Packit Service f02b19
Packit Service f02b19
	result = g_string_sized_new (64);
Packit Service f02b19
Packit Service f02b19
	/* Each (possibly multi valued) RDN */
Packit Service f02b19
	for (i = 1; !done; ++i) {
Packit Service f02b19
Packit Service f02b19
		/* Each type=value pair of an RDN */
Packit Service f02b19
		for (j = 1; TRUE; ++j) {
Packit Service f02b19
			node = egg_asn1x_node (asn, i, j, NULL);
Packit Service f02b19
			if (!node) {
Packit Service f02b19
				done = j == 1;
Packit Service f02b19
				break;
Packit Service f02b19
			}
Packit Service f02b19
Packit Service f02b19
			rdn = dn_parse_rdn (node);
Packit Service f02b19
			g_return_val_if_fail (rdn, NULL);
Packit Service f02b19
Packit Service f02b19
			/* Account for multi valued RDNs */
Packit Service f02b19
			if (j > 1)
Packit Service f02b19
				g_string_append (result, "+");
Packit Service f02b19
			else if (i > 1)
Packit Service f02b19
				g_string_append (result, ", ");
Packit Service f02b19
Packit Service f02b19
			g_string_append (result, rdn);
Packit Service f02b19
			g_free (rdn);
Packit Service f02b19
		}
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	/* Returns null when string is empty */
Packit Service f02b19
	return g_string_free (result, (result->len == 0));
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
gchar*
Packit Service f02b19
egg_dn_read_part (GNode *asn, const gchar *match)
Packit Service f02b19
{
Packit Service f02b19
	gboolean done = FALSE;
Packit Service f02b19
	const gchar *name;
Packit Service f02b19
	GNode *node;
Packit Service f02b19
	GQuark oid;
Packit Service f02b19
	gint i, j;
Packit Service f02b19
Packit Service f02b19
	g_return_val_if_fail (asn, NULL);
Packit Service f02b19
	g_return_val_if_fail (match, NULL);
Packit Service f02b19
Packit Service f02b19
	/* Each (possibly multi valued) RDN */
Packit Service f02b19
	for (i = 1; !done; ++i) {
Packit Service f02b19
Packit Service f02b19
		/* Each type=value pair of an RDN */
Packit Service f02b19
		for (j = 1; TRUE; ++j) {
Packit Service f02b19
			node = egg_asn1x_node (asn, i, j, "type", NULL);
Packit Service f02b19
			if (!node) {
Packit Service f02b19
				done = j == 1;
Packit Service f02b19
				break;
Packit Service f02b19
			}
Packit Service f02b19
Packit Service f02b19
			oid = egg_asn1x_get_oid_as_quark (node);
Packit Service f02b19
			g_return_val_if_fail (oid, NULL);
Packit Service f02b19
Packit Service f02b19
			/* Does it match either the OID or the displayable? */
Packit Service f02b19
			if (g_ascii_strcasecmp (g_quark_to_string (oid), match) != 0) {
Packit Service f02b19
				name = egg_oid_get_name (oid);
Packit Service f02b19
				if (!g_ascii_strcasecmp (name, match) == 0)
Packit Service f02b19
					continue;
Packit Service f02b19
			}
Packit Service f02b19
Packit Service f02b19
			node = egg_asn1x_node (asn, i, j, "value", NULL);
Packit Service f02b19
			g_return_val_if_fail (node, NULL);
Packit Service f02b19
Packit Service f02b19
			return dn_print_oid_value (oid, egg_oid_get_flags (oid), node);
Packit Service f02b19
		}
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	return NULL;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
gboolean
Packit Service f02b19
egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
Packit Service f02b19
{
Packit Service f02b19
	gboolean done = FALSE;
Packit Service f02b19
	GNode *node;
Packit Service f02b19
	GQuark oid;
Packit Service f02b19
	guint i, j;
Packit Service f02b19
Packit Service f02b19
	g_return_val_if_fail (asn, FALSE);
Packit Service f02b19
Packit Service f02b19
	/* Each (possibly multi valued) RDN */
Packit Service f02b19
	for (i = 1; !done; ++i) {
Packit Service f02b19
Packit Service f02b19
		/* Each type=value pair of an RDN */
Packit Service f02b19
		for (j = 1; TRUE; ++j) {
Packit Service f02b19
Packit Service f02b19
			/* Dig out the type */
Packit Service f02b19
			node = egg_asn1x_node (asn, i, j, "type", NULL);
Packit Service f02b19
			if (!node) {
Packit Service f02b19
				done = j == 1;
Packit Service f02b19
				break;
Packit Service f02b19
			}
Packit Service f02b19
Packit Service f02b19
			oid = egg_asn1x_get_oid_as_quark (node);
Packit Service f02b19
			g_return_val_if_fail (oid, FALSE);
Packit Service f02b19
Packit Service f02b19
			/* Dig out the value */
Packit Service f02b19
			node = egg_asn1x_node (asn, i, j, "value", NULL);
Packit Service f02b19
			if (!node) {
Packit Service f02b19
				done = j == 1;
Packit Service f02b19
				break;
Packit Service f02b19
			}
Packit Service f02b19
Packit Service f02b19
			if (callback)
Packit Service f02b19
				(callback) (i, oid, node, user_data);
Packit Service f02b19
		}
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	return i > 1;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
gchar *
Packit Service f02b19
egg_dn_print_value (GQuark oid,
Packit Service f02b19
                    GNode *value)
Packit Service f02b19
{
Packit Service f02b19
	g_return_val_if_fail (oid != 0, NULL);
Packit Service f02b19
	g_return_val_if_fail (value != NULL, NULL);
Packit Service f02b19
Packit Service f02b19
	return dn_print_oid_value (oid, egg_oid_get_flags (oid), value);
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static gboolean
Packit Service f02b19
is_ascii_string (const gchar *string)
Packit Service f02b19
{
Packit Service f02b19
	const gchar *p = string;
Packit Service f02b19
Packit Service f02b19
	g_return_val_if_fail (string != NULL, FALSE);
Packit Service f02b19
Packit Service f02b19
	for (p = string; *p != '\0'; p++) {
Packit Service f02b19
		if (!g_ascii_isspace (*p) && *p < ' ')
Packit Service f02b19
			return FALSE;
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	return TRUE;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
static gboolean
Packit Service f02b19
is_printable_string (const gchar *string)
Packit Service f02b19
{
Packit Service f02b19
	const gchar *p = string;
Packit Service f02b19
Packit Service f02b19
	g_return_val_if_fail (string != NULL, FALSE);
Packit Service f02b19
Packit Service f02b19
	for (p = string; *p != '\0'; p++) {
Packit Service f02b19
		if (!g_ascii_isalnum (*p) && !strchr (" '()+,-./:=?", *p))
Packit Service f02b19
			return FALSE;
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	return TRUE;
Packit Service f02b19
}
Packit Service f02b19
Packit Service f02b19
void
Packit Service f02b19
egg_dn_add_string_part (GNode *asn,
Packit Service f02b19
                        GQuark oid,
Packit Service f02b19
                        const gchar *string)
Packit Service f02b19
{
Packit Service f02b19
	GNode *node;
Packit Service f02b19
	GNode *value;
Packit Service f02b19
	GNode *val;
Packit Service f02b19
	guint flags;
Packit Service f02b19
Packit Service f02b19
	g_return_if_fail (asn != NULL);
Packit Service f02b19
	g_return_if_fail (oid != 0);
Packit Service f02b19
	g_return_if_fail (string != NULL);
Packit Service f02b19
Packit Service f02b19
	flags = egg_oid_get_flags (oid);
Packit Service f02b19
	g_return_if_fail (flags & EGG_OID_PRINTABLE);
Packit Service f02b19
Packit Service f02b19
	/* Add the RelativeDistinguishedName */
Packit Service f02b19
	node = egg_asn1x_append (asn);
Packit Service f02b19
Packit Service f02b19
	/* Add the AttributeTypeAndValue */
Packit Service f02b19
	node = egg_asn1x_append (node);
Packit Service f02b19
Packit Service f02b19
	egg_asn1x_set_oid_as_quark (egg_asn1x_node (node, "type", NULL), oid);
Packit Service f02b19
Packit Service f02b19
	value = egg_asn1x_create_quark (pkix_asn1_tab, oid);
Packit Service f02b19
Packit Service f02b19
	if (egg_asn1x_type (value) == EGG_ASN1X_CHOICE) {
Packit Service f02b19
		if (is_printable_string (string))
Packit Service f02b19
			val = egg_asn1x_node (value, "printableString", NULL);
Packit Service f02b19
		else if (is_ascii_string (string))
Packit Service f02b19
			val = egg_asn1x_node (value, "ia5String", NULL);
Packit Service f02b19
		else
Packit Service f02b19
			val = egg_asn1x_node (value, "utf8String", NULL);
Packit Service f02b19
		egg_asn1x_set_choice (value, val);
Packit Service f02b19
	} else {
Packit Service f02b19
		val = value;
Packit Service f02b19
	}
Packit Service f02b19
Packit Service f02b19
	egg_asn1x_set_string_as_utf8 (val, g_strdup (string), g_free);
Packit Service f02b19
Packit Service f02b19
	egg_asn1x_set_any_from (egg_asn1x_node (node, "value", NULL), value);
Packit Service f02b19
	egg_asn1x_destroy (value);
Packit Service f02b19
}