summaryrefslogtreecommitdiff
path: root/egg/egg-asn1x.c
diff options
context:
space:
mode:
authorStef Walter <stef@memberwebs.com>2009-12-25 16:21:47 +0000
committerStef Walter <stef@memberwebs.com>2010-06-24 03:00:13 +0000
commit50bdd9c5c905049111f407c6ddf1a204fcfe79a4 (patch)
treeba40d54b76593e4a2de28b2976da86c66905f84d /egg/egg-asn1x.c
parentba038c971212bda2258dcd0ee6f42daedf9a1b62 (diff)
downloadgcr-50bdd9c5c905049111f407c6ddf1a204fcfe79a4.tar.gz
[egg] Implement a bunch of value reading functionality.
Diffstat (limited to 'egg/egg-asn1x.c')
-rw-r--r--egg/egg-asn1x.c327
1 files changed, 286 insertions, 41 deletions
diff --git a/egg/egg-asn1x.c b/egg/egg-asn1x.c
index b656046..d325fb2 100644
--- a/egg/egg-asn1x.c
+++ b/egg/egg-asn1x.c
@@ -230,8 +230,8 @@ anode_def_value (GNode *node)
return an->def->value;
}
-static glong
-anode_def_value_as_long (GNode *node)
+static gulong
+anode_def_value_as_ulong (GNode *node)
{
const gchar* value;
gchar *end = NULL;
@@ -239,7 +239,7 @@ anode_def_value_as_long (GNode *node)
value = anode_def_value (node);
g_return_val_if_fail (value, G_MAXULONG);
- lval = strtol (value, &end, 10);
+ lval = strtoul (value, &end, 10);
g_return_val_if_fail (end && !end[0], G_MAXULONG);
return lval;
}
@@ -373,7 +373,6 @@ static gulong
anode_encode_tag_for_flags (GNode *node, gint flags)
{
GNode *child;
- gulong tag;
g_return_val_if_fail (anode_def_type_is_real (node), G_MAXULONG);
@@ -381,9 +380,7 @@ anode_encode_tag_for_flags (GNode *node, gint flags)
if (flags & FLAG_TAG) {
child = anode_child_with_type (node, TYPE_TAG);
g_return_val_if_fail (child, G_MAXULONG);
- tag = anode_def_value_as_long (child);
- g_return_val_if_fail (tag >= 0, G_MAXULONG);
- return tag;
+ return anode_def_value_as_ulong (child);
}
/* A tag from the universal set */
@@ -1166,7 +1163,7 @@ parse_general_time (const gchar *time, gsize n_time,
}
static gboolean
-anode_read_time (GNode *node, Atlv *tlv, time_t *value)
+anode_read_time (GNode *node, Atlv *tlv, glong *value)
{
const gchar *data;
gboolean ret;
@@ -1202,12 +1199,12 @@ anode_read_time (GNode *node, Atlv *tlv, time_t *value)
}
static gboolean
-anode_read_integer_as_long (GNode *node, Atlv *tlv, glong *value)
+anode_read_integer_as_ulong (GNode *node, Atlv *tlv, gulong *value)
{
const guchar *p;
gsize k;
- if (tlv->len < 1 || tlv->len > 4)
+ if (tlv->len < 1 || tlv->len > sizeof (gulong))
return FALSE;
p = tlv->buf + tlv->off;
@@ -1266,6 +1263,281 @@ anode_read_string (GNode *node, Atlv *tlv, gpointer value, gsize *n_value)
return TRUE;
}
+static gboolean
+anode_read_boolean (GNode *node, Atlv *tlv, gboolean *value)
+{
+ g_assert (node);
+ g_assert (tlv);
+ g_assert (value);
+
+ if (tlv->len != 1)
+ return FALSE;
+ if (tlv->buf[tlv->off] == 0x00)
+ *value = FALSE;
+ if (tlv->buf[tlv->off] == 0xFF)
+ *value = TRUE;
+ else
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
+{
+ GString *result = NULL;
+ const guchar *p;
+ gboolean lead;
+ guint val, pval;
+ gint k;
+
+ g_assert (tlv);
+ if (tlv->len <= 0)
+ return FALSE;
+ p = tlv->buf + tlv->off;
+
+ if (oid)
+ result = g_string_sized_new (32);
+
+ pval = p[0] / 40;
+ val = p[0] - pval * 40;
+
+ if (result)
+ g_string_append_printf (result, "%u.%u.", pval, val);
+
+ /* TODO: Validate first byte? */
+ for (k = 1, lead = 1, val = 0, pval = 0; k < tlv->len; ++k) {
+ /* X.690: the leading byte must never be 0x80 */
+ if (lead && p[k] == 0x80) {
+ anode_failure (node, "object id encoding is invalid");
+ break;
+ }
+ val = val << 7;
+ val |= p[k] & 0x7F;
+ /* Check for wrap around */
+ if (val < pval) {
+ anode_failure (node, "object id encoding is invalid");
+ break;
+ }
+ pval = val;
+ if (!(p[k] & 0x80)) {
+ if (result)
+ g_string_append_printf (result, "%u.", val);
+ pval = val = 0;
+ lead = 1;
+ }
+ }
+
+ if (k < tlv->len) {
+ if (result)
+ g_string_free (result, TRUE);
+ return FALSE;
+ }
+
+ if (result)
+ *oid = g_string_free (result, FALSE);
+ return TRUE;
+}
+
+GNode*
+egg_asn1x_node (GNode *asn, ...)
+{
+ GNode *node = asn;
+ const gchar *name;
+ va_list va;
+ gint type;
+ gint index, i;
+
+ g_return_val_if_fail (asn, NULL);
+ va_start (va, asn);
+
+ for (;;) {
+ type = anode_def_type (node);
+
+ /* Use integer indexes for these */
+ if (type == TYPE_SEQUENCE_OF || type == TYPE_SET_OF) {
+ index = va_arg (va, gint);
+ if (index == 0)
+ return node;
+ node = anode_child_with_real_type (node);
+ g_return_val_if_fail (node, NULL);
+ for (i = 1; node && i <= index; ++i)
+ node = anode_next_with_real_type (node);
+ if (node == NULL)
+ return NULL;
+
+ /* Use strings for these */
+ } else {
+ name = va_arg (va, const gchar*);
+ if (name == NULL)
+ return node;
+ /* Warn if they're using indexes here */
+ if (name <= (const gchar*)4096) {
+ g_warning ("possible misuse of egg_asn1x_node, expected a string, but got an index");
+ return NULL;
+ }
+ node = anode_child_with_name (node, name);
+ if (node == NULL)
+ return NULL;
+ }
+ }
+}
+
+gboolean
+egg_asn1x_get_boolean (GNode *node, gboolean *value)
+{
+ Atlv *tlv;
+
+ g_return_val_if_fail (node, FALSE);
+ g_return_val_if_fail (value, FALSE);
+ g_return_val_if_fail (anode_def_type (node) == TYPE_BOOLEAN, FALSE);
+
+ tlv = anode_get_tlv_data (node);
+ g_return_val_if_fail (tlv, FALSE);
+
+ return anode_read_boolean (node, tlv, value);
+}
+
+gboolean
+egg_asn1x_get_integer_as_ulong (GNode *node, gulong *value)
+{
+ Atlv *tlv;
+
+ g_return_val_if_fail (node, FALSE);
+ g_return_val_if_fail (value, FALSE);
+ g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
+
+ tlv = anode_get_tlv_data (node);
+ g_return_val_if_fail (tlv, FALSE);
+
+ return anode_read_integer_as_ulong(node, tlv, value);
+}
+
+gconstpointer
+egg_asn1x_get_integer_in_place (GNode *node, gsize *n_content)
+{
+ Atlv *tlv;
+
+ g_return_val_if_fail (node, NULL);
+ g_return_val_if_fail (n_content, NULL);
+ g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, NULL);
+
+ tlv = anode_get_tlv_data (node);
+ g_return_val_if_fail (tlv, NULL);
+
+ /* Integers are always primitive so we can do this */
+ g_return_val_if_fail (!(tlv->cls & ASN1_CLASS_STRUCTURED), NULL);
+
+ *n_content = tlv->len;
+ return tlv->buf + tlv->off;
+}
+
+guchar*
+egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_string)
+{
+ gsize length;
+ guchar *string;
+ Atlv *tlv;
+ gint type;
+
+ g_return_val_if_fail (node, NULL);
+ g_return_val_if_fail (n_string, NULL);
+
+ type = anode_def_type (node);
+ g_return_val_if_fail (type == TYPE_OCTET_STRING || type == TYPE_GENERALSTRING, NULL);
+
+ tlv = anode_get_tlv_data (node);
+ g_return_val_if_fail (tlv, NULL);
+
+ if (!anode_read_string (node, tlv, NULL, &length))
+ return NULL;
+
+ string = (allocator) (NULL, length + 1);
+ if (string == NULL)
+ return NULL;
+
+ if (!anode_read_string (node, tlv, string, &length)) {
+ (allocator) (string, 0);
+ return NULL;
+ }
+
+ /* Courtesy null termination, string must however be validated! */
+ string[length] = 0;
+ *n_string = length;
+ return string;
+}
+
+gchar*
+egg_asn1x_get_string_as_utf8 (GNode *node, EggAllocator allocator)
+{
+ gchar *string;
+ gsize n_string;
+
+ g_return_val_if_fail (node, NULL);
+
+ if (allocator == NULL)
+ allocator = g_realloc;
+
+ string = (gchar*)egg_asn1x_get_string_as_raw (node, allocator, &n_string);
+ if (!string)
+ return NULL;
+
+ if (!g_utf8_validate (string, n_string, NULL)) {
+ (allocator) (string, 0);
+ return NULL;
+ }
+
+ return string;
+}
+
+glong
+egg_asn1x_get_time_as_long (GNode *node)
+{
+ Atlv *tlv;
+ glong time;
+
+ g_return_val_if_fail (node, -1);
+ g_return_val_if_fail (anode_def_type (node) == TYPE_TIME, -1);
+
+ tlv = anode_get_tlv_data (node);
+ g_return_val_if_fail (tlv, -1);
+
+ if (!anode_read_time (node, tlv, &time))
+ return -1;
+ return time;
+}
+
+gchar*
+egg_asn1x_get_oid_as_string (GNode *node)
+{
+ gchar *oid;
+ Atlv *tlv;
+
+ g_return_val_if_fail (node, NULL);
+ g_return_val_if_fail (anode_def_type (node) == TYPE_OBJECT_ID, NULL);
+
+ tlv = anode_get_tlv_data (node);
+ g_return_val_if_fail (tlv, NULL);
+
+ if (!anode_read_object_id (node, tlv, &oid))
+ return NULL;
+
+ return oid;
+}
+
+GQuark
+egg_asn1x_get_oid_as_quark (GNode *node)
+{
+ GQuark quark;
+ gchar *oid;
+
+ oid = egg_asn1x_get_oid_as_string (node);
+ if (!oid)
+ return 0;
+ quark = g_quark_from_string (oid);
+ g_free (oid);
+ return quark;
+}
+
/* -----------------------------------------------------------------------------------
* VALIDATION
*/
@@ -1299,7 +1571,7 @@ anode_validate_size (GNode *node, gulong length)
static gboolean
anode_validate_integer (GNode *node, Atlv *tlv)
{
- glong value, check;
+ gulong value, check;
gboolean found;
GNode *child;
gint flags;
@@ -1313,14 +1585,14 @@ anode_validate_integer (GNode *node, Atlv *tlv)
flags = anode_def_flags (node);
if (flags & FLAG_LIST) {
/* Parse out the value, we only support small integers*/
- if (!anode_read_integer_as_long (node, tlv, &value))
+ if (!anode_read_integer_as_ulong (node, tlv, &value))
return anode_failure (node, "integer not part of list");
/* Look through the list of constants */
found = FALSE;
for (child = anode_child_with_type (node, TYPE_CONSTANT);
child; child = anode_next_with_type (child, TYPE_CONSTANT)) {
- check = anode_def_value_as_long (child);
+ check = anode_def_value_as_ulong (child);
g_return_val_if_fail (check != G_MAXULONG, FALSE);
if (check == value) {
found = TRUE;
@@ -1396,34 +1668,7 @@ anode_validate_string (GNode *node, Atlv *tlv)
static gboolean
anode_validate_object_id (GNode *node, Atlv *tlv)
{
- const guchar *p;
- gboolean lead;
- guint val, pval;
- gint k;
-
- g_assert (tlv);
- if (tlv->len <= 0)
- return FALSE;
- p = tlv->buf + tlv->off;
-
- /* TODO: Validate first byte? */
- for (k = 1, lead = 1, val = 0, pval = 0; k < tlv->len; ++k) {
- /* X.690: the leading byte must never be 0x80 */
- if (lead && p[k] == 0x80)
- return anode_failure (node, "object id encoding is invalid");
- val = val << 7;
- val |= p[k] & 0x7F;
- /* Check for wrap around */
- if (val < pval)
- return anode_failure (node, "object id encoding is invalid");
- pval = val;
- if (!(p[k] & 0x80)) {
- pval = val = 0;
- lead = 1;
- }
- }
-
- return TRUE;
+ return anode_read_object_id (node, tlv, NULL);
}
static gboolean