Use new DER decoding and encoding routines.
authorStef Walter <stef@memberwebs.com>
Fri, 9 Jul 2010 16:57:20 +0000 (16:57 +0000)
committerStef Walter <stef@memberwebs.com>
Sat, 10 Jul 2010 23:58:26 +0000 (23:58 +0000)
 * Benefits are less copies of sensitive data in memory.
 * More insightful parsing and API.

21 files changed:
egg/Makefile.am
egg/egg-asn1-defs.h [new file with mode: 0644]
egg/egg-asn1.c [deleted file]
egg/egg-asn1.h [deleted file]
egg/egg-asn1x.c
egg/egg-asn1x.h
egg/egg-dn.c
egg/egg-dn.h
egg/egg-symkey.c
egg/tests/Makefile.am
egg/tests/test-asn1.c
egg/tests/test-asn1x.c
egg/tests/test-data/test-pkcs7-2.der [new file with mode: 0755]
egg/tests/test-dn.c
egg/tests/test.asn
egg/tests/tests.asn [deleted file]
egg/tests/unit-test-asn1.c
gcr/gcr-certificate-details-widget.c
gcr/gcr-certificate.c
gcr/gcr-parser.c
gcr/gcr-simple-certificate.c

index 6e2642d..f22d000 100644 (file)
@@ -10,7 +10,7 @@ noinst_LTLIBRARIES = \
        libegg-entry-buffer.la
 
 BUILT_SOURCES = \
-       asn1-def-pk.h asn1-def-pkix.h
+       asn1-def-pk.c asn1-def-pkix.c
 
 INCLUDES = \
        -I$(top_srcdir)
@@ -21,7 +21,6 @@ libegg_la_CFLAGS = \
        $(GLIB_CFLAGS)
 
 libegg_la_SOURCES = \
-       egg-asn1.c egg-asn1.h \
        egg-asn1x.c egg-asn1x.h \
        egg-buffer.c egg-buffer.h \
        egg-cleanup.c egg-cleanup.h \
@@ -38,13 +37,14 @@ libegg_la_SOURCES = \
        egg-secure-memory.c egg-secure-memory.h \
        egg-spawn.c egg-spawn.h \
        egg-symkey.c egg-symkey.h \
+       egg-asn1-defs.h \
        $(BUILT_SOURCES)
 
-asn1-def-pk.h: pk.asn
-       $(ASN1PARSER) -o asn1-def-pk.h $(srcdir)/pk.asn
+asn1-def-pk.c: pk.asn
+       $(ASN1PARSER) -o asn1-def-pk.c $(srcdir)/pk.asn
 
-asn1-def-pkix.h: pkix.asn
-       $(ASN1PARSER) -o asn1-def-pkix.h $(srcdir)/pkix.asn
+asn1-def-pkix.c: pkix.asn
+       $(ASN1PARSER) -o asn1-def-pkix.c $(srcdir)/pkix.asn
 
 EXTRA_DIST = \
        pkix.asn \
@@ -57,7 +57,8 @@ DISTCLEANFILES = \
 # COMMON STUFF COMPILED INTO SMALLER COMPONENTS
 
 libegg_asn1x_la_SOURCES = \
-       egg-asn1x.c egg-asn1x.h
+       egg-asn1x.c egg-asn1x.h \
+       $(BUILT_SOURCES)
 
 libegg_asn1x_la_CFLAGS = \
        $(LIBTASN1_CFLAGS) \
diff --git a/egg/egg-asn1-defs.h b/egg/egg-asn1-defs.h
new file mode 100644 (file)
index 0000000..02fe427
--- /dev/null
@@ -0,0 +1,32 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-asn1-defs.h - ASN.1 definitions
+
+   Copyright (C) 2010 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef@memberwebs.com>
+*/
+
+#ifndef EGG_ASN1_DEFS_H_
+#define EGG_ASN1_DEFS_H_
+
+#include <libtasn1.h>
+
+extern const ASN1_ARRAY_TYPE pkix_asn1_tab[];
+extern const ASN1_ARRAY_TYPE pk_asn1_tab[];
+
+#endif /*EGG_ASN1_DEFS_H_*/
diff --git a/egg/egg-asn1.c b/egg/egg-asn1.c
deleted file mode 100644 (file)
index 681a580..0000000
+++ /dev/null
@@ -1,817 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* egg-asn1.c - ASN.1 helper routines
-
-   Copyright (C) 2007 Stefan Walter
-
-   The Gnome Keyring Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The Gnome Keyring Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the Gnome Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.
-
-   Author: Stef Walter <stef@memberwebs.com>
-*/
-
-#include "config.h"
-
-#include "egg-asn1.h"
-#include "egg-oid.h"
-
-#include <libtasn1.h>
-
-#include <string.h>
-
-#include <glib/gi18n-lib.h>
-
-/*
- * HACK: asn1Parser defines these arrays as extern const, which gives
- * gcc a fit. So we def it out.
- */
-
-#define extern
-#include "asn1-def-pk.h"
-#include "asn1-def-pkix.h"
-#undef extern
-
-static ASN1_TYPE asn1_pk = NULL;
-static ASN1_TYPE asn1_pkix = NULL;
-
-static void
-init_asn1_trees (void)
-{
-       static volatile gsize asn1_initialized = 0;
-       int res;
-
-       if (g_once_init_enter (&asn1_initialized)) {
-               res = asn1_array2tree (pk_asn1_tab, &asn1_pk, NULL);
-               g_return_if_fail (res == ASN1_SUCCESS);
-               res = asn1_array2tree (pkix_asn1_tab, &asn1_pkix, NULL);
-               g_return_if_fail (res == ASN1_SUCCESS);
-               g_once_init_leave (&asn1_initialized, 1);
-       }
-}
-
-ASN1_TYPE
-egg_asn1_get_pk_asn1type (void)
-{
-       init_asn1_trees ();
-       return asn1_pk;
-}
-
-ASN1_TYPE
-egg_asn1_get_pkix_asn1type (void)
-{
-       init_asn1_trees ();
-       return asn1_pkix;
-}
-
-ASN1_TYPE
-egg_asn1_decode (const gchar *type, const guchar *data, gsize n_data)
-{
-       ASN1_TYPE base = ASN1_TYPE_EMPTY;
-       ASN1_TYPE asn;
-       int res;
-
-       if (strncmp (type, "PKIX1.", 6) == 0)
-               base = egg_asn1_get_pkix_asn1type ();
-       else if (strncmp (type, "PK.", 3) == 0)
-               base = egg_asn1_get_pk_asn1type ();
-       else
-               g_return_val_if_reached (NULL);
-
-       res = asn1_create_element (base, type, &asn);
-       g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
-
-       res = asn1_der_decoding (&asn, data, n_data, NULL);
-       if (res != ASN1_SUCCESS) {
-               asn1_delete_structure (&asn);
-               return NULL;
-       }
-
-       return asn;
-}
-
-guchar*
-egg_asn1_encode (ASN1_TYPE asn, const gchar* part, gsize *n_data, EggAllocator alloc)
-{
-       guchar *data;
-       int res, len;
-
-       g_assert (asn);
-       g_assert (n_data);
-
-       len = 0;
-       res = asn1_der_coding (asn, part, NULL, &len, NULL);
-       g_return_val_if_fail (res == ASN1_MEM_ERROR, NULL);
-
-       if (!alloc)
-               alloc = (EggAllocator)g_realloc;
-
-       data = (alloc) (NULL, len);
-       g_return_val_if_fail (data != NULL, NULL);
-
-       res = asn1_der_coding (asn, part, data, &len, NULL);
-       if (res != ASN1_SUCCESS) {
-               (alloc) (data, 0);
-               return NULL;
-       }
-
-       *n_data = len;
-       return data;
-}
-
-gint
-egg_asn1_element_length (const guchar *data, gsize n_data)
-{
-       guchar cls;
-       int counter = 0;
-       int cb, len;
-       gulong tag;
-
-       if (asn1_get_tag_der (data, n_data, &cls, &cb, &tag) == ASN1_SUCCESS) {
-               counter += cb;
-               len = asn1_get_length_der (data + cb, n_data - cb, &cb);
-               counter += cb;
-               if (len >= 0) {
-                       len += counter;
-                       if (n_data >= len)
-                               return len;
-               }
-       }
-
-       return -1;
-}
-
-const guchar*
-egg_asn1_read_element (ASN1_TYPE asn, const guchar *data, gsize n_data,
-                            const gchar *part, gsize *n_element)
-{
-       int beg, end, res;
-
-       g_return_val_if_fail (asn != NULL, NULL);
-       g_return_val_if_fail (part != NULL, NULL);
-       g_return_val_if_fail (data != NULL, NULL);
-       g_return_val_if_fail (n_element != NULL, NULL);
-
-       res = asn1_der_decoding_startEnd (asn, data, n_data, part, &beg, &end);
-       if (res != ASN1_SUCCESS)
-               return NULL;
-
-       *n_element = end - beg + 1;
-       return data + beg;
-}
-
-const guchar*
-egg_asn1_read_content (ASN1_TYPE asn, const guchar *data, gsize n_data,
-                            const gchar *part, gsize *n_content)
-{
-       const guchar *raw;
-       gsize n_raw;
-
-       g_return_val_if_fail (asn != NULL, NULL);
-       g_return_val_if_fail (part != NULL, NULL);
-       g_return_val_if_fail (data != NULL, NULL);
-       g_return_val_if_fail (n_content != NULL, NULL);
-
-       raw = egg_asn1_read_element (asn, data, n_data, part, &n_raw);
-       if (!raw)
-               return NULL;
-
-       return egg_asn1_element_content (raw, n_raw, n_content);
-}
-
-const guchar*
-egg_asn1_element_content (const guchar *data, gsize n_data, gsize *n_content)
-{
-       int counter = 0;
-       guchar cls;
-       gulong tag;
-       int cb, len;
-
-       g_return_val_if_fail (data != NULL, NULL);
-       g_return_val_if_fail (n_content != NULL, NULL);
-
-       /* Now get the data out of this element */
-       if (asn1_get_tag_der (data, n_data, &cls, &cb, &tag) != ASN1_SUCCESS)
-               return NULL;
-
-       counter += cb;
-       len = asn1_get_length_der (data + cb, n_data - cb, &cb);
-       if (len < 0)
-               return NULL;
-       counter += cb;
-
-       *n_content = len;
-       return data + counter;
-}
-
-guchar*
-egg_asn1_read_value (ASN1_TYPE asn, const gchar *part, gsize *len, EggAllocator allocator)
-{
-       int l, res;
-       guchar *buf;
-
-       g_return_val_if_fail (asn != NULL, NULL);
-       g_return_val_if_fail (part != NULL, NULL);
-       g_return_val_if_fail (len != NULL, NULL);
-
-       if (allocator == NULL)
-               allocator = (EggAllocator)g_realloc;
-
-       l = 0;
-       res = asn1_read_value (asn, part, NULL, &l);
-       g_return_val_if_fail (res != ASN1_SUCCESS, NULL);
-       if (res != ASN1_MEM_ERROR)
-               return NULL;
-
-       /* Always null terminate it, just for convenience */
-       buf = (allocator) (NULL, l + 1);
-       g_return_val_if_fail (buf, NULL);
-       memset (buf, 0, l + 1);
-
-       res = asn1_read_value (asn, part, buf, &l);
-       if (res != ASN1_SUCCESS) {
-               (allocator) (buf, 0);
-               buf = NULL;
-       } else {
-               *len = l;
-       }
-
-       return buf;
-}
-
-gboolean
-egg_asn1_write_value (ASN1_TYPE asn, const gchar *part,
-                                  const guchar* value, gsize len)
-{
-       int res;
-
-       g_return_val_if_fail (asn, FALSE);
-       g_return_val_if_fail (part, FALSE);
-       g_return_val_if_fail (!len || value, FALSE);
-
-       res = asn1_write_value (asn, part, (const void*)value, (int)len);
-       return res == ASN1_SUCCESS;
-}
-
-static gboolean
-ascii_length_equals (const gchar *str, gconstpointer data, gsize n_data)
-{
-       g_assert (str);
-       if (!data)
-               return FALSE;
-       if (strlen (str) != n_data)
-               return FALSE;
-       return strncmp (str, data, n_data) == 0;
-}
-
-static gboolean
-ascii_length_case_equals (const gchar *str, gconstpointer data, gsize n_data)
-{
-       g_assert (str);
-       if (!data)
-               return FALSE;
-       if (strlen (str) != n_data)
-               return FALSE;
-       return g_ascii_strncasecmp (str, data, n_data) == 0;
-}
-
-gboolean
-egg_asn1_read_boolean (ASN1_TYPE asn, const gchar *part, gboolean *val)
-{
-       gchar buffer[32];
-       int n_buffer = sizeof (buffer);
-       int res;
-
-       memset (buffer, 0, sizeof (buffer));
-
-       res = asn1_read_value (asn, part, buffer, &n_buffer);
-       if (res != ASN1_SUCCESS || !n_buffer)
-               return FALSE;
-
-       if (ascii_length_case_equals ("TRUE", buffer, n_buffer - 1))
-               *val = TRUE;
-       else
-               *val = FALSE;
-
-       return TRUE;
-}
-
-gboolean
-egg_asn1_read_uint (ASN1_TYPE asn, const gchar *part, guint *val)
-{
-       guchar buf[4];
-       int n_buf = sizeof (buf);
-       gsize i;
-       int res;
-
-       res = asn1_read_value (asn, part, buf, &n_buf);
-       if(res != ASN1_SUCCESS)
-               return FALSE;
-
-       if (n_buf > 4 || n_buf < 1)
-               return FALSE;
-
-       *val = 0;
-       for (i = 0; i < n_buf; ++i)
-               *val |= buf[i] << (8 * ((n_buf - 1) - i));
-
-       return TRUE;
-}
-
-gboolean
-egg_asn1_write_uint (ASN1_TYPE asn, const gchar *part, guint32 val)
-{
-       guchar buf[4];
-       int res, bytes;
-
-       buf[0] = (val >> 24) & 0xff;
-       buf[1] = (val >> 16) & 0xff;
-       buf[2] = (val >> 8) & 0xff;
-       buf[3] = (val >> 0) & 0xff;
-
-       for (bytes = 3; bytes >= 0; --bytes)
-               if (!buf[bytes])
-                       break;
-
-       bytes = 4 - (bytes + 1);
-       if (bytes == 0)
-               bytes = 1;
-       res = asn1_write_value (asn, part, buf + (4 - bytes), bytes);
-       return res == ASN1_SUCCESS;
-}
-
-GQuark
-egg_asn1_read_oid (ASN1_TYPE asn, const gchar *part)
-{
-       GQuark quark;
-       guchar *buf;
-       gpointer end;
-       gsize n_buf;
-
-       buf = egg_asn1_read_value (asn, part, &n_buf, NULL);
-       if (!buf || !n_buf)
-               return 0;
-
-       /* Make sure the string is actually that long */
-       end = memchr (buf, 0, n_buf - 1);
-       if (end != NULL)
-               return 0;
-
-       quark = g_quark_from_string ((gchar*)buf);
-       g_free (buf);
-       return quark;
-}
-
-gboolean
-egg_asn1_write_oid (ASN1_TYPE asn, const gchar *part, GQuark val)
-{
-       const gchar* oid;
-
-       g_return_val_if_fail (val, FALSE);
-
-       oid = g_quark_to_string (val);
-       g_return_val_if_fail (oid, FALSE);
-
-       return egg_asn1_write_value (asn, part, (const guchar*)oid, strlen (oid));
-}
-
-static int
-atoin (const char *p, int digits)
-{
-       int ret = 0, base = 1;
-       while(--digits >= 0) {
-               if (p[digits] < '0' || p[digits] > '9')
-                       return -1;
-               ret += (p[digits] - '0') * base;
-               base *= 10;
-       }
-       return ret;
-}
-
-static int
-two_to_four_digit_year (int year)
-{
-       time_t now;
-       struct tm tm;
-       int century, current;
-
-       g_return_val_if_fail (year >= 0 && year <= 99, -1);
-
-       /* Get the current year */
-       now = time (NULL);
-       g_return_val_if_fail (now >= 0, -1);
-       if (!gmtime_r (&now, &tm))
-               g_return_val_if_reached (-1);
-
-       current = (tm.tm_year % 100);
-       century = (tm.tm_year + 1900) - current;
-
-       /*
-        * Check if it's within 40 years before the
-        * current date.
-        */
-       if (current < 40) {
-               if (year < current)
-                       return century + year;
-               if (year > 100 - (40 - current))
-                       return (century - 100) + year;
-       } else {
-               if (year < current && year > (current - 40))
-                       return century + year;
-       }
-
-       /*
-        * If it's after then adjust for overflows to
-        * the next century.
-        */
-       if (year < current)
-               return century + 100 + year;
-       else
-               return century + year;
-}
-
-#ifndef HAVE_TIMEGM
-time_t timegm(struct tm *t)
-{
-       time_t tl, tb;
-       struct tm *tg;
-
-       tl = mktime (t);
-       if (tl == -1)
-       {
-               t->tm_hour--;
-               tl = mktime (t);
-               if (tl == -1)
-                       return -1; /* can't deal with output from strptime */
-               tl += 3600;
-       }
-       tg = gmtime (&tl);
-       tg->tm_isdst = 0;
-       tb = mktime (tg);
-       if (tb == -1)
-       {
-               tg->tm_hour--;
-               tb = mktime (tg);
-               if (tb == -1)
-                       return -1; /* can't deal with output from gmtime */
-               tb += 3600;
-       }
-       return (tl - (tb - tl));
-}
-#endif //NOT_HAVE_TIMEGM
-
-static gboolean
-parse_utc_time (const gchar *time, gsize n_time,
-                struct tm* when, gint *offset)
-{
-       const char *p, *e;
-       int year;
-
-       g_assert (when);
-       g_assert (time);
-       g_assert (offset);
-
-       if (n_time != strlen (time))
-               return FALSE;
-
-       /* YYMMDDhhmmss.ffff Z | +0000 */
-       if (n_time < 6 || n_time >= 28)
-               return FALSE;
-
-       /* Reset everything to default legal values */
-       memset (when, 0, sizeof (*when));
-       *offset = 0;
-       when->tm_mday = 1;
-
-       /* Select the digits part of it */
-       p = time;
-       for (e = p; *e >= '0' && *e <= '9'; ++e);
-
-       if (p + 2 <= e) {
-               year = atoin (p, 2);
-               p += 2;
-
-               /*
-                * 40 years in the past is our century. 60 years
-                * in the future is the next century.
-                */
-               when->tm_year = two_to_four_digit_year (year) - 1900;
-       }
-       if (p + 2 <= e) {
-               when->tm_mon = atoin (p, 2) - 1;
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_mday = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_hour = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_min = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_sec = atoin (p, 2);
-               p += 2;
-       }
-
-       if (when->tm_year < 0 || when->tm_year > 9999 ||
-           when->tm_mon < 0 || when->tm_mon > 11 ||
-           when->tm_mday < 1 || when->tm_mday > 31 ||
-           when->tm_hour < 0 || when->tm_hour > 23 ||
-           when->tm_min < 0 || when->tm_min > 59 ||
-           when->tm_sec < 0 || when->tm_sec > 59)
-               return FALSE;
-
-       /* Make sure all that got parsed */
-       if (p != e)
-               return FALSE;
-
-       /* Now the remaining optional stuff */
-       e = time + n_time;
-
-       /* See if there's a fraction, and discard it if so */
-       if (p < e && *p == '.' && p + 5 <= e)
-               p += 5;
-
-       /* See if it's UTC */
-       if (p < e && *p == 'Z') {
-               p += 1;
-
-       /* See if it has a timezone */
-       } else if ((*p == '-' || *p == '+') && p + 3 <= e) {
-               int off, neg;
-
-               neg = *p == '-';
-               ++p;
-
-               off = atoin (p, 2) * 3600;
-               if (off < 0 || off > 86400)
-                       return -1;
-               p += 2;
-
-               if (p + 2 <= e) {
-                       off += atoin (p, 2) * 60;
-                       p += 2;
-               }
-
-               /* Use TZ offset */
-               if (neg)
-                       *offset = 0 - off;
-               else
-                       *offset = off;
-       }
-
-       /* Make sure everything got parsed */
-       if (p != e)
-               return FALSE;
-
-       return TRUE;
-}
-
-static time_t
-when_to_time (struct tm *when, gint offset)
-{
-       time_t result;
-
-       g_assert (when);
-
-       /* In order to work with 32 bit time_t. */
-       if (sizeof (time_t) <= 4 && when->tm_year >= 2038)
-               return (time_t) 2145914603;  /* 2037-12-31 23:23:23 */
-
-       /* Convert to seconds since epoch */
-       result = timegm (when);
-       if (result >= 0)
-               result += offset;
-
-       return result;
-}
-
-glong
-egg_asn1_time_parse_utc (const gchar *time, gssize n_time)
-{
-       struct tm when;
-       gint offset;
-
-       g_return_val_if_fail (time, -1);
-
-       if (n_time == -1)
-               n_time = strlen (time);
-
-       if (!parse_utc_time (time, n_time, &when, &offset))
-               return -1;
-
-       return when_to_time (&when, offset);
-}
-
-static gboolean
-parse_general_time (const gchar *time, gsize n_time,
-                    struct tm* when, gint *offset)
-{
-       const char *p, *e;
-
-       g_assert (time);
-       g_assert (when);
-       g_assert (offset);
-
-       if (strlen (time) != n_time)
-               return FALSE;
-
-       /* YYYYMMDDhhmmss.ffff Z | +0000 */
-       if (n_time < 8 || n_time >= 30)
-               return FALSE;
-
-       /* Reset everything to default legal values */
-       memset (when, 0, sizeof (*when));
-       *offset = 0;
-       when->tm_mday = 1;
-
-       /* Select the digits part of it */
-       p = time;
-       for (e = p; *e >= '0' && *e <= '9'; ++e);
-
-       if (p + 4 <= e) {
-               when->tm_year = atoin (p, 4) - 1900;
-               p += 4;
-       }
-       if (p + 2 <= e) {
-               when->tm_mon = atoin (p, 2) - 1;
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_mday = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_hour = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_min = atoin (p, 2);
-               p += 2;
-       }
-       if (p + 2 <= e) {
-               when->tm_sec = atoin (p, 2);
-               p += 2;
-       }
-
-       if (when->tm_year < 0 || when->tm_year > 9999 ||
-           when->tm_mon < 0 || when->tm_mon > 11 ||
-           when->tm_mday < 1 || when->tm_mday > 31 ||
-           when->tm_hour < 0 || when->tm_hour > 23 ||
-           when->tm_min < 0 || when->tm_min > 59 ||
-           when->tm_sec < 0 || when->tm_sec > 59)
-               return FALSE;
-
-       /* Make sure all that got parsed */
-       if (p != e)
-               return FALSE;
-
-       /* Now the remaining optional stuff */
-       e = time + n_time;
-
-       /* See if there's a fraction, and discard it if so */
-       if (p < e && *p == '.' && p + 5 <= e)
-               p += 5;
-
-       /* See if it's UTC */
-       if (p < e && *p == 'Z') {
-               p += 1;
-
-       /* See if it has a timezone */
-       } else if ((*p == '-' || *p == '+') && p + 3 <= e) {
-               int off, neg;
-
-               neg = *p == '-';
-               ++p;
-
-               off = atoin (p, 2) * 3600;
-               if (off < 0 || off > 86400)
-                       return -1;
-               p += 2;
-
-               if (p + 2 <= e) {
-                       off += atoin (p, 2) * 60;
-                       p += 2;
-               }
-
-               /* Use TZ offset */
-               if (neg)
-                       *offset = 0 - off;
-               else
-                       *offset = off;
-       }
-
-       /* Make sure everything got parsed */
-       if (p != e)
-               return FALSE;
-
-       return TRUE;
-}
-
-glong
-egg_asn1_time_parse_general (const gchar *time, gssize n_time)
-{
-       struct tm when;
-       gint offset;
-
-       g_return_val_if_fail (time, -1);
-
-       if (n_time == -1)
-               n_time = strlen (time);
-
-       if (!parse_general_time (time, n_time, &when, &offset))
-               return -1;
-
-       return when_to_time (&when, offset);
-}
-
-static gboolean
-read_asn1_time (ASN1_TYPE asn, const gchar *part, struct tm *when, gint *offset)
-{
-       gchar ttime[256];
-       gchar *name;
-       int len, res;
-
-       g_assert (asn);
-       g_assert (part);
-       g_assert (when);
-       g_assert (offset);
-
-       len = sizeof (ttime);
-       res = asn1_read_value (asn, part, ttime, &len);
-       if (res != ASN1_SUCCESS)
-               return FALSE;
-       --len; /* libtasn1 returns the null terminator in this count */
-
-       /* CHOICE */
-       if (ascii_length_equals ("generalTime", ttime, len)) {
-               name = g_strconcat (part, ".generalTime", NULL);
-               len = sizeof (ttime) - 1;
-               res = asn1_read_value (asn, name, ttime, &len);
-               g_free (name);
-               if (res != ASN1_SUCCESS)
-                       return FALSE;
-               return parse_general_time (ttime, len - 1, when, offset);
-
-       /* UTCTIME */
-       } else if (ascii_length_equals ("utcTime", ttime, len)) {
-               name = g_strconcat (part, ".utcTime", NULL);
-               len = sizeof (ttime) - 1;
-               res = asn1_read_value (asn, name, ttime, &len);
-               g_free (name);
-               if (res != ASN1_SUCCESS)
-                       return FALSE;
-               return parse_utc_time (ttime, len - 1, when, offset);
-       }
-
-       return FALSE;
-}
-
-gboolean
-egg_asn1_read_time (ASN1_TYPE asn, const gchar *part, time_t *val)
-{
-       struct tm when;
-       gint offset;
-
-       g_return_val_if_fail (asn, FALSE);
-       g_return_val_if_fail (part, FALSE);
-       g_return_val_if_fail (val, FALSE);
-
-       if (!read_asn1_time (asn, part, &when, &offset))
-               return FALSE;
-
-       *val = when_to_time (&when, offset);
-       return TRUE;
-}
-
-gboolean
-egg_asn1_read_date (ASN1_TYPE asn, const gchar *part, GDate *date)
-{
-       struct tm when;
-       gint offset;
-
-       g_return_val_if_fail (asn, FALSE);
-       g_return_val_if_fail (part, FALSE);
-       g_return_val_if_fail (date, FALSE);
-
-       if (!read_asn1_time (asn, part, &when, &offset))
-               return FALSE;
-
-       g_date_set_dmy (date, when.tm_mday, when.tm_mon + 1, when.tm_year + 1900);
-       return g_date_valid (date);
-}
diff --git a/egg/egg-asn1.h b/egg/egg-asn1.h
deleted file mode 100644 (file)
index b4c85d5..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* egg-asn1.h - ASN.1 helper routines
-
-   Copyright (C) 2007 Stefan Walter
-
-   The Gnome Keyring Library is free software; you can redistribute it and/or
-   modify it under the terms of the GNU Library General Public License as
-   published by the Free Software Foundation; either version 2 of the
-   License, or (at your option) any later version.
-
-   The Gnome Keyring Library is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-   Library General Public License for more details.
-
-   You should have received a copy of the GNU Library General Public
-   License along with the Gnome Library; see the file COPYING.LIB.  If not,
-   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.
-
-   Author: Stef Walter <stef@memberwebs.com>
-*/
-
-#ifndef EGG_ASN1_H_
-#define EGG_ASN1_H_
-
-#include <glib.h>
-
-#include <libtasn1.h>
-
-#ifndef HAVE_EGG_ALLOCATOR
-typedef void* (*EggAllocator) (void* p, gsize);
-#define HAVE_EGG_ALLOCATOR
-#endif
-
-ASN1_TYPE          egg_asn1_get_pk_asn1type               (void);
-
-ASN1_TYPE          egg_asn1_get_pkix_asn1type             (void);
-
-ASN1_TYPE          egg_asn1_decode                        (const gchar *type, const guchar *data,
-                                                           gsize n_data);
-
-guchar*            egg_asn1_encode                        (ASN1_TYPE asn, const gchar* part,
-                                                           gsize *len, EggAllocator alloc);
-
-guchar*            egg_asn1_read_value                    (ASN1_TYPE asn, const gchar *part,
-                                                           gsize *len, EggAllocator alloc);
-
-gboolean           egg_asn1_write_value                   (ASN1_TYPE asn, const gchar *part,
-                                                           const guchar* value, gsize len);
-
-GQuark             egg_asn1_read_oid                      (ASN1_TYPE asn, const gchar *part);
-
-gboolean           egg_asn1_write_oid                     (ASN1_TYPE asn, const gchar *part, GQuark val);
-
-gboolean           egg_asn1_read_boolean                  (ASN1_TYPE asn, const gchar *part, gboolean *val);
-
-gboolean           egg_asn1_read_uint                     (ASN1_TYPE asn, const gchar *part, guint *val);
-
-gboolean           egg_asn1_read_time                     (ASN1_TYPE asn, const gchar *part, time_t *val);
-
-gboolean           egg_asn1_read_date                     (ASN1_TYPE asn, const gchar *part, GDate *date);
-
-const guchar*      egg_asn1_read_content                  (ASN1_TYPE asn, const guchar *data, gsize n_data,
-                                                           const gchar *part, gsize *n_content);
-
-const guchar*      egg_asn1_read_element                  (ASN1_TYPE asn, const guchar *data, gsize n_data,
-                                                           const gchar *part, gsize *n_element);
-
-gboolean           egg_asn1_write_uint                    (ASN1_TYPE asn, const gchar *part, guint val);
-
-gint               egg_asn1_element_length                (const guchar *data, gsize n_data);
-
-const guchar*      egg_asn1_element_content               (const guchar *data, gsize n_data, gsize *n_content);
-
-glong              egg_asn1_time_parse_utc                (const gchar* value, gssize n_value);
-
-glong              egg_asn1_time_parse_general            (const gchar* value, gssize n_value);
-
-#endif /*EGG_ASN1_H_*/
index 1c71e8f..3a46ddf 100644 (file)
@@ -86,11 +86,11 @@ typedef struct _Aenc Aenc;
 typedef struct _Atlv Atlv;
 typedef struct _Anode Anode;
 typedef struct _Abuf Abuf;
+typedef struct _Abits Abits;
 
 struct _Aenc {
        EggAsn1xEncoder encoder;
-       gpointer user_data;
-       GDestroyNotify destroy;
+       gpointer data;
 };
 
 struct _Atlv {
@@ -109,6 +109,8 @@ struct _Anode {
        GList *opts;
        Atlv *tlv;
        Aenc *enc;
+       gpointer user_data;
+       GDestroyNotify destroy;
        gchar* failure;
 };
 
@@ -118,6 +120,12 @@ struct _Abuf {
        gpointer user_data;
 };
 
+struct _Abits {
+       guint n_bits;
+       guchar *bits;
+       GDestroyNotify destroy;
+};
+
 /* Forward Declarations */
 static gboolean anode_decode_anything (GNode*, Atlv*);
 static gboolean anode_decode_anything_for_flags (GNode *, Atlv*, gint);
@@ -229,7 +237,7 @@ anode_def_value (GNode *node)
 }
 
 static gulong
-anode_def_value_as_ulong (ASN1_ARRAY_TYPE *def)
+anode_def_value_as_ulong (const ASN1_ARRAY_TYPE *def)
 {
        gchar *end = NULL;
        gulong lval;
@@ -342,23 +350,31 @@ anode_clr_enc_data (GNode *node)
 {
        Anode *an = node->data;
        if (an->enc) {
-               if (an->enc->destroy)
-                       (an->enc->destroy) (an->enc->user_data);
                g_slice_free (Aenc, an->enc);
                an->enc = NULL;
        }
 }
 
 static void
-anode_set_enc_data (GNode *node, EggAsn1xEncoder encoder,
-                    gpointer user_data, GDestroyNotify destroy)
+anode_set_enc_data (GNode *node, EggAsn1xEncoder encoder, gpointer enc_data)
 {
        Anode *an = node->data;
        g_assert (!an->enc);
        an->enc = g_slice_new0 (Aenc);
        an->enc->encoder = encoder;
-       an->enc->user_data = user_data;
-       an->enc->destroy = destroy;
+       an->enc->data = enc_data;
+}
+
+static void
+anode_set_user_data (GNode *node, gpointer user_data, GDestroyNotify destroy)
+{
+       Anode *an;
+       g_assert (node && node->data);
+       an = node->data;
+       if (an->destroy)
+               (an->destroy) (an->user_data);
+       an->user_data = user_data;
+       an->destroy = destroy;
 }
 
 static Aenc*
@@ -384,7 +400,7 @@ anode_failure (GNode *node, const gchar *failure)
 
        g_free (an->failure);
        an->failure = g_strdup_printf ("%s: %s", prefix, failure);
-       return FALSE; /* So this can be changed */
+       return FALSE; /* So this can be chained */
 }
 
 static const gchar*
@@ -400,6 +416,7 @@ anode_clear (GNode *node)
        Anode *an = node->data;
        anode_clr_tlv_data (node);
        anode_clr_enc_data (node);
+       anode_set_user_data (node, NULL, NULL);
        g_free (an->failure);
        an->failure = NULL;
 }
@@ -415,6 +432,16 @@ anode_free_func (GNode *node, gpointer unused)
 }
 
 static void
+abits_destroy (gpointer data)
+{
+       Abits *ab = data;
+       g_assert (ab);
+       if (ab->destroy)
+               (ab->destroy) (ab->bits);
+       g_slice_free (Abits, ab);
+}
+
+static void
 anode_destroy (GNode *node)
 {
        if (!G_NODE_IS_ROOT (node))
@@ -494,6 +521,25 @@ anode_calc_tag (GNode *node)
        return anode_calc_tag_for_flags (node, anode_def_flags (node));
 }
 
+static gboolean
+anode_calc_explicit_for_flags (GNode *node, gint flags)
+{
+       const ASN1_ARRAY_TYPE *opt;
+       if ((flags & FLAG_TAG) != FLAG_TAG)
+               return FALSE;
+       opt = anode_opt_lookup (node, TYPE_TAG, NULL);
+       g_return_val_if_fail (opt, FALSE);
+       if ((opt->type & FLAG_IMPLICIT) == FLAG_IMPLICIT)
+               return FALSE;
+       return TRUE;
+}
+
+static gboolean
+anode_calc_explicit (GNode *node)
+{
+       return anode_calc_explicit_for_flags (node, anode_def_flags (node));
+}
+
 /* -------------------------------------------------------------------------
  * DECODE
  */
@@ -801,7 +847,7 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
        end = tlv->end;
 
        /* An explicit, wrapped tag */
-       if (flags & FLAG_TAG && !(flags & FLAG_IMPLICIT)) {
+       if (anode_calc_explicit_for_flags (node, flags)) {
                if ((tlv->cls & ASN1_CLASS_CONTEXT_SPECIFIC) == 0)
                        return anode_failure (node, "missing context specific tag");
                if (!anode_decode_tlv_for_contents (tlv, TRUE, &ctlv))
@@ -820,8 +866,6 @@ anode_decode_structured (GNode *node, Atlv *tlv, gint flags)
 
        /* Other structured types */
        } else {
-               if ((tlv->cls & ASN1_CLASS_CONTEXT_SPECIFIC) != 0)
-                       return anode_failure (node, "invalid context specific tag");
                switch (anode_def_type (node)) {
                case TYPE_ANY:
                        if (!anode_decode_struct_any (node, tlv))
@@ -886,16 +930,8 @@ anode_decode_anything_for_flags (GNode *node, Atlv *tlv, gint flags)
                tag = tlv->tag;
 
        /* Tag does not match, what do we do? */
-       if (tlv->off == 0 || tag != tlv->tag) {
-               if (flags & FLAG_OPTION || flags & FLAG_DEFAULT) {
-                       tlv->len = 0;
-                       tlv->end = tlv->buf;
-                       tlv->off = 0;
-                       return TRUE;
-               } else {
-                       return FALSE;
-               }
-       }
+       if (tlv->off == 0 || tag != tlv->tag)
+               return FALSE;
 
        /* Structured value */
        if (tlv->cls & ASN1_CLASS_STRUCTURED)
@@ -911,7 +947,21 @@ anode_decode_anything_for_flags (GNode *node, Atlv *tlv, gint flags)
 static gboolean
 anode_decode_anything (GNode *node, Atlv *tlv)
 {
-       return anode_decode_anything_for_flags (node, tlv, anode_def_flags (node));
+       gint flags = anode_def_flags (node);
+
+       if (!anode_decode_anything_for_flags (node, tlv, flags)) {
+               if (flags & FLAG_OPTION || flags & FLAG_DEFAULT) {
+                       tlv->len = 0;
+                       tlv->end = tlv->buf;
+                       tlv->off = 0;
+                       anode_clr_tlv_data (node);
+                       return TRUE;
+               }
+
+               return FALSE;
+       }
+
+       return TRUE;
 }
 
 gboolean
@@ -1031,7 +1081,7 @@ anode_encode_tlv_and_enc (GNode *node, gsize n_data, EggAsn1xEncoder encoder,
        /* Build up the class */
        flags = anode_def_flags (node);
        if (flags & FLAG_TAG) {
-               explicit = !(flags & FLAG_IMPLICIT);
+               explicit = anode_calc_explicit_for_flags (node, flags);
                if (explicit)
                        flags &= ~FLAG_TAG;
                else
@@ -1053,11 +1103,12 @@ anode_encode_tlv_and_enc (GNode *node, gsize n_data, EggAsn1xEncoder encoder,
        }
 
        /* Not completely filled in */
-       tlv.buf = tlv.end = 0;
+       tlv.buf = tlv.end = NULL;
 
        anode_clear (node);
        anode_set_tlv_data (node, &tlv);
-       anode_set_enc_data (node, encoder, user_data, destroy);
+       anode_set_enc_data (node, encoder, user_data);
+       anode_set_user_data (node, user_data, destroy);
 }
 
 static gboolean
@@ -1081,7 +1132,7 @@ anode_encode_build (GNode *node, guchar *data, gsize n_data)
 
        /* Encode any explicit tag */
        flags = anode_def_flags (node);
-       if (flags & FLAG_TAG && !(flags & FLAG_IMPLICIT)) {
+       if (anode_calc_explicit_for_flags (node, flags)) {
                tag = anode_calc_tag (node);
                g_return_val_if_fail (tag != G_MAXULONG, FALSE);
                cls = (ASN1_CLASS_STRUCTURED | ASN1_CLASS_CONTEXT_SPECIFIC);
@@ -1100,7 +1151,7 @@ anode_encode_build (GNode *node, guchar *data, gsize n_data)
        tlv->end = data + n_data;
 
        /* Encode in the data */
-       if (!(enc->encoder) (enc->user_data, data + tlv->off, tlv->len))
+       if (!(enc->encoder) (enc->data, data + tlv->off, tlv->len))
                return FALSE;
 
        return TRUE;
@@ -1159,6 +1210,8 @@ traverse_and_sort_set_of (GNode *node, gpointer user_data)
        Atlv *tlv;
        GNode *child;
 
+       g_assert (allocator);
+
        /* We have to sort any SET OF :( */
        if (anode_def_type (node) != TYPE_SET_OF)
                return FALSE;
@@ -1248,7 +1301,7 @@ anode_encoder_choice (gpointer user_data, guchar *data, gsize n_data)
                if (ctlv) {
                        enc = anode_get_enc_data (child);
                        g_return_val_if_fail (enc, FALSE);
-                       if (!(enc->encoder) (enc->user_data, data, n_data))
+                       if (!(enc->encoder) (enc->data, data, n_data))
                                return FALSE;
 
                        /* Child's buffer matches ours */
@@ -1262,19 +1315,49 @@ anode_encoder_choice (gpointer user_data, guchar *data, gsize n_data)
 }
 
 static gboolean
+anode_encoder_bit_string (gpointer user_data, guchar *data, gsize n_data)
+{
+       Abits *ab = user_data;
+       guchar empty, mask;
+       gsize len;
+
+       empty = ab->n_bits % 8;
+       if (empty > 0)
+               empty = 8 - empty;
+       len = (ab->n_bits / 8) + (empty ? 1 : 0);
+       g_assert (n_data == len + 1);
+
+       /* Fill in the amount of empty */
+       data[0] = empty;
+       data += 1;
+
+       /* Fill in the actual data */
+       memcpy (data, ab->bits, len);
+
+       /* Set the extra bits to zero */
+       if (len && empty) {
+               mask = 0xFF >> (8 - empty);
+               data[len - 1] &= ~mask;
+       }
+
+       return TRUE;
+}
+
+static gboolean
 anode_encode_prepare_simple (GNode *node)
 {
        Aenc *enc;
        Atlv *tlv;
 
-       enc = anode_get_enc_data (node);
        tlv = anode_get_tlv_data (node);
-       if (enc != NULL || tlv == NULL)
+       if (tlv == NULL)
                return FALSE;
 
        /* Transfer the tlv data over to enc */
-       anode_set_enc_data (node, anode_encoder_simple,
-                           (guchar*)tlv->buf + tlv->off, NULL);
+       enc = anode_get_enc_data (node);
+       if (enc == NULL)
+               anode_set_enc_data (node, anode_encoder_simple, (guchar*)tlv->buf + tlv->off);
+
        tlv->buf = tlv->end = NULL;
        return TRUE;
 }
@@ -1314,7 +1397,7 @@ anode_encode_prepare_structured (GNode *node)
                        g_return_val_if_fail (tlv, had);
                        anode_clr_tlv_data (node);
                        anode_set_tlv_data (node, tlv);
-                       anode_set_enc_data (node, anode_encoder_choice, node, NULL);
+                       anode_set_enc_data (node, anode_encoder_choice, node);
                }
 
        /* Other container types */
@@ -1366,7 +1449,8 @@ egg_asn1x_encode (GNode *asn, EggAllocator allocator, gsize *n_data)
        if (!allocator)
                allocator = g_realloc;
 
-       anode_encode_prepare (asn);
+       if (!anode_encode_prepare (asn))
+               return NULL;
 
        /* We must sort all the nasty SET OF nodes */
        g_node_traverse (asn, G_POST_ORDER, G_TRAVERSE_ALL, -1,
@@ -1865,7 +1949,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
        val = p[0] - pval * 40;
 
        if (result)
-               g_string_append_printf (result, "%u.%u.", pval, val);
+               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) {
@@ -1884,7 +1968,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
                pval = val;
                if (!(p[k] & 0x80)) {
                        if (result)
-                               g_string_append_printf (result, "%u.", val);
+                               g_string_append_printf (result, ".%u", val);
                        pval = val = 0;
                        lead = 1;
                }
@@ -1904,7 +1988,7 @@ anode_read_object_id (GNode *node, Atlv *tlv, gchar **oid)
 static gboolean
 anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
 {
-       const gchar *p;
+       const gchar *p, *next;
        gint num, num1;
        guchar bit7;
        gboolean had;
@@ -1913,10 +1997,12 @@ anode_write_oid (const gchar *oid, guchar *data, gsize *n_data)
        p = oid;
        at = 0;
 
-       for (i = 0; oid[0]; ++i, oid = p) {
+       for (i = 0; oid[0]; ++i, oid = next) {
                p = strchr (oid, '.');
                if (p == NULL)
-                       p = oid + strlen (oid);
+                       next = p = oid + strlen (oid);
+               else
+                       next = p + 1;
                if (p == oid)
                        return FALSE;
                num = atoin (oid, p - oid);
@@ -1975,7 +2061,18 @@ egg_asn1x_node (GNode *asn, ...)
                        index = va_arg (va, gint);
                        if (index == 0)
                                return node;
-                       node = g_node_nth_child (node, index);
+
+                       /* Only consider nodes that have data */
+                       node = g_node_nth_child (node, 0);
+                       while (node) {
+                               if (egg_asn1x_have (node)) {
+                                       --index;
+                                       if (index == 0)
+                                               break;
+                               }
+                               node = g_node_next_sibling (node);
+                       }
+
                        if (node == NULL)
                                return NULL;
 
@@ -1996,9 +2093,46 @@ egg_asn1x_node (GNode *asn, ...)
        }
 }
 
+const gchar*
+egg_asn1x_name (GNode *node)
+{
+       g_return_val_if_fail (node, NULL);
+       return anode_def_name (node);
+}
+
+guint
+egg_asn1x_count (GNode *node)
+{
+       gint type;
+
+       g_return_val_if_fail (node, 0);
+
+       type = anode_def_type (node);
+       if (type != TYPE_SEQUENCE_OF && type != TYPE_SET_OF) {
+               g_warning ("node passed to egg_asn1x_count was not a sequence of or set of");
+               return 0;
+       }
+
+       return g_node_n_children (node);
+}
+
+gboolean
+egg_asn1x_have (GNode *node)
+{
+       Atlv *tlv;
+
+       g_return_val_if_fail (node, FALSE);
+
+       /* TODO: Handle default values */
+
+       tlv = anode_get_tlv_data (node);
+       return tlv != NULL && tlv->buf != NULL;
+}
+
 gboolean
 egg_asn1x_get_boolean (GNode *node, gboolean *value)
 {
+       ASN1_ARRAY_TYPE *opt;
        Atlv *tlv;
 
        g_return_val_if_fail (node, FALSE);
@@ -2006,8 +2140,24 @@ egg_asn1x_get_boolean (GNode *node, gboolean *value)
        g_return_val_if_fail (anode_def_type (node) == TYPE_BOOLEAN, FALSE);
 
        tlv = anode_get_tlv_data (node);
-       if (tlv == NULL)
-               return FALSE;
+       if (tlv == NULL || tlv->buf == NULL) {
+
+               if ((anode_def_flags (node) & FLAG_DEFAULT) == 0)
+                       return FALSE;
+
+               /* Try to get a default */
+               opt = anode_opt_lookup (node, TYPE_DEFAULT, NULL);
+               g_return_val_if_fail (opt, FALSE);
+
+               /* Parse out the default value */
+               if ((opt->type & FLAG_TRUE) == FLAG_TRUE)
+                       *value = TRUE;
+               else if ((opt->type & FLAG_FALSE) == FLAG_FALSE)
+                       *value = FALSE;
+               else
+                       g_return_val_if_reached (FALSE);
+               return TRUE;
+       }
 
        return anode_read_boolean (node, tlv, value);
 }
@@ -2021,6 +2171,8 @@ egg_asn1x_set_boolean (GNode *node, gboolean value)
        g_return_val_if_fail (node, FALSE);
        g_return_val_if_fail (anode_def_type (node) == TYPE_BOOLEAN, FALSE);
 
+       /* TODO: Handle default values */
+
        n_data = 1;
        data = g_malloc0 (1);
        if (!anode_write_boolean (value, data, &n_data))
@@ -2032,16 +2184,44 @@ egg_asn1x_set_boolean (GNode *node, gboolean value)
 gboolean
 egg_asn1x_get_integer_as_ulong (GNode *node, gulong *value)
 {
+       const ASN1_ARRAY_TYPE *opt;
+       const gchar *defval;
        Atlv *tlv;
+       gchar *end;
 
        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);
-       if (tlv == NULL)
+       if (tlv == NULL || tlv->buf == NULL) {
+
+               if ((anode_def_flags (node) & FLAG_DEFAULT) == 0)
+                       return FALSE;
+
+               /* Try to get a default */
+               opt = anode_opt_lookup (node, TYPE_DEFAULT, NULL);
+               g_return_val_if_fail (opt, FALSE);
+               g_return_val_if_fail (opt->value, FALSE);
+               defval = opt->value;
+
+               opt = anode_opt_lookup (node, TYPE_CONSTANT, defval);
+               if (opt != NULL) {
+                       g_return_val_if_fail (opt->value, FALSE);
+                       defval = opt->value;
+               }
+
+               /* Parse out the default value */
+               *value = strtoul (defval, &end, 10);
+               g_return_val_if_fail (end && !end[0], FALSE);
+               return TRUE;
+       }
+
+       if (tlv == NULL || tlv->buf == NULL)
                return FALSE;
 
+       /* TODO: Default integer values */
+
        return anode_read_integer_as_ulong(node, tlv, value);
 }
 
@@ -2052,7 +2232,9 @@ egg_asn1x_set_integer_as_ulong (GNode *node, gulong value)
        gsize n_data;
 
        g_return_val_if_fail (node, FALSE);
-       g_return_val_if_fail (anode_def_type (node) == TYPE_BOOLEAN, FALSE);
+       g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
+
+       /* TODO: Handle default values */
 
        n_data = 8;
        data = g_malloc0 (8);
@@ -2062,6 +2244,115 @@ egg_asn1x_set_integer_as_ulong (GNode *node, gulong value)
        return TRUE;
 }
 
+gpointer
+egg_asn1x_get_integer_as_raw (GNode *node, EggAllocator allocator, gsize *n_data)
+{
+       Atlv *tlv;
+       gpointer data;
+
+       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (n_data, FALSE);
+       g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
+
+       if (!allocator)
+               allocator = g_realloc;
+
+       tlv = anode_get_tlv_data (node);
+       if (tlv == NULL || tlv->buf == NULL)
+               return NULL;
+
+       data = (allocator) (NULL, tlv->len);
+       if (data == NULL)
+               return NULL;
+
+       memcpy (data, tlv->buf + tlv->off, tlv->len);
+       *n_data = tlv->len;
+       return data;
+}
+
+gboolean
+egg_asn1x_set_integer_as_raw (GNode *node, gpointer data, gsize n_data, GDestroyNotify destroy)
+{
+       gboolean sign;
+       guchar *p;
+
+       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (data, FALSE);
+       g_return_val_if_fail (n_data > 0, FALSE);
+       g_return_val_if_fail (anode_def_type (node) == TYPE_INTEGER, FALSE);
+
+       /* Make sure the integer is properly encoded in twos complement*/
+       p = (guchar*)data;
+       sign = !!(p[0] & 0x80);
+       if (sign) {
+               g_warning ("integer in egg_asn1x_set_integer_as_raw is not two's complement");
+               return FALSE;
+       }
+
+       anode_encode_tlv_and_enc (node, n_data, anode_encoder_simple, data, destroy);
+       return TRUE;
+}
+
+gconstpointer
+egg_asn1x_get_raw_element (GNode *node, gsize *n_element)
+{
+       Atlv *tlv;
+
+       g_return_val_if_fail (node, NULL);
+       g_return_val_if_fail (n_element, NULL);
+
+       tlv = anode_get_tlv_data (node);
+       if (tlv == NULL || tlv->buf == NULL)
+               return NULL;
+
+       if (anode_calc_explicit (node)) {
+               *n_element = (tlv->len + tlv->off) - tlv->oft;
+               return tlv->buf + tlv->oft;
+       } else {
+               *n_element = tlv->len + tlv->off;
+               return tlv->buf;
+       }
+}
+
+gboolean
+egg_asn1x_set_raw_element (GNode *node, gpointer data,
+                           gsize n_data, GDestroyNotify destroy)
+{
+       Atlv tlv;
+
+       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (data, FALSE);
+       g_return_val_if_fail (n_data, FALSE);
+
+       anode_clear (node);
+       memset (&tlv, 0, sizeof (tlv));
+
+       /* TODO: This needs implementation */
+       if (anode_calc_explicit (node)) {
+               g_warning ("egg_asn1x_set_raw_element does not yet work with explicit tagging");
+               return FALSE;
+       }
+
+       /* Decode the beginning TLV */
+       if (!anode_decode_tlv_for_data (data, (const guchar*)data + n_data, &tlv))
+               return FALSE;
+
+       /* Decode the data into place properly */
+       if (!anode_decode_anything (node, &tlv))
+               return FALSE;
+
+       /* There was extra data */
+       if (tlv.end - tlv.buf != n_data)
+               return FALSE;
+
+       /* Should have been set above */
+       g_assert (anode_get_tlv_data (node) != NULL);
+
+       /* We set this so the data is properly destroyed */
+       anode_set_user_data (node, data, destroy);
+       return TRUE;
+}
+
 gconstpointer
 egg_asn1x_get_raw_value (GNode *node, gsize *n_content)
 {
@@ -2071,8 +2362,8 @@ egg_asn1x_get_raw_value (GNode *node, gsize *n_content)
        g_return_val_if_fail (n_content, NULL);
 
        tlv = anode_get_tlv_data (node);
-       if (tlv == NULL)
-               return FALSE;
+       if (tlv == NULL || tlv->buf == NULL)
+               return NULL;
        g_return_val_if_fail (!(tlv->cls & ASN1_CLASS_STRUCTURED), NULL);
 
        *n_content = tlv->len;
@@ -2101,11 +2392,14 @@ egg_asn1x_get_string_as_raw (GNode *node, EggAllocator allocator, gsize *n_strin
        g_return_val_if_fail (node, NULL);
        g_return_val_if_fail (n_string, NULL);
 
+       if (!allocator)
+               allocator = g_realloc;
+
        type = anode_def_type (node);
        g_return_val_if_fail (type == TYPE_OCTET_STRING || type == TYPE_GENERALSTRING, NULL);
 
        tlv = anode_get_tlv_data (node);
-       if (tlv == NULL)
+       if (tlv == NULL || tlv->buf == NULL)
                return NULL;
 
        if (!anode_read_string (node, tlv, NULL, &length))
@@ -2179,17 +2473,160 @@ egg_asn1x_set_string_as_utf8 (GNode *node, gchar *data, GDestroyNotify destroy)
        return egg_asn1x_set_string_as_raw (node, (guchar*)data, n_data, destroy);
 }
 
+guchar*
+egg_asn1x_get_bits_as_raw (GNode *node, EggAllocator allocator, guint *n_bits)
+{
+       Atlv *tlv;
+       gpointer bits;
+       guchar padded;
+
+       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (n_bits, FALSE);
+       g_return_val_if_fail (anode_def_type (node) == TYPE_BIT_STRING, FALSE);
+
+       if (!allocator)
+               allocator = g_realloc;
+
+       tlv = anode_get_tlv_data (node);
+       if (tlv == NULL || tlv->buf == NULL)
+               return NULL;
+
+       padded = *(tlv->buf + tlv->off);
+       g_return_val_if_fail (padded < 8, NULL);
+       g_return_val_if_fail (tlv->len > 1, NULL);
+
+       bits = (allocator) (NULL, tlv->len);
+       if (bits == NULL)
+               return NULL;
+
+       memcpy (bits, tlv->buf + tlv->off + 1, tlv->len - 1);
+       *n_bits = ((tlv->len - 1) * 8) - padded;
+       return bits;
+}
+
+gboolean
+egg_asn1x_set_bits_as_raw (GNode *node, guchar *bits, guint n_bits, GDestroyNotify destroy)
+{
+       gint type;
+       gsize length;
+       Abits *ab;
+
+       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (bits, FALSE);
+
+       type = anode_def_type (node);
+       g_return_val_if_fail (type == TYPE_BIT_STRING, FALSE);
+
+       length = (n_bits / 8);
+       if (n_bits % 8)
+               length += 1;
+
+       ab = g_slice_new0 (Abits);
+       ab->bits = bits;
+       ab->n_bits = n_bits;
+       ab->destroy = destroy;
+
+       anode_encode_tlv_and_enc (node, length + 1, anode_encoder_bit_string, ab, abits_destroy);
+       return TRUE;
+}
+
+gboolean
+egg_asn1x_get_bits_as_ulong (GNode *node, gulong *bits, guint *n_bits)
+{
+       Atlv *tlv;
+       guint i, length;
+       guchar empty;
+       const guchar *p;
+       gulong value;
+
+       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (bits, FALSE);
+       g_return_val_if_fail (n_bits, FALSE);
+       g_return_val_if_fail (anode_def_type (node) == TYPE_BIT_STRING, FALSE);
+
+       tlv = anode_get_tlv_data (node);
+       if (tlv == NULL || tlv->buf == NULL)
+               return FALSE;
+
+       empty = *(tlv->buf + tlv->off);
+       g_return_val_if_fail (empty < 8, FALSE);
+       g_return_val_if_fail (tlv->len > 1, FALSE);
+
+       length = ((tlv->len - 1) * 8) - empty;
+       if (length > sizeof (gulong) * 8)
+               return FALSE;
+
+       value = 0;
+       p = tlv->buf + tlv->off + 1;
+
+       for (i = 0; i < tlv->len - 1; ++i)
+               value = value << 8 | p[i];
+
+       *bits = value >> empty;
+       *n_bits = length;
+       return TRUE;
+}
+
+gboolean
+egg_asn1x_set_bits_as_ulong (GNode *node, gulong bits, guint n_bits)
+{
+       guchar *data;
+       gulong value;
+       gint type;
+       gsize i, length;
+       guchar empty;
+       Abits *ab;
+
+       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (bits, FALSE);
+       g_return_val_if_fail (n_bits <= sizeof (gulong) * 8, FALSE);
+
+       type = anode_def_type (node);
+       g_return_val_if_fail (type == TYPE_BIT_STRING, FALSE);
+
+       empty = n_bits % 8;
+       if (empty > 0)
+               empty = 8 - empty;
+       length = (n_bits / 8) + (empty ? 1 : 0);
+
+       data = g_malloc0 (sizeof (gulong));
+       value = bits << empty;
+
+       for (i = 0; i < length; ++i)
+               data[(length - i) - 1] = (value >> i * 8) & 0xFF;
+
+       ab = g_slice_new0 (Abits);
+       ab->bits = data;
+       ab->n_bits = n_bits;
+       ab->destroy = g_free;
+
+       anode_encode_tlv_and_enc (node, length + 1, anode_encoder_bit_string, ab, abits_destroy);
+       return TRUE;
+}
+
 glong
 egg_asn1x_get_time_as_long (GNode *node)
 {
        Atlv *tlv;
        glong time;
+       gint type;
 
        g_return_val_if_fail (node, -1);
-       g_return_val_if_fail (anode_def_type (node) == TYPE_TIME, -1);
+       type = anode_def_type (node);
+
+       /* Time is often represented as a choice, so work than in here */
+       if (type == TYPE_CHOICE) {
+               node = egg_asn1x_get_choice (node);
+               if (node == NULL)
+                       return -1;
+               g_return_val_if_fail (anode_def_type (node) == TYPE_TIME, -1);
+               return egg_asn1x_get_time_as_long (node);
+       }
+
+       g_return_val_if_fail (type == TYPE_TIME, -1);
 
        tlv = anode_get_tlv_data (node);
-       if (tlv == NULL)
+       if (tlv == NULL || tlv->buf == NULL)
                return -1;
 
        if (!anode_read_time (node, tlv, &time))
@@ -2197,6 +2634,23 @@ egg_asn1x_get_time_as_long (GNode *node)
        return time;
 }
 
+gboolean
+egg_asn1x_get_time_as_date (GNode *node, GDate *date)
+{
+       GTimeVal tv;
+
+       g_return_val_if_fail (node, FALSE);
+       g_return_val_if_fail (date, FALSE);
+
+       tv.tv_sec = egg_asn1x_get_time_as_long (node);
+       if (tv.tv_sec < 0)
+               return FALSE;
+       tv.tv_usec = 0;
+
+       g_date_set_time_val (date, &tv);
+       return TRUE;
+}
+
 gchar*
 egg_asn1x_get_oid_as_string (GNode *node)
 {
@@ -2207,7 +2661,7 @@ egg_asn1x_get_oid_as_string (GNode *node)
        g_return_val_if_fail (anode_def_type (node) == TYPE_OBJECT_ID, NULL);
 
        tlv = anode_get_tlv_data (node);
-       if (tlv == NULL)
+       if (tlv == NULL || tlv->buf == NULL)
                return NULL;
 
        if (!anode_read_object_id (node, tlv, &oid))
@@ -2265,6 +2719,22 @@ egg_asn1x_set_oid_as_quark (GNode *node, GQuark oid)
        return egg_asn1x_set_oid_as_string (node, str);
 }
 
+GNode*
+egg_asn1x_get_choice (GNode *node)
+{
+       GNode *child;
+
+       g_return_val_if_fail (node, NULL);
+
+       /* One and only one of the children must be set */
+       for (child = node->children; child; child = child->next) {
+               if (anode_get_tlv_data (child))
+                       return child;
+       }
+
+       return NULL;
+}
+
 /* -----------------------------------------------------------------------------------
  * VALIDATION
  */
@@ -2302,9 +2772,6 @@ anode_validate_size (GNode *node, gulong length)
 
        if (anode_def_flags (node) & FLAG_SIZE) {
                size = anode_opt_lookup (node, TYPE_SIZE, NULL);
-               if (size == NULL) {
-                       egg_asn1x_dump (g_node_get_root (node));
-               }
                g_return_val_if_fail (size, FALSE);
                if (!anode_parse_size (node, size->value, &value1))
                        g_return_val_if_reached (FALSE);
@@ -2396,7 +2863,7 @@ anode_validate_bit_string (GNode *node, Atlv *tlv)
        g_assert (tlv);
 
        /* At least two bytes in length */
-       if (tlv->len < 2)
+       if (tlv->len < 1)
                return anode_failure (node, "invalid length bit string");
        /* First byte is the number of free bits at end */
        empty = tlv->buf[tlv->off];
@@ -2404,7 +2871,7 @@ anode_validate_bit_string (GNode *node, Atlv *tlv)
                return anode_failure (node, "bit string has invalid header");
        /* Free bits at end must be zero */
        mask = 0xFF >> (8 - empty);
-       if (tlv->buf[tlv->off + tlv->len - 1] & mask)
+       if (tlv->len > 1 && tlv->buf[tlv->off + tlv->len - 1] & mask)
                return anode_failure (node, "bit string has invalid trailing bits");
        return TRUE;
 }
@@ -2507,11 +2974,11 @@ anode_validate_sequence_or_set_of (GNode *node)
 
        /* All the children must validate properly */
        for (child = node->children; child; child = child->next) {
-               if (!anode_validate_anything (child))
-                       return FALSE;
-
                tlv = anode_get_tlv_data (child);
                if (tlv) {
+                       if (!anode_validate_anything (child))
+                               return FALSE;
+
                        /* Tag must have same tag as top */
                        if (count == 0)
                                tag = anode_calc_tag (child);
@@ -2541,6 +3008,8 @@ anode_validate_anything (GNode *node)
        if (!tlv) {
                if (anode_def_flags (node) & FLAG_OPTION)
                        return TRUE;
+               if (anode_def_flags (node) & FLAG_DEFAULT)
+                       return TRUE;
                return anode_failure (node, "missing value");
        }
 
@@ -2629,14 +3098,58 @@ join_each_child (GNode *child, gpointer data)
 }
 
 static const ASN1_ARRAY_TYPE*
-lookup_def (const ASN1_ARRAY_TYPE *defs, const gchar *identifier, gint type)
+adef_next_sibling (const ASN1_ARRAY_TYPE *def)
+{
+       int depth = 0;
+
+       g_assert (def);
+       g_assert (def->value || def->type || def->name);
+
+       if ((def->type & FLAG_RIGHT) == 0)
+               return NULL;
+
+       /* Skip past any children */
+       if ((def->type & FLAG_DOWN) == FLAG_DOWN) {
+               depth += 1;
+               while (depth > 0) {
+                       ++def;
+                       if ((def->type & FLAG_DOWN) == FLAG_DOWN)
+                               depth += 1;
+                       if ((def->type & FLAG_RIGHT) == 0)
+                               depth -= 1;
+               }
+       }
+
+       ++def;
+       g_return_val_if_fail (def->value || def->type || def->name, NULL);
+       return def;
+}
+
+static const ASN1_ARRAY_TYPE*
+adef_first_child (const ASN1_ARRAY_TYPE *def)
 {
-       /* Find the one we're interested in */
-       while (defs && (defs->value || defs->type || defs->name)) {
-               if ((defs->type & 0xFF) == type &&
-                   defs->name && g_str_equal (identifier, defs->name))
-                       return defs;
-               ++defs;
+       g_assert (def);
+       g_assert (def->value || def->type || def->name);
+
+       if ((def->type & FLAG_DOWN) == 0)
+               return NULL;
+
+       ++def;
+       g_return_val_if_fail (def->value || def->type || def->name, NULL);
+       return def;
+}
+
+static const ASN1_ARRAY_TYPE*
+lookup_def_of_type (const ASN1_ARRAY_TYPE *defs, const gchar *name, gint type)
+{
+       const ASN1_ARRAY_TYPE *def;
+
+       g_assert (defs);
+       g_assert (defs->value || defs->type || defs->name);
+
+       for (def = adef_first_child (defs); def; def = adef_next_sibling (def)) {
+               if ((def->type & 0xFF) == type && def->name && g_str_equal (name, def->name))
+                       return def;
        }
 
        return NULL;
@@ -2673,7 +3186,7 @@ traverse_and_prepare (GNode *node, gpointer data)
                identifier = anode_def_name (node);
                if (identifier && !g_str_equal (identifier, "MAX") &&
                    g_ascii_isalpha (identifier[0])) {
-                       def = lookup_def (defs, identifier, TYPE_INTEGER);
+                       def = lookup_def_of_type (defs, identifier, TYPE_INTEGER);
                        g_return_val_if_fail (def, TRUE);
                        anode_opt_add (node, def);
                }
@@ -2719,26 +3232,123 @@ traverse_and_prepare (GNode *node, gpointer data)
        return FALSE;
 }
 
+static const ASN1_ARRAY_TYPE*
+match_oid_in_definition (const ASN1_ARRAY_TYPE *def, GHashTable *names,
+                          const gchar *match, const gchar **problem)
+{
+       const ASN1_ARRAY_TYPE *result = NULL;
+       const ASN1_ARRAY_TYPE *odef;
+       const gchar *value;
+       GString *oid = NULL;
+
+       g_assert (match);
+       g_assert (problem);
+       g_assert (names);
+
+       for (odef = adef_first_child (def); odef; odef = adef_next_sibling (odef)) {
+               if ((odef->type & 0xFF) != TYPE_CONSTANT)
+                       continue;
+
+               g_return_val_if_fail (odef->value, NULL);
+               if (strspn (odef->value, "01234567890") == strlen (odef->value)) {
+                       value = odef->value;
+
+               } else {
+                       value = g_hash_table_lookup (names, odef->value);
+
+                       /* A name resolution problem */
+                       if (!value) {
+                               if (oid)
+                                       g_string_free (oid, TRUE);
+                               *problem = odef->value;
+                               return NULL;
+                       }
+               }
+
+               if (oid) {
+                       g_string_append_c (oid, '.');
+                       g_string_append (oid, value);
+               } else {
+                       oid = g_string_new (value);
+               }
+       }
+
+       if (oid != NULL) {
+               if (g_str_equal (oid->str, match))
+                       result = adef_next_sibling (def);
+               g_assert (def->name);
+               g_hash_table_insert (names, (gchar*)def->name, g_string_free (oid, FALSE));
+       }
+
+       return result;
+}
+
+static const ASN1_ARRAY_TYPE*
+match_oid_in_definitions (const ASN1_ARRAY_TYPE *defs, const gchar *match)
+{
+       const ASN1_ARRAY_TYPE *def;
+       const ASN1_ARRAY_TYPE *result;
+       GHashTable *names;
+       gboolean progress;
+       const gchar *problem;
+
+       names = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+       for (;;) {
+               progress = FALSE;
+               problem = NULL;
+
+               for (def = adef_first_child (defs); def; def = adef_next_sibling (def)) {
+
+                       /* Only work with object ids, and ones with names */
+                       if ((def->type & 0xFF) != TYPE_OBJECT_ID || !def->name)
+                               continue;
+
+                       /* If we've already seen this one, skip */
+                       if (g_hash_table_lookup (names, def->name))
+                               continue;
+
+                       progress = TRUE;
+                       result = match_oid_in_definition (def, names, match, &problem);
+                       if (result != NULL)
+                               break;
+               }
+
+               if (!problem || result) {
+                       break;
+               } else if (problem && !progress) {
+                       g_warning ("couldn't find oid definition in ASN.1 for: %s", problem);
+                       g_return_val_if_reached (NULL);
+               }
+       }
+
+       g_hash_table_destroy (names);
+       return result;
+}
+
 GNode*
-egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *identifier)
+egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *type)
 {
        const ASN1_ARRAY_TYPE *def;
        GNode *root, *parent, *node;
        int flags;
 
        g_return_val_if_fail (defs, NULL);
-       g_return_val_if_fail (identifier, NULL);
+       g_return_val_if_fail (type, NULL);
 
-       def = defs;
+       /* An OID */
+       if (strspn (type, "0123456789.") == strlen (type)) {
+               def = match_oid_in_definitions (defs, type);
 
-       /* Find the one we're interested in */
-       while (def && (def->value || def->type || def->name)) {
-               if (def->name && g_str_equal (identifier, def->name))
-                       break;
-               ++def;
+       /* An Identifier */
+       } else {
+               for (def = adef_first_child (defs); def; def = adef_next_sibling (def)) {
+                       if (def->name && g_str_equal (type, def->name))
+                               break;
+               }
        }
 
-       if (!def->name || !def->type)
+       if (def == NULL || !def->name || !def->type)
                return NULL;
 
        /* The node for this item */
@@ -2779,6 +3389,33 @@ egg_asn1x_create (const ASN1_ARRAY_TYPE *defs, const gchar *identifier)
        return root;
 }
 
+GNode*
+egg_asn1x_create_quark (const ASN1_ARRAY_TYPE *defs, GQuark type)
+{
+       g_return_val_if_fail (type, NULL);
+       return egg_asn1x_create (defs, g_quark_to_string (type));
+}
+
+GNode*
+egg_asn1x_create_and_decode (const ASN1_ARRAY_TYPE *defs, const gchar *identifier,
+                             gconstpointer data, gsize n_data)
+{
+       GNode *asn;
+
+       g_return_val_if_fail (defs, NULL);
+       g_return_val_if_fail (identifier, NULL);
+
+       asn = egg_asn1x_create (defs, identifier);
+       g_return_val_if_fail (asn, NULL);
+
+       if (!egg_asn1x_decode (asn, data, n_data)) {
+               egg_asn1x_destroy (asn);
+               return NULL;
+       }
+
+       return asn;
+}
+
 /* -----------------------------------------------------------------------------------
  * DUMPING and MESSAGES
  */
@@ -2814,6 +3451,7 @@ traverse_and_dump (GNode *node, gpointer unused)
        guint i, depth;
        GString *output;
        gchar *string;
+       Atlv *tlv;
        Anode *an;
        GList *l;
 
@@ -2821,12 +3459,14 @@ traverse_and_dump (GNode *node, gpointer unused)
        for (i = 0; i < depth - 1; ++i)
                g_printerr ("    ");
 
+       tlv = anode_get_tlv_data (node);
        output = g_string_new ("");
        dump_append_type (output, anode_def_type (node));
        dump_append_flags (output, anode_def_flags (node));
        string = g_utf8_casefold (output->str, output->len - 1);
        g_string_free (output, TRUE);
-       g_printerr ("+ %s: %s [%s]\n", anode_def_name (node), anode_def_value (node), string);
+       g_printerr ("+ %s: %s [%s]%s\n", anode_def_name (node), anode_def_value (node),
+                   string, tlv && tlv->buf ? " *" : "");
        g_free (string);
 
        /* Print out all the options */
@@ -2915,6 +3555,127 @@ egg_asn1x_clear (GNode *asn)
 void
 egg_asn1x_destroy (gpointer data)
 {
-       if (data)
-               anode_destroy (data);
+       GNode *node = data;
+
+       if (node != NULL) {
+               g_return_if_fail (G_NODE_IS_ROOT (node));
+               anode_destroy (node);
+       }
+}
+
+/* --------------------------------------------------------------------------------
+ * TIME PARSING
+ */
+
+glong
+egg_asn1x_parse_time_general (const gchar *time, gssize n_time)
+{
+       gboolean ret;
+       glong value;
+       struct tm when;
+       gint offset = 0;
+
+       g_return_val_if_fail (time, -1);
+
+       if (n_time < 0)
+               n_time = strlen (time);
+
+       ret = parse_general_time (time, n_time, &when, &offset);
+       if (!ret)
+               return -1;
+
+       /* In order to work with 32 bit time_t. */
+       if (sizeof (time_t) <= 4 && when.tm_year >= 2038) {
+               value = (time_t)2145914603;  /* 2037-12-31 23:23:23 */
+
+       /* Convert to seconds since epoch */
+       } else {
+               value = timegm (&when);
+               g_return_val_if_fail (*time >= 0, FALSE);
+               value += offset;
+       }
+
+       return value;
+}
+
+glong
+egg_asn1x_parse_time_utc (const gchar *time, gssize n_time)
+{
+       gboolean ret;
+       glong value;
+       struct tm when;
+       gint offset = 0;
+
+       g_return_val_if_fail (time, -1);
+
+       if (n_time < 0)
+               n_time = strlen (time);
+
+       ret = parse_utc_time (time, n_time, &when, &offset);
+       if (!ret)
+               return -1;
+
+       /* In order to work with 32 bit time_t. */
+       if (sizeof (time_t) <= 4 && when.tm_year >= 2038) {
+               value = (time_t)2145914603;  /* 2037-12-31 23:23:23 */
+
+       /* Convert to seconds since epoch */
+       } else {
+               value = timegm (&when);
+               g_return_val_if_fail (*time >= 0, FALSE);
+               value += offset;
+       }
+
+       return value;
+}
+
+/* --------------------------------------------------------------------------------
+ * BASIC RAW ELEMENT INFO
+ */
+
+gssize
+egg_asn1x_element_length (gconstpointer data, gsize n_data)
+{
+       guchar cls;
+       int counter = 0;
+       int cb, len;
+       gulong tag;
+
+       if (asn1_get_tag_der (data, n_data, &cls, &cb, &tag) == ASN1_SUCCESS) {
+               counter += cb;
+               len = asn1_get_length_der ((const guchar*)data + cb, n_data - cb, &cb);
+               counter += cb;
+               if (len >= 0) {
+                       len += counter;
+                       if (n_data >= len)
+                               return len;
+               }
+       }
+
+       return -1;
+}
+
+gconstpointer
+egg_asn1x_element_content (gconstpointer data, gsize n_data, gsize *n_content)
+{
+       int counter = 0;
+       guchar cls;
+       gulong tag;
+       int cb, len;
+
+       g_return_val_if_fail (data != NULL, NULL);
+       g_return_val_if_fail (n_content != NULL, NULL);
+
+       /* Now get the data out of this element */
+       if (asn1_get_tag_der (data, n_data, &cls, &cb, &tag) != ASN1_SUCCESS)
+               return NULL;
+
+       counter += cb;
+       len = asn1_get_length_der ((const guchar*)data + cb, n_data - cb, &cb);
+       if (len < 0)
+               return NULL;
+       counter += cb;
+
+       *n_content = len;
+       return (const guchar*)data + counter;
 }
index 6d69b0a..705e226 100644 (file)
@@ -26,9 +26,6 @@
 
 #include <glib.h>
 
-#include <libtasn1.h>
-
-
 #ifndef HAVE_EGG_ALLOCATOR
 typedef void* (*EggAllocator) (void* p, gsize);
 #define HAVE_EGG_ALLOCATOR
@@ -36,9 +33,19 @@ typedef void* (*EggAllocator) (void* p, gsize);
 
 typedef gboolean (*EggAsn1xEncoder) (gpointer data, guchar *buf, gsize n_buf);
 
-GNode*              egg_asn1x_create                 (const ASN1_ARRAY_TYPE *defs,
+struct static_struct_asn;
+
+GNode*              egg_asn1x_create                 (const struct static_struct_asn *defs,
                                                       const gchar *type);
 
+GNode*              egg_asn1x_create_quark           (const struct static_struct_asn *defs,
+                                                      GQuark type);
+
+GNode*              egg_asn1x_create_and_decode      (const struct static_struct_asn *defs,
+                                                      const gchar *type,
+                                                      gconstpointer data,
+                                                      gsize n_data);
+
 void                egg_asn1x_dump                   (GNode *asn);
 
 void                egg_asn1x_clear                  (GNode *asn);
@@ -58,6 +65,14 @@ const gchar*        egg_asn1x_message                (GNode *asn);
 GNode*              egg_asn1x_node                   (GNode *asn,
                                                       ...) G_GNUC_NULL_TERMINATED;
 
+const gchar*        egg_asn1x_name                   (GNode *asn);
+
+guint               egg_asn1x_count                  (GNode *node);
+
+gboolean            egg_asn1x_have                   (GNode *node);
+
+GNode*              egg_asn1x_get_choice             (GNode *node);
+
 gboolean            egg_asn1x_get_boolean            (GNode *node,
                                                       gboolean *value);
 
@@ -70,6 +85,15 @@ gboolean            egg_asn1x_get_integer_as_ulong   (GNode *node,
 gboolean            egg_asn1x_set_integer_as_ulong   (GNode *node,
                                                       gulong value);
 
+gpointer            egg_asn1x_get_integer_as_raw     (GNode *node,
+                                                      EggAllocator allocator,
+                                                      gsize *n_data);
+
+gboolean            egg_asn1x_set_integer_as_raw     (GNode *node,
+                                                      gpointer data,
+                                                      gsize n_data,
+                                                      GDestroyNotify destroy);
+
 gconstpointer       egg_asn1x_get_raw_value          (GNode *node,
                                                       gsize *n_content);
 
@@ -79,6 +103,14 @@ gboolean            egg_asn1x_set_raw_value          (GNode *node,
                                                       gpointer user_data,
                                                       GDestroyNotify destroy);
 
+gconstpointer       egg_asn1x_get_raw_element        (GNode *node,
+                                                      gsize *n_data);
+
+gboolean            egg_asn1x_set_raw_element        (GNode *node,
+                                                      gpointer user_data,
+                                                      gsize n_data,
+                                                      GDestroyNotify destroy);
+
 guchar*             egg_asn1x_get_string_as_raw      (GNode *node,
                                                       EggAllocator allocator,
                                                       gsize *n_string);
@@ -88,6 +120,23 @@ gboolean            egg_asn1x_set_string_as_raw      (GNode *node,
                                                       gsize n_data,
                                                       GDestroyNotify destroy);
 
+guchar*             egg_asn1x_get_bits_as_raw        (GNode *node,
+                                                      EggAllocator allocator,
+                                                      guint *n_bits);
+
+gboolean            egg_asn1x_set_bits_as_raw        (GNode *node,
+                                                      guchar *data,
+                                                      guint n_bits,
+                                                      GDestroyNotify destroy);
+
+gboolean            egg_asn1x_get_bits_as_ulong      (GNode *node,
+                                                      gulong *value,
+                                                      guint *n_bits);
+
+gboolean            egg_asn1x_set_bits_as_ulong      (GNode *node,
+                                                      gulong value,
+                                                      guint n_bits);
+
 gchar*              egg_asn1x_get_string_as_utf8     (GNode *node,
                                                       EggAllocator allocator);
 
@@ -97,7 +146,14 @@ gboolean            egg_asn1x_set_string_as_utf8     (GNode *node,
 
 glong               egg_asn1x_get_time_as_long       (GNode *node);
 
-glong               egg_asn1x_set_time_as_long       (GNode *node);
+gboolean            egg_asn1x_set_time_as_long       (GNode *node,
+                                                      glong time);
+
+gboolean            egg_asn1x_get_time_as_date       (GNode *node,
+                                                      GDate *date);
+
+gboolean            egg_asn1x_set_time_as_date       (GNode *node,
+                                                      GDate *date);
 
 GQuark              egg_asn1x_get_oid_as_quark       (GNode *node);
 
@@ -111,4 +167,17 @@ gboolean            egg_asn1x_set_oid_as_string      (GNode *node,
 
 void                egg_asn1x_destroy                (gpointer asn);
 
+glong               egg_asn1x_parse_time_general     (const gchar *time,
+                                                      gssize n_time);
+
+glong               egg_asn1x_parse_time_utc         (const gchar *time,
+                                                      gssize n_time);
+
+gssize              egg_asn1x_element_length         (gconstpointer data,
+                                                      gsize n_data);
+
+gconstpointer       egg_asn1x_element_content        (gconstpointer data,
+                                                      gsize n_data,
+                                                      gsize *n_content);
+
 #endif /*EGG_ASN1X_H_*/
index 199cb6a..b41844e 100644 (file)
 
 #include "config.h"
 
-#include "egg-asn1.h"
+#include "egg-asn1-defs.h"
+#include "egg-asn1x.h"
 #include "egg-dn.h"
 #include "egg-oid.h"
 
-#include <libtasn1.h>
-
 #include <string.h>
 
 static const char HEXC[] = "0123456789ABCDEF";
 
-static gboolean
-ascii_length_equals (const gchar *str, gconstpointer data, gsize n_data)
-{
-       g_assert (str);
-       if (!data)
-               return FALSE;
-       if (strlen (str) != n_data)
-               return FALSE;
-       return strncmp (str, data, n_data) == 0;
-}
-
 static gchar*
 dn_print_hex_value (const guchar *data, gsize len)
 {
@@ -62,63 +50,53 @@ dn_print_hex_value (const guchar *data, gsize len)
 static gchar*
 dn_print_oid_value_parsed (GQuark oid, guint flags, const guchar *data, gsize len)
 {
-       const gchar *asn_name;
-       ASN1_TYPE asn1;
-       gchar *part;
-       gchar *value;
+       GNode *asn1, *node;
+       gconstpointer value;
        gsize n_value;
+       gchar *result;
 
        g_assert (data);
        g_assert (len);
 
-       asn_name = asn1_find_structure_from_oid (egg_asn1_get_pkix_asn1type (),
-                                                g_quark_to_string (oid));
-       g_return_val_if_fail (asn_name, NULL);
-
-       part = g_strdup_printf ("PKIX1.%s", asn_name);
-       asn1 = egg_asn1_decode (part, data, len);
-       g_free (part);
+       asn1 = egg_asn1x_create_quark (pkix_asn1_tab, oid);
+       g_return_val_if_fail (asn1, NULL);
 
-       if (!asn1) {
-               g_message ("couldn't decode value for OID: %s", g_quark_to_string (oid));
+       if (!egg_asn1x_decode (asn1, data, len)) {
+               g_message ("couldn't decode value for OID: %s: %s",
+                          g_quark_to_string (oid), egg_asn1x_message (asn1));
+               egg_asn1x_destroy (asn1);
                return NULL;
        }
 
-       value = (gchar*)egg_asn1_read_value (asn1, "", &n_value, NULL);
-
        /*
         * If it's a choice element, then we have to read depending
         * on what's there.
         */
-       if (value && (flags & EGG_OID_IS_CHOICE)) {
-               if (ascii_length_equals ("printableString", value, n_value - 1) ||
-                       ascii_length_equals ("ia5String", value, n_value - 1 ) ||
-                       ascii_length_equals ("utf8String", value, n_value - 1) ||
-                       ascii_length_equals ("teletexString", value, n_value - 1)) {
-                       part = value;
-                       value = (gchar*)egg_asn1_read_value (asn1, part, &n_value, NULL);
-                       g_free (part);
-               } else {
-                       g_free (value);
-                       return NULL;
-               }
-       }
+       if (flags & EGG_OID_IS_CHOICE)
+               node = egg_asn1x_get_choice (asn1);
+       else
+               node = asn1;
 
-       if (!value) {
-               g_message ("couldn't read value for OID: %s", g_quark_to_string (oid));
-               return NULL;
-       }
+       value = egg_asn1x_get_raw_value (node, &n_value);
 
        /*
         * Now we make sure it's UTF-8.
         */
-       if (!g_utf8_validate (value, n_value, NULL)) {
-               gchar *hex = dn_print_hex_value ((guchar*)value, n_value);
-               g_free (value);
-               value = hex;
+
+       if (!value) {
+               g_message ("couldn't read value for OID: %s", g_quark_to_string (oid));
+               result = NULL;
+
+       } else if (!g_utf8_validate (value, n_value, NULL)) {
+               result = dn_print_hex_value ((guchar*)value, n_value);
+
+       } else {
+               result = g_strndup (value, n_value);
        }
 
-       return value;
+       egg_asn1x_destroy (asn1);
+
+       return result;
 }
 
 static gchar*
@@ -139,55 +117,45 @@ dn_print_oid_value (GQuark oid, guint flags, const guchar *data, gsize len)
 }
 
 static gchar*
-dn_parse_rdn (ASN1_TYPE asn, const gchar *part)
+dn_parse_rdn (GNode *asn)
 {
        const gchar *name;
        guint flags;
        GQuark oid;
-       gchar *path;
-       guchar *value;
+       gconstpointer value;
        gsize n_value;
        gchar *display;
        gchar *result;
 
        g_assert (asn);
-       g_assert (part);
 
-       path = g_strdup_printf ("%s.type", part);
-       oid = egg_asn1_read_oid (asn, path);
-       g_free (path);
-
-       if (!oid)
-               return NULL;
-
-       path = g_strdup_printf ("%s.value", part);
-       value = egg_asn1_read_value (asn, path, &n_value, NULL);
-       g_free (path);
+       oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "type", NULL));
+       g_return_val_if_fail (oid, NULL);
 
        flags = egg_oid_get_flags (oid);
        name = egg_oid_get_name (oid);
 
+       value = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "value", NULL), &n_value);
        g_return_val_if_fail (value, NULL);
-       display = dn_print_oid_value (oid, flags, value, n_value);
 
+       display = dn_print_oid_value (oid, flags, value, n_value);
        result = g_strconcat ((flags & EGG_OID_PRINTABLE) ? name : g_quark_to_string (oid),
-                             "=", display, NULL);
+                             "=", display, NULL);
        g_free (display);
 
        return result;
 }
 
 gchar*
-egg_dn_read (ASN1_TYPE asn, const gchar *part)
+egg_dn_read (GNode* asn)
 {
        gboolean done = FALSE;
        GString *result;
-       gchar *path;
+       GNode *node;
        gchar *rdn;
        gint i, j;
 
        g_return_val_if_fail (asn, NULL);
-       g_return_val_if_fail (part, NULL);
 
        result = g_string_sized_new (64);
 
@@ -196,16 +164,15 @@ egg_dn_read (ASN1_TYPE asn, const gchar *part)
 
                /* Each type=value pair of an RDN */
                for (j = 1; TRUE; ++j) {
-                       path = g_strdup_printf ("%s%s?%u.?%u", part ? part : "",
-                                               part ? "." : "", i, j);
-                       rdn = dn_parse_rdn (asn, path);
-                       g_free (path);
-
-                       if (!rdn) {
+                       node = egg_asn1x_node (asn, i, j, NULL);
+                       if (!node) {
                                done = j == 1;
                                break;
                        }
 
+                       rdn = dn_parse_rdn (node);
+                       g_return_val_if_fail (rdn, NULL);
+
                        /* Account for multi valued RDNs */
                        if (j > 1)
                                g_string_append (result, "+");
@@ -222,18 +189,17 @@ egg_dn_read (ASN1_TYPE asn, const gchar *part)
 }
 
 gchar*
-egg_dn_read_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
+egg_dn_read_part (GNode *asn, const gchar *match)
 {
        gboolean done = FALSE;
        const gchar *name;
-       guchar *value;
+       gconstpointer value;
        gsize n_value;
-       gchar *path;
+       GNode *node;
        GQuark oid;
        gint i, j;
 
        g_return_val_if_fail (asn, NULL);
-       g_return_val_if_fail (part, NULL);
        g_return_val_if_fail (match, NULL);
 
        /* Each (possibly multi valued) RDN */
@@ -241,17 +207,15 @@ egg_dn_read_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
 
                /* Each type=value pair of an RDN */
                for (j = 1; TRUE; ++j) {
-                       path = g_strdup_printf ("%s%s?%u.?%u.type",
-                                               part ? part : "",
-                                               part ? "." : "", i, j);
-                       oid = egg_asn1_read_oid (asn, path);
-                       g_free (path);
-
-                       if (!oid) {
+                       node = egg_asn1x_node (asn, i, j, "type", NULL);
+                       if (!node) {
                                done = j == 1;
                                break;
                        }
 
+                       oid = egg_asn1x_get_oid_as_quark (node);
+                       g_return_val_if_fail (oid, NULL);
+
                        /* Does it match either the OID or the displayable? */
                        if (g_ascii_strcasecmp (g_quark_to_string (oid), match) != 0) {
                                name = egg_oid_get_name (oid);
@@ -259,13 +223,12 @@ egg_dn_read_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
                                        continue;
                        }
 
-                       path = g_strdup_printf ("%s%s?%u.?%u.value",
-                                               part ? part : "",
-                                               part ? "." : "", i, j);
-                       value = egg_asn1_read_value (asn, path, &n_value, NULL);
-                       g_free (path);
+                       node = egg_asn1x_node (asn, i, j, "value", NULL);
+                       g_return_val_if_fail (node, NULL);
 
+                       value = egg_asn1x_get_raw_element (node, &n_value);
                        g_return_val_if_fail (value, NULL);
+
                        return dn_print_oid_value (oid, egg_oid_get_flags (oid), value, n_value);
                }
        }
@@ -274,12 +237,11 @@ egg_dn_read_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
 }
 
 gboolean
-egg_dn_parse (ASN1_TYPE asn, const gchar *part,
-              EggDnCallback callback, gpointer user_data)
+egg_dn_parse (GNode *asn, EggDnCallback callback, gpointer user_data)
 {
        gboolean done = FALSE;
-       gchar *path;
-       guchar *value;
+       GNode *node;
+       gconstpointer value;
        gsize n_value;
        GQuark oid;
        guint i, j;
@@ -293,33 +255,26 @@ egg_dn_parse (ASN1_TYPE asn, const gchar *part,
                for (j = 1; TRUE; ++j) {
 
                        /* Dig out the type */
-                       path = g_strdup_printf ("%s%s?%u.?%u.type",
-                                               part ? part : "",
-                                               part ? "." : "", i, j);
-                       oid = egg_asn1_read_oid (asn, path);
-                       g_free (path);
-
-                       if (!oid) {
+                       node = egg_asn1x_node (asn, i, j, "type", NULL);
+                       if (!node) {
                                done = j == 1;
                                break;
                        }
 
-                       /* Print the value as nicely as we can */
-                       path = g_strdup_printf ("%s%s?%u.?%u.value",
-                                               part ? part : "",
-                                               part ? "." : "", i, j);
-                       value = egg_asn1_read_value (asn, path, &n_value, NULL);
-                       g_free (path);
+                       oid = egg_asn1x_get_oid_as_quark (node);
+                       g_return_val_if_fail (oid, FALSE);
 
-                       if (!value) {
+                       /* Dig out the value */
+                       node = egg_asn1x_node (asn, i, j, "value", NULL);
+                       if (!node) {
                                done = j == 1;
                                break;
                        }
 
+                       value = egg_asn1x_get_raw_element (node, &n_value);
+
                        if (callback)
                                (callback) (i, oid, value, n_value, user_data);
-
-                       g_free (value);
                }
        }
 
index c205ba7..96fe5ff 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
-/* egg-asn1.h - ASN.1 helper routines
+/* egg-dn.h - ASN.1 helper routines
 
-   Copyright (C) 2007 Stefan Walter
+   Copyright (C) 2010 Stefan Walter
 
    The Gnome Keyring Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
 
 #include <glib.h>
 
-#include <libtasn1.h>
+gchar*             egg_dn_read                            (GNode *node);
 
-gchar*             egg_dn_read                            (ASN1_TYPE asn, const gchar *part);
+gchar*             egg_dn_read_part                       (GNode *node,
+                                                           const gchar *match);
 
-gchar*             egg_dn_read_part                       (ASN1_TYPE asn, const gchar *part, const gchar *match);
+typedef void       (*EggDnCallback)                       (guint index,
+                                                           GQuark oid,
+                                                           const guchar *value,
+                                                           gsize n_value,
+                                                           gpointer user_data);
 
-typedef void       (*EggDnCallback)                       (guint index, GQuark oid, const guchar *value,
-                                                           gsize n_value, gpointer user_data);
+gboolean           egg_dn_parse                           (GNode *node,
+                                                           EggDnCallback callback,
+                                                           gpointer user_data);
 
-gboolean           egg_dn_parse                           (ASN1_TYPE asn, const gchar *part,
-                                                           EggDnCallback callback, gpointer user_data);
+gchar*             egg_dn_print_value                     (GQuark oid,
+                                                           const guchar *value,
+                                                           gsize n_value);
 
-gchar*             egg_dn_print_value                     (GQuark oid, const guchar *value, gsize n_value);
-
-#endif /*EGG_DN_H_*/
+#endif /* EGG_DN_H_ */
index 17ef50a..e63f87a 100644 (file)
@@ -21,7 +21,8 @@
 
 #include "config.h"
 
-#include "egg-asn1.h"
+#include "egg-asn1-defs.h"
+#include "egg-asn1x.h"
 #include "egg-secure-memory.h"
 #include "egg-symkey.h"
 
@@ -613,12 +614,12 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
                        const gchar *password, gsize n_password, const guchar *data,
                        gsize n_data, gcry_cipher_hd_t *cih)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gcry_error_t gcry;
-       const guchar *salt;
+       gconstpointer salt;
        gsize n_salt;
        gsize n_block, n_key;
-       guint iterations;
+       gulong iterations;
        guchar *key = NULL;
        guchar *iv = NULL;
        gboolean ret;
@@ -635,14 +636,16 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
            gcry_md_test_algo (hash_algo) != 0)
                goto done;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-5-PBE-params", data, n_data);
-       if (!asn)
+       asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-PBE-params");
+       g_return_val_if_fail (asn, FALSE);
+
+       if (!egg_asn1x_decode (asn, data, n_data))
                goto done;
 
-       salt = egg_asn1_read_content (asn, data, n_data, "salt", &n_salt);
+       salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL), &n_salt);
        if (!salt)
                goto done;
-       if (!egg_asn1_read_uint (asn, "iterationCount", &iterations))
+       if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
                iterations = 1;
 
        n_key = gcry_cipher_get_algo_keylen (cipher_algo);
@@ -668,9 +671,7 @@ read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, int hash_algo,
 done:
        g_free (iv);
        egg_secure_free (key);
-
-       if (asn)
-               asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
 
        return ret;
 }
@@ -678,55 +679,59 @@ done:
 static gboolean
 setup_pkcs5_rc2_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gcry_error_t gcry;
        const guchar *iv;
        gsize n_iv;
-       guint version;
+       gulong version;
+       gboolean ret = FALSE;
 
        g_assert (data);
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-5-rc2-CBC-params", data, n_data);
-       if (!asn)
-               return FALSE;
+       asn = egg_asn1x_create (pkix_asn1_tab, "pkcs-5-rc2-CBC-params");
+       g_return_val_if_fail (asn, FALSE);
 
-       if (!egg_asn1_read_uint (asn, "rc2ParameterVersion", &version))
-               return FALSE;
+       if (!egg_asn1x_decode (asn, data, n_data))
+               goto done;
 
-       iv = egg_asn1_read_content (asn, data, n_data, "iv", &n_iv);
-       asn1_delete_structure (&asn);
+       if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "rc2ParameterVersion", NULL), &version))
+               goto done;
 
+       iv = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "iv", NULL), &n_iv);
        if (!iv)
-               return FALSE;
+               goto done;
 
        gcry = gcry_cipher_setiv (cih, iv, n_iv);
-
        if (gcry != 0) {
                g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv);
-               return FALSE;
+               goto done;
        }
 
-       return TRUE;
+       ret = TRUE;
+
+done:
+       egg_asn1x_destroy (asn);
+       return ret;
 }
 
 static gboolean
 setup_pkcs5_des_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gcry_error_t gcry;
-       const guchar *iv;
+       gconstpointer iv;
        gsize n_iv;
 
        g_assert (data);
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-5-des-EDE3-CBC-params", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-EDE3-CBC-params", data, n_data);
        if (!asn)
-               asn = egg_asn1_decode ("PKIX1.pkcs-5-des-CBC-params", data, n_data);
+               asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-des-CBC-params", data, n_data);
        if (!asn)
                return FALSE;
 
-       iv = egg_asn1_read_content (asn, data, n_data, "", &n_iv);
-       asn1_delete_structure (&asn);
+       iv = egg_asn1x_get_raw_value (asn, &n_iv);
+       egg_asn1x_destroy (asn);
 
        if (!iv)
                return FALSE;
@@ -745,26 +750,26 @@ static gboolean
 setup_pkcs5_pbkdf2_params (const gchar *password, gsize n_password, const guchar *data,
                            gsize n_data, int cipher_algo, gcry_cipher_hd_t cih)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gboolean ret;
        gcry_error_t gcry;
        guchar *key = NULL;
        const guchar *salt;
        gsize n_salt, n_key;
-       guint iterations;
+       gulong iterations;
 
        g_assert (cipher_algo);
        g_assert (data);
 
        ret = FALSE;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-5-PBKDF2-params", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBKDF2-params", data, n_data);
        if (!asn)
                goto done;
 
-       if (!egg_asn1_read_uint (asn, "iterationCount", &iterations))
+       if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterationCount", NULL), &iterations))
                iterations = 1;
-       salt = egg_asn1_read_content (asn, data, n_data, "salt.specified", &n_salt);
+       salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", "specified", NULL), &n_salt);
        if (!salt)
                goto done;
 
@@ -785,8 +790,7 @@ setup_pkcs5_pbkdf2_params (const gchar *password, gsize n_password, const guchar
 
 done:
        egg_secure_free (key);
-       if (asn)
-               asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
        return ret;
 }
 
@@ -794,12 +798,13 @@ static gboolean
 read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *data,
                          gsize n_data, gcry_cipher_hd_t *cih)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gboolean r, ret;
        GQuark key_deriv_algo, enc_oid;
        gcry_error_t gcry;
        int algo, mode;
-       int beg, end;
+       gconstpointer params;
+       gsize n_params;
 
        g_return_val_if_fail (cih != NULL, FALSE);
        g_return_val_if_fail (data != NULL && n_data != 0, FALSE);
@@ -809,14 +814,14 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
        *cih = NULL;
        ret = FALSE;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-5-PBES2-params", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-5-PBES2-params", data, n_data);
        if (!asn)
                goto done;
 
        algo = mode = 0;
 
        /* Read in all the encryption type */
-       enc_oid = egg_asn1_read_oid (asn, "encryptionScheme.algorithm");
+       enc_oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionScheme", "algorithm", NULL));
        if (!enc_oid)
                goto done;
        if (enc_oid == OID_DES_EDE3_CBC)
@@ -840,17 +845,17 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
        }
 
        /* Read out the parameters */
-       if (asn1_der_decoding_startEnd (asn, data, n_data, "encryptionScheme.parameters",
-                                       &beg, &end) != ASN1_SUCCESS)
+       params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionScheme", "parameters", NULL), &n_params);
+       if (!params)
                goto done;
 
        switch (algo) {
        case GCRY_CIPHER_3DES:
        case GCRY_CIPHER_DES:
-               r = setup_pkcs5_des_params (data + beg, end - beg + 1, *cih);
+               r = setup_pkcs5_des_params (params, n_params, *cih);
                break;
        case GCRY_CIPHER_RFC2268_128:
-               r = setup_pkcs5_rc2_params (data + beg, end - beg + 1, *cih);
+               r = setup_pkcs5_rc2_params (params, n_params, *cih);
                break;
        default:
                /* Should have been caught on the oid check above */
@@ -863,7 +868,7 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
                goto done;
 
        /* Read out the key creation paramaters */
-       key_deriv_algo = egg_asn1_read_oid (asn, "keyDerivationFunc.algorithm");
+       key_deriv_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "keyDerivationFunc", "algorithm", NULL));
        if (!key_deriv_algo)
                goto done;
        if (key_deriv_algo != OID_PBKDF2) {
@@ -871,11 +876,11 @@ read_cipher_pkcs5_pbes2 (const gchar *password, gsize n_password, const guchar *
                goto done;
        }
 
-       if (asn1_der_decoding_startEnd (asn, data, n_data, "keyDerivationFunc.parameters",
-                                       &beg, &end) != ASN1_SUCCESS)
+       params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "keyDerivationFunc", "parameters", NULL), &n_params);
+       if (!params)
                goto done;
 
-       ret = setup_pkcs5_pbkdf2_params (password, n_password, data + beg, end - beg + 1, algo, *cih);
+       ret = setup_pkcs5_pbkdf2_params (password, n_password, params, n_params, algo, *cih);
 
 done:
        if (ret != TRUE && *cih) {
@@ -883,9 +888,7 @@ done:
                *cih = NULL;
        }
 
-       if (asn)
-               asn1_delete_structure (&asn);
-
+       egg_asn1x_destroy (asn);
        return ret;
 }
 
@@ -894,13 +897,13 @@ read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password,
                         gsize n_password, const guchar *data, gsize n_data,
                         gcry_cipher_hd_t *cih)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gcry_error_t gcry;
        gboolean ret;
        const guchar *salt;
        gsize n_salt;
        gsize n_block, n_key;
-       guint iterations;
+       gulong iterations;
        guchar *key = NULL;
        guchar *iv = NULL;
 
@@ -915,14 +918,14 @@ read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password,
        if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
                goto done;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-12-PbeParams", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PbeParams", data, n_data);
        if (!asn)
                goto done;
 
-       salt = egg_asn1_read_content (asn, data, n_data, "salt", &n_salt);
+       salt = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "salt", NULL), &n_salt);
        if (!salt)
                goto done;
-       if (!egg_asn1_read_uint (asn, "iterations", &iterations))
+       if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "iterations", NULL), &iterations))
                goto done;
 
        n_block = gcry_cipher_get_algo_blklen (cipher_algo);
@@ -954,10 +957,7 @@ done:
 
        g_free (iv);
        egg_secure_free (key);
-
-       if (asn)
-               asn1_delete_structure (&asn);
-
+       egg_asn1x_destroy (asn);
        return ret;
 }
 
index c7d6acc..00bcfde 100644 (file)
@@ -1,8 +1,5 @@
-asn1-def-test.h: test.asn
-       $(ASN1PARSER) -o asn1-def-test.h $(srcdir)/test.asn
-
-asn1-def-tests.h: tests.asn
-       $(ASN1PARSER) -o asn1-def-tests.h $(srcdir)/tests.asn
+asn1-def-test.c: test.asn
+       $(ASN1PARSER) -o asn1-def-test.c $(srcdir)/test.asn
 
 # Test files should be listed in order they need to run
 TESTING_FILES = \
@@ -18,8 +15,7 @@ TESTING_FILES = \
        unit-test-openssl.c \
        unit-test-dh.c \
        unit-test-spawn.c \
-       asn1-def-test.h \
-       asn1-def-tests.h
+       asn1-def-test.c
 
 UNIT_PROMPT =
 
@@ -28,13 +24,12 @@ TESTING_LIBS =  \
 
 EXTRA_DIST = \
        test.asn \
-       tests.asn \
        test-data
 
 include $(top_srcdir)/testing/testing.make
 
 BUILT_SOURCES += \
-       asn1-def-test.h
+       asn1-def-test.c
 
 # ------------------------------------------------------------------------------
 
index d550984..57d4aac 100644 (file)
 #include "egg/egg-asn1x.h"
 
 #include <glib.h>
+#include <libtasn1.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 
-#include "asn1-def-tests.h"
+extern const ASN1_ARRAY_TYPE test_asn1_tab[];
 
 const gchar I33[] =           "\x02\x01\x2A";
 const gchar BFALSE[] =        "\x01\x01\x00";
@@ -42,6 +43,9 @@ const gchar SFARNSWORTH[] =   "\x04\x0A""farnsworth";
 const gchar SIMPLICIT[] =     "\x85\x08""implicit";
 const gchar SEXPLICIT[] =     "\xE5\x0A\x04\x08""explicit";
 const gchar TGENERALIZED[] =  "\x18\x0F""20070725130528Z";
+const gchar BITS_TEST[] =  "\x03\x04\x06\x6e\x5d\xc0";
+const gchar BITS_BAD[] =  "\x03\x04\x06\x6e\x5d\xc1";
+const gchar BITS_ZERO[] =  "\x03\x01\x00";
 
 #define XL(x) G_N_ELEMENTS (x) - 1
 
@@ -50,7 +54,7 @@ DEFINE_TEST(asn1_boolean)
        GNode *asn;
        gboolean value;
 
-       asn = egg_asn1x_create (tests_asn1_tab, "TestBoolean");
+       asn = egg_asn1x_create (test_asn1_tab, "TestBoolean");
        g_assert (asn);
 
        /* Shouldn't succeed */
@@ -87,7 +91,7 @@ DEFINE_TEST(asn1_integer)
        GNode *asn;
        gulong value;
 
-       asn = egg_asn1x_create (tests_asn1_tab, "TestInteger");
+       asn = egg_asn1x_create (test_asn1_tab, "TestInteger");
        g_assert (asn);
 
        /* Shouldn't succeed */
@@ -115,7 +119,7 @@ DEFINE_TEST(asn1_octet_string)
        GNode *asn;
        gchar *value;
 
-       asn = egg_asn1x_create (tests_asn1_tab, "TestOctetString");
+       asn = egg_asn1x_create (test_asn1_tab, "TestOctetString");
        g_assert (asn);
 
        /* Shouldn't succeed */
@@ -143,7 +147,7 @@ DEFINE_TEST(asn1_generalized_time)
        GNode *asn;
        glong value;
 
-       asn = egg_asn1x_create (tests_asn1_tab, "TestGeneralized");
+       asn = egg_asn1x_create (test_asn1_tab, "TestGeneralized");
        g_assert (asn);
 
        /* Shouldn't succeed */
@@ -170,7 +174,7 @@ DEFINE_TEST(asn1_implicit)
        GNode *asn;
        gchar *value;
 
-       asn = egg_asn1x_create (tests_asn1_tab, "TestImplicit");
+       asn = egg_asn1x_create (test_asn1_tab, "TestImplicit");
        g_assert (asn);
 
        /* Should work */
@@ -188,7 +192,7 @@ DEFINE_TEST(asn1_explicit)
        GNode *asn;
        gchar *value;
 
-       asn = egg_asn1x_create (tests_asn1_tab, "TestExplicit");
+       asn = egg_asn1x_create (test_asn1_tab, "TestExplicit");
        g_assert (asn);
 
        /* Should work */
@@ -200,3 +204,214 @@ DEFINE_TEST(asn1_explicit)
 
        egg_asn1x_destroy (asn);
 }
+
+DEFINE_TEST(asn1_bit_string_decode)
+{
+       GNode *asn;
+       guchar *bits;
+       guint n_bits;
+
+       asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+       g_assert (asn);
+
+       /* Should work */
+       if (!egg_asn1x_decode (asn, BITS_TEST, XL (BITS_TEST)))
+               g_assert_not_reached ();
+
+       bits = egg_asn1x_get_bits_as_raw (asn, NULL, &n_bits);
+       g_assert (bits);
+       g_assert_cmpuint (n_bits, ==, 18);
+       g_assert_cmpint (bits[0], ==, 0x6e);
+       g_assert_cmpint (bits[1], ==, 0x5d);
+       g_assert_cmpint (bits[2], ==, 0xc0);
+
+       g_free (bits);
+       egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_decode_bad)
+{
+       GNode *asn;
+
+       asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+       g_assert (asn);
+
+       /* Should not work */
+       if (egg_asn1x_decode (asn, BITS_BAD, XL (BITS_BAD)))
+               g_assert_not_reached ();
+
+       egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_decode_ulong)
+{
+       GNode *asn;
+       gulong bits;
+       guint n_bits;
+
+       asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+       g_assert (asn);
+
+       /* Should work */
+       if (!egg_asn1x_decode (asn, BITS_TEST, XL (BITS_TEST)))
+               g_assert_not_reached ();
+
+       if (!egg_asn1x_get_bits_as_ulong (asn, &bits, &n_bits))
+               g_assert_not_reached ();
+
+       g_assert_cmpuint (n_bits, ==, 18);
+       g_assert_cmphex (bits, ==, 0x1b977);
+
+       egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_encode_decode)
+{
+       GNode *asn;
+       guchar bits[] = { 0x5d, 0x6e, 0x83 };
+       guchar *check;
+       guint n_check, n_bits = 17;
+       gpointer data;
+       gsize n_data;
+
+       asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+       g_assert (asn);
+
+       if (!egg_asn1x_set_bits_as_raw (asn, bits, n_bits, NULL))
+               g_assert_not_reached ();
+
+       data = egg_asn1x_encode (asn, NULL, &n_data);
+       g_assert (data);
+
+       if (!egg_asn1x_decode (asn, data, n_data))
+               g_assert_not_reached ();
+
+       check = egg_asn1x_get_bits_as_raw (asn, NULL, &n_check);
+       g_assert (check);
+       g_assert_cmpuint (n_check, ==, 17);
+       g_assert_cmpint (check[0], ==, 0x5d);
+       g_assert_cmpint (check[1], ==, 0x6e);
+       g_assert_cmpint (check[2], ==, 0x80);
+
+       g_free (check);
+
+       g_free (data);
+       egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_encode_decode_ulong)
+{
+       GNode *asn;
+       gulong check, bits = 0x0101b977;
+       guint n_check, n_bits = 18;
+       gpointer data;
+       gsize n_data;
+
+       asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+       g_assert (asn);
+
+       if (!egg_asn1x_set_bits_as_ulong (asn, bits, n_bits))
+               g_assert_not_reached ();
+
+       data = egg_asn1x_encode (asn, NULL, &n_data);
+       g_assert (data);
+
+       if (!egg_asn1x_decode (asn, data, n_data))
+               g_assert_not_reached ();
+
+       if (!egg_asn1x_get_bits_as_ulong (asn, &check, &n_check))
+               g_assert_not_reached ();
+
+       g_assert_cmpuint (n_check, ==, 18);
+       g_assert_cmphex (check, ==, 0x1b977);
+
+       g_free (data);
+       egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_bit_string_encode_decode_zero)
+{
+       GNode *asn;
+       gpointer data;
+       gsize n_data;
+
+       asn = egg_asn1x_create (test_asn1_tab, "TestBitString");
+       g_assert (asn);
+
+       if (!egg_asn1x_set_bits_as_raw (asn, (guchar*)"", 0, NULL))
+               g_assert_not_reached ();
+
+       data = egg_asn1x_encode (asn, NULL, &n_data);
+       g_assert (data);
+
+       g_assert_cmpsize (n_data, ==, XL (BITS_ZERO));
+       g_assert (memcmp (data, BITS_ZERO, n_data) == 0);
+
+       g_free (data);
+       egg_asn1x_destroy (asn);
+}
+
+DEFINE_TEST(asn1_have)
+{
+       GNode *asn;
+       guchar *data;
+       gsize n_data;
+
+       asn = egg_asn1x_create (test_asn1_tab, "TestBoolean");
+       g_assert (asn);
+
+       g_assert (!egg_asn1x_have (asn));
+
+       if (!egg_asn1x_set_boolean (asn, TRUE))
+               g_assert_not_reached ();
+
+       g_assert (!egg_asn1x_have (asn));
+
+       data = egg_asn1x_encode (asn, NULL, &n_data);
+       g_assert (data);
+
+       g_assert (egg_asn1x_have (asn));
+
+       g_free (data);
+       egg_asn1x_destroy (asn);
+}
+
+static gboolean is_freed = FALSE;
+
+static void
+test_is_freed (gpointer unused)
+{
+       g_assert (!is_freed);
+       is_freed = TRUE;
+}
+
+DEFINE_TEST(asn1_any_set_raw)
+{
+       GNode *asn, *node;
+       guchar *data;
+       const guchar *check;
+       gsize n_data, n_check;
+
+       asn = egg_asn1x_create (test_asn1_tab, "TestAnySeq");
+       g_assert (asn);
+
+       is_freed = FALSE;
+       node = egg_asn1x_node (asn, "contents", NULL);
+       g_assert (node);
+
+       if (!egg_asn1x_set_raw_element (node, (guchar*)SFARNSWORTH, XL (SFARNSWORTH), test_is_freed))
+               g_assert_not_reached ();
+
+       data = egg_asn1x_encode (asn, NULL, &n_data);
+       g_assert (data);
+
+       check = egg_asn1x_get_raw_element (node, &n_check);
+       g_assert (check);
+
+       g_assert (n_check == XL (SFARNSWORTH));
+       g_assert (memcmp (check, SFARNSWORTH, n_check) == 0);
+
+       g_free (data);
+       egg_asn1x_destroy (asn);
+       g_assert (is_freed);
+}
index c71a29f..b397754 100644 (file)
@@ -6,10 +6,7 @@
 #include <stdlib.h>
 #include <unistd.h>
 
-#define extern
-#include "egg/asn1-def-pkix.h"
-#include "egg/asn1-def-pk.h"
-#undef extern
+#include "egg/egg-asn1-defs.h"
 
 #if 0
 static void
@@ -86,6 +83,7 @@ run (void)
        test_some_asn1_stuff (pk_asn1_tab, "test-rsakey-1.der", "RSAPrivateKey");
        test_some_asn1_stuff (pkix_asn1_tab, "test-personalname-1.der", "PersonalName");
        test_some_asn1_stuff (pkix_asn1_tab, "test-pkcs7-1.der", "pkcs-7-ContentInfo");
+       test_some_asn1_stuff (pkix_asn1_tab, "test-pkcs7-2.der", "pkcs-7-ContentInfo");
        test_some_asn1_stuff (pkix_asn1_tab, "test-pkcs12-1.der", "pkcs-12-PFX");
 
        return 0;
diff --git a/egg/tests/test-data/test-pkcs7-2.der b/egg/tests/test-data/test-pkcs7-2.der
new file mode 100755 (executable)
index 0000000..d45b9e0
Binary files /dev/null and b/egg/tests/test-data/test-pkcs7-2.der differ
index 6ad3811..aa0a61c 100644 (file)
@@ -25,7 +25,8 @@
 
 #include "test-suite.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-asn1x.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-oid.h"
 
 #include <stdio.h>
 #include <string.h>
 
-static ASN1_TYPE asn1_cert = NULL;
+static GNode* asn1_cert = NULL;
 static guchar *data_cert = NULL;
 static gsize n_data_cert = 0;
 
 DEFINE_SETUP(dn_cert)
 {
-       ASN1_TYPE pkix;
-       int res;
-
        data_cert = testing_data_read ("test-certificate-1.der", &n_data_cert);
 
-       /* We'll be catching this error later */
-       pkix = egg_asn1_get_pkix_asn1type ();
-       if (!pkix) return;
-
-       res = asn1_create_element (pkix, "PKIX1.Certificate", &asn1_cert);
-       g_assert (res == ASN1_SUCCESS);
+       asn1_cert = egg_asn1x_create (pkix_asn1_tab, "Certificate");
+       g_assert (asn1_cert != NULL);
 
-       res = asn1_der_decoding (&asn1_cert, data_cert, n_data_cert, NULL);
-       g_assert (res == ASN1_SUCCESS);
+       if (!egg_asn1x_decode (asn1_cert, data_cert, n_data_cert))
+               g_assert_not_reached ();
 }
 
 DEFINE_TEARDOWN(dn_cert)
 {
-       asn1_delete_structure (&asn1_cert);
+       egg_asn1x_destroy (asn1_cert);
        g_free (data_cert);
        data_cert = NULL;
 }
@@ -70,14 +64,11 @@ DEFINE_TEST(read_dn)
 {
        gchar *dn;
 
-       dn = egg_dn_read (asn1_cert, "tbsCertificate.issuer.rdnSequence");
+       dn = egg_dn_read (egg_asn1x_node (asn1_cert, "tbsCertificate", "issuer", "rdnSequence", NULL));
        g_assert (dn != NULL);
        g_assert_cmpstr (dn, ==, "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Premium CA, EMAIL=personal-premium@thawte.com");
 
        g_free (dn);
-
-       dn = egg_dn_read (asn1_cert, "tbsCertificate.nonExistant");
-       g_assert (dn == NULL);
 }
 
 DEFINE_TEST(dn_value)
@@ -132,7 +123,7 @@ DEFINE_TEST(parse_dn)
        GString *dn = g_string_new ("");
        last_index = 1;
 
-       if (!egg_dn_parse (asn1_cert, "tbsCertificate.issuer.rdnSequence", concatenate_dn, dn))
+       if (!egg_dn_parse (egg_asn1x_node (asn1_cert, "tbsCertificate", "issuer", "rdnSequence", NULL), concatenate_dn, dn))
                g_assert_not_reached ();
 
        g_assert_cmpstr (dn->str, ==, "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Premium CA, EMAIL=personal-premium@thawte.com");
@@ -141,27 +132,27 @@ DEFINE_TEST(parse_dn)
 
 DEFINE_TEST(read_dn_part)
 {
+       GNode *node;
        gchar *value;
 
-       value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "CN");
+       node = egg_asn1x_node (asn1_cert, "tbsCertificate", "issuer", "rdnSequence", NULL);
+
+       value = egg_dn_read_part (node, "CN");
        g_assert (value != NULL);
        g_assert_cmpstr (value, ==, "Thawte Personal Premium CA");
        g_free (value);
 
-       value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "2.5.4.8");
+       value = egg_dn_read_part (node, "2.5.4.8");
        g_assert (value != NULL);
        g_assert_cmpstr (value, ==, "Western Cape");
        g_free (value);
 
-       value = egg_dn_read_part (asn1_cert, "tbsCertificate.nonExistant", "CN");
-       g_assert (value == NULL);
-
-       value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "DC");
+       value = egg_dn_read_part (node, "DC");
        g_assert (value == NULL);
 
-       value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "0.0.0.0");
+       value = egg_dn_read_part (node, "0.0.0.0");
        g_assert (value == NULL);
 
-       value = egg_dn_read_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "2.5.4.9");
+       value = egg_dn_read_part (node, "2.5.4.9");
        g_assert (value == NULL);
 }
index 0a9c7d1..f5f3053 100644 (file)
@@ -1,9 +1,23 @@
-TEST { }
+TESTS { }
 
 DEFINITIONS EXPLICIT TAGS ::=
 
 BEGIN
 
+TestInteger ::= INTEGER
+
+TestBoolean ::= BOOLEAN
+
+TestOctetString ::= OCTET STRING
+
+TestGeneralized ::= GeneralizedTime
+
+TestImplicit ::= [5] IMPLICIT OCTET STRING
+
+TestExplicit ::= [5] EXPLICIT OCTET STRING
+
+TestBitString ::= BIT STRING
+
 TestIntegers ::= SEQUENCE {
        uint1                   INTEGER,
        uint2                   INTEGER,
@@ -11,8 +25,19 @@ TestIntegers ::= SEQUENCE {
 }
 
 TestData ::= SEQUENCE {
-       data                    OCTET STRING,
+       data                    OCTET STRING
+}
+
+TestBooleanSeq ::= SEQUENCE {
        boolean                 BOOLEAN DEFAULT FALSE
 }
 
+TestOid ::= SEQUENCE {
+       oid                     OBJECT IDENTIFIER
+}
+
+TestAnySeq ::= SEQUENCE {
+       contents                ANY
+}
+
 END
diff --git a/egg/tests/tests.asn b/egg/tests/tests.asn
deleted file mode 100644 (file)
index ad23d5b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-TESTS { }
-
-DEFINITIONS EXPLICIT TAGS ::=
-
-BEGIN
-
-TestInteger ::= INTEGER
-
-TestBoolean ::= BOOLEAN
-
-TestOctetString ::= OCTET STRING
-
-TestGeneralized ::= GeneralizedTime
-
-TestImplicit ::= [5] IMPLICIT OCTET STRING
-
-TestExplicit ::= [5] EXPLICIT OCTET STRING
-
-END
index dca1db6..e8ef55d 100644 (file)
@@ -25,7 +25,8 @@
 
 #include "test-suite.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1-defs.h"
+#include "egg/egg-asn1x.h"
 #include "egg/egg-oid.h"
 
 #include <glib.h>
 #include <stdio.h>
 #include <string.h>
 
-#define extern
-#include "asn1-def-test.h"
-#undef extern
+extern const ASN1_ARRAY_TYPE test_asn1_tab[];
 
-static ASN1_TYPE asn1_test = NULL;
-
-static ASN1_TYPE asn1_cert = NULL;
+static GNode *asn1_cert = NULL;
 static guchar *data_cert = NULL;
 static gsize n_data_cert = 0;
 
 DEFINE_SETUP(asn1_tree)
 {
-       ASN1_TYPE pkix;
-
-       int res = asn1_array2tree (test_asn1_tab, &asn1_test, NULL);
-       g_assert (res == ASN1_SUCCESS);
-
-       /* -------- */
-
        data_cert = testing_data_read ("test-certificate-1.der", &n_data_cert);
 
-       /* We'll be catching this error later */
-       pkix = egg_asn1_get_pkix_asn1type ();
-       if (!pkix) return;
-
-       res = asn1_create_element (pkix, "PKIX1.Certificate", &asn1_cert);
-       g_assert (res == ASN1_SUCCESS);
-
-       res = asn1_der_decoding (&asn1_cert, data_cert, n_data_cert, NULL);
-       g_assert (res == ASN1_SUCCESS);
+       asn1_cert = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data_cert, n_data_cert);
+       g_assert (asn1_cert != NULL);
 }
 
 DEFINE_TEARDOWN(asn1_tree)
 {
-       asn1_delete_structure (&asn1_test);
-       asn1_delete_structure (&asn1_cert);
+       egg_asn1x_destroy (asn1_cert);
        g_free (data_cert);
        data_cert = NULL;
 }
 
-DEFINE_TEST(asn1_types)
+DEFINE_TEST(node_name)
 {
-       ASN1_TYPE asn;
-
-       asn = egg_asn1_get_pk_asn1type ();
-       g_assert ("pk asn type is null" && asn != NULL);
-
-       asn = egg_asn1_get_pkix_asn1type ();
-       g_assert ("pkix asn type is null" && asn != NULL);
+       g_assert_cmpstr (egg_asn1x_name (asn1_cert), ==, "Certificate");
 }
 
 DEFINE_TEST(asn1_integers)
 {
-       ASN1_TYPE asn;
+       GNode *asn;
        guchar *data;
        gsize n_data;
        gboolean ret;
-       guint val;
-       int res;
+       gulong val;
 
-       res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn);
+       asn = egg_asn1x_create (test_asn1_tab, "TestIntegers");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       ret = egg_asn1_write_uint (asn, "uint1", 35);
+       ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), 35);
        g_assert ("couldn't write integer" && ret);
 
-       ret = egg_asn1_write_uint (asn, "uint2", 23456);
+       ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), 23456);
        g_assert ("couldn't write integer" && ret);
 
-       ret = egg_asn1_write_uint (asn, "uint3", 209384022);
+       ret = egg_asn1x_set_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), 209384022);
        g_assert ("couldn't write integer" && ret);
 
        /* Now encode the whole caboodle */
-       data = egg_asn1_encode (asn, "", &n_data, NULL);
+       data = egg_asn1x_encode (asn, NULL, &n_data);
        g_assert ("encoding asn1 didn't work" && data != NULL);
 
-       asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
 
        /* Now decode it all nicely */
-       res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn);
-       g_return_if_fail (res == ASN1_SUCCESS);
-
-       res = asn1_der_decoding (&asn, data, n_data, NULL);
-       g_assert ("decoding asn didn't work" && res == ASN1_SUCCESS);
+       asn = egg_asn1x_create_and_decode (test_asn1_tab, "TestIntegers", data, n_data);
+       g_return_if_fail (asn != NULL);
 
        /* And get out the values */
-       ret = egg_asn1_read_uint (asn, "uint1", &val);
+       ret = egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "uint1", NULL), &val);
        g_assert ("couldn't read integer from asn1" && ret);
        g_assert_cmpuint (val, ==, 35);
 
-       ret = egg_asn1_read_uint (asn, "uint2", &val);
+       ret = egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "uint2", NULL), &val);
        g_assert ("couldn't read integer from asn1" && ret);
        g_assert_cmpuint (val, ==, 23456);
 
-       ret = egg_asn1_read_uint (asn, "uint3", &val);
+       ret = egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "uint3", NULL), &val);
        g_assert ("couldn't read integer from asn1" && ret);
        g_assert_cmpuint (val, ==, 209384022);
+
+       g_free (data);
 }
 
 DEFINE_TEST(boolean)
 {
-       ASN1_TYPE asn = NULL;
+       GNode *asn = NULL;
        gboolean value, ret;
-       int res;
+       gpointer data;
+       gsize n_data;
 
-       res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+       asn = egg_asn1x_create (test_asn1_tab, "TestBooleanSeq");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       res = asn1_write_value (asn, "boolean", "TRUE", 4);
-       g_assert (res == ASN1_SUCCESS);
+       /* Get the default value */
+       value = TRUE;
+       ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
+       g_assert (ret == TRUE);
+       g_assert (value == FALSE);
+
+       ret = egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), TRUE);
+       g_assert (ret == TRUE);
+
+       data = egg_asn1x_encode (asn, NULL, &n_data);
+       g_assert (data);
 
-       ret = egg_asn1_read_boolean (asn, "boolean", &value);
+       ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
        g_assert (ret);
        g_assert (value == TRUE);
 
-       res = asn1_write_value (asn, "boolean", "FALSE", 5);
-       g_assert (res == ASN1_SUCCESS);
+       ret = egg_asn1x_set_boolean (egg_asn1x_node (asn, "boolean", NULL), FALSE);
+       g_assert (ret == TRUE);
 
-       ret = egg_asn1_read_boolean (asn, "boolean", &value);
+       g_free (data);
+       data = egg_asn1x_encode (asn, NULL, &n_data);
+       g_assert (data);
+
+       ret = egg_asn1x_get_boolean (egg_asn1x_node (asn, "boolean", NULL), &value);
        g_assert (ret);
        g_assert (value == FALSE);
 
-       ret = egg_asn1_read_boolean (asn, "nonExistant", &value);
-       g_assert (!ret);
-
-       asn1_delete_structure (&asn);
+       g_free (data);
+       egg_asn1x_destroy (asn);
 }
 
 DEFINE_TEST(write_value)
 {
-       ASN1_TYPE asn = NULL;
+       GNode *asn = NULL;
        guchar *data;
        gsize n_data;
-       int res;
+       guchar *encoded;
+       gsize n_encoded;
 
-       res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+       asn = egg_asn1x_create (test_asn1_tab, "TestData");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       if (!egg_asn1_write_value (asn, "data", (const guchar*)"SOME DATA", 9))
+       if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
                g_assert_not_reached ();
 
-       data = egg_asn1_read_value (asn, "data", &n_data, NULL);
+       encoded = egg_asn1x_encode (asn, NULL, &n_encoded);
+       g_assert (encoded);
+
+       data = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "data", NULL), NULL, &n_data);
        g_assert (data != NULL);
        g_assert_cmpuint (n_data, ==, 9);
        g_assert (memcmp (data, "SOME DATA", 9) == 0);
        g_free (data);
 
-       asn1_delete_structure (&asn);
+       g_free (encoded);
+       egg_asn1x_destroy (asn);
 }
 
 DEFINE_TEST(element_length_content)
 {
-       ASN1_TYPE asn = NULL;
-       guchar buffer[1024];
+       GNode *asn = NULL;
+       gchar *buffer;
        const guchar *content;
        gsize n_content;
-       gint length;
-       int res;
+       gsize n_buffer;
+       gssize length;
 
-       res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+       asn = egg_asn1x_create (test_asn1_tab, "TestData");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       res = asn1_write_value (asn, "data", "SOME DATA", 9);
-       g_assert (res == ASN1_SUCCESS);
+       if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
+               g_assert_not_reached ();
 
-       length = 1024;
-       res = asn1_der_coding (asn, "", buffer, &length, NULL);
-       g_assert (res == ASN1_SUCCESS);
+       buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+       g_assert (buffer != NULL);
 
        /* Now the real test */
-       length = egg_asn1_element_length (buffer, 1024);
+       length = egg_asn1x_element_length (buffer, n_buffer + 1024);
        g_assert_cmpint (length, ==, 13);
 
-       content = egg_asn1_element_content (buffer, length, &n_content);
+       content = egg_asn1x_element_content (buffer, length, &n_content);
        g_assert (content);
        g_assert_cmpuint (n_content, ==, 11);
 
-       content = egg_asn1_element_content (content, n_content, &n_content);
+       content = egg_asn1x_element_content (content, n_content, &n_content);
        g_assert (content);
        g_assert_cmpuint (n_content, ==, 9);
        g_assert (memcmp (content, "SOME DATA", 9) == 0);
 
-       asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
+       g_free (buffer);
 }
 
 DEFINE_TEST(read_element)
 {
-       ASN1_TYPE asn = NULL;
-       guchar buffer[1024];
-       const guchar *data;
+       GNode *asn = NULL;
+       guchar *buffer;
+       gconstpointer data;
        gsize n_data;
-       gint length;
-       int res;
+       gsize n_buffer;
 
-       res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+       asn = egg_asn1x_create (test_asn1_tab, "TestData");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       res = asn1_write_value (asn, "data", "SOME DATA", 9);
-       g_assert (res == ASN1_SUCCESS);
+       if (!egg_asn1x_set_string_as_raw (egg_asn1x_node (asn, "data", NULL), (guchar*)"SOME DATA", 9, NULL))
+               g_assert_not_reached ();
 
-       length = 1024;
-       res = asn1_der_coding (asn, "", buffer, &length, NULL);
-       g_assert (res == ASN1_SUCCESS);
+       buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+       g_assert (buffer != NULL);
 
        /* Now the real test */
-       data = egg_asn1_read_element (asn, buffer, length, "data", &n_data);
+       data = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "data", NULL), &n_data);
        g_assert (data != NULL);
        g_assert_cmpint (n_data, ==, 11);
 
-       data = egg_asn1_read_content (asn, buffer, length, "data", &n_data);
+       data = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "data", NULL), &n_data);
        g_assert (data);
        g_assert_cmpuint (n_data, ==, 9);
        g_assert (memcmp (data, "SOME DATA", 9) == 0);
 
-       /* Invalid should return null for both those */
-       data = egg_asn1_read_element (asn, buffer, length, "nonExistant", &n_data);
-       g_assert (data == NULL);
-       data = egg_asn1_read_content (asn, buffer, length, "nonExistant", &n_data);
-       g_assert (data == NULL);
-
-       asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
+       g_free (buffer);
 }
 
 DEFINE_TEST(oid)
 {
-       ASN1_TYPE asn = NULL;
+       GNode *asn = NULL;
        GQuark oid, check;
-       int res;
+       guchar *buffer;
+       gsize n_buffer;
 
-       res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+       asn = egg_asn1x_create (test_asn1_tab, "TestOid");
        g_assert ("asn test structure is null" && asn != NULL);
 
-       res = asn1_write_value (asn, "data", "SOME DATA", 9);
-       g_assert (res == ASN1_SUCCESS);
+       if (!egg_asn1x_set_oid_as_string (egg_asn1x_node (asn, "oid", NULL), "1.2.34567.89"))
+               g_assert_not_reached ();
 
-       /* No such element, should return 0 */
-       oid = egg_asn1_read_oid (asn, "nonExistant");
-       g_assert (oid == 0);
+       buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+       g_assert (buffer != NULL);
 
        /* Now a quark has been defined */
-       check = g_quark_from_static_string ("SOME DATA");
-       oid = egg_asn1_read_oid (asn, "data");
+       check = g_quark_from_static_string ("1.2.34567.89");
+       oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "oid", NULL));
+       g_assert (oid);
        g_assert (check == oid);
-       g_assert_cmpstr (g_quark_to_string (oid), ==, "SOME DATA");
+       g_assert_cmpstr (g_quark_to_string (oid), ==, "1.2.34567.89");
 
        /* Write a different OID */
-       if (!egg_asn1_write_oid (asn, "data", g_quark_from_static_string ("ANOTHER")))
+       if (!egg_asn1x_set_oid_as_quark (egg_asn1x_node (asn, "oid", NULL), g_quark_from_static_string ("5.4.3.2.1678")))
                g_assert_not_reached ();
 
-       oid = egg_asn1_read_oid (asn, "data");
+       g_free (buffer);
+       buffer = egg_asn1x_encode (asn, NULL, &n_buffer);
+       g_assert (buffer != NULL);
+
+       oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "oid", NULL));
        g_assert (oid);
-       g_assert_cmpstr (g_quark_to_string (oid), ==, "ANOTHER");
+       g_assert_cmpstr (g_quark_to_string (oid), ==, "5.4.3.2.1678");
 
-       asn1_delete_structure (&asn);
+       g_free (buffer);
+       egg_asn1x_destroy (asn);
 }
 
 typedef struct _TimeTestData {
@@ -332,7 +322,7 @@ DEFINE_TEST(general_time)
        const TimeTestData *data;
 
        for (data = generalized_time_test_data; data->value; ++data) {
-               when = egg_asn1_time_parse_general (data->value, -1);
+               when = egg_asn1x_parse_time_general (data->value, -1);
                if (data->ref != when) {
                        printf ("%s", data->value);
                        printf ("%s != ", ctime (&when));
@@ -350,7 +340,7 @@ DEFINE_TEST(utc_time)
        const TimeTestData *data;
 
        for (data = utc_time_test_data; data->value; ++data) {
-               when = egg_asn1_time_parse_utc (data->value, -1);
+               when = egg_asn1x_parse_time_utc (data->value, -1);
                if (data->ref != when) {
                        printf ("%s", data->value);
                        printf ("%s != ", ctime (&when));
@@ -364,19 +354,56 @@ DEFINE_TEST(utc_time)
 
 DEFINE_TEST(read_time)
 {
-       time_t time;
+       glong time;
 
-       if (!egg_asn1_read_time (asn1_cert, "tbsCertificate.validity.notBefore", &time))
-               g_assert_not_reached ();
+       time = egg_asn1x_get_time_as_long (egg_asn1x_node (asn1_cert, "tbsCertificate", "validity", "notBefore", NULL));
        g_assert_cmpint (time, ==, 820454400);
 }
 
 DEFINE_TEST(read_date)
 {
        GDate date;
-       if (!egg_asn1_read_date (asn1_cert, "tbsCertificate.validity.notAfter", &date))
+       if (!egg_asn1x_get_time_as_date (egg_asn1x_node (asn1_cert, "tbsCertificate", "validity", "notAfter", NULL), &date))
                g_assert_not_reached ();
        g_assert_cmpint (date.day, ==, 31);
        g_assert_cmpint (date.month, ==, 12);
        g_assert_cmpint (date.year, ==, 2020);
 }
+
+DEFINE_TEST(create_by_oid)
+{
+       /* id-at-initials = X520initials */
+       GNode *node = egg_asn1x_create (pkix_asn1_tab, "2.5.4.43");
+       g_assert (node != NULL);
+       g_assert_cmpstr (egg_asn1x_name (node), ==, "X520initials");
+       egg_asn1x_destroy (node);
+}
+
+DEFINE_TEST(create_by_oid_invalid)
+{
+       GNode *node = egg_asn1x_create (pkix_asn1_tab, "23.23.23.23");
+       g_assert (node == NULL);
+}
+
+DEFINE_TEST(create_by_bad_order)
+{
+       /*
+        * In pkix.asn the definition for parts of this oid
+        * come in the wrong order. However this should still work.
+        */
+
+       /* id-pe-authorityInfoAccess = AuthorityInfoAccessSyntax */
+       GNode *node = egg_asn1x_create (pkix_asn1_tab, "1.3.6.1.5.5.7.1.1");
+       g_assert (node != NULL);
+       g_assert_cmpstr (egg_asn1x_name (node), ==, "AuthorityInfoAccessSyntax");
+       egg_asn1x_destroy (node);
+}
+
+DEFINE_TEST(count)
+{
+       GNode *node;
+
+       node = egg_asn1x_node (asn1_cert, "tbsCertificate", "issuer", "rdnSequence", NULL);
+       g_assert (node);
+       g_assert_cmpuint (egg_asn1x_count (node), ==, 7);
+}
index 48f656a..13f7115 100644 (file)
@@ -22,7 +22,8 @@
 #include "gcr-certificate.h"
 #include "gcr-certificate-details-widget.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-oid.h"
 #include "egg/egg-hex.h"
@@ -178,30 +179,24 @@ append_fingerprint (GcrCertificateDetailsWidget *self, const guchar *data,
 }
 
 static gboolean
-append_extension (GcrCertificateDetailsWidget *self, ASN1_TYPE asn,
+append_extension (GcrCertificateDetailsWidget *self, GNode *asn,
                   const guchar *data, gsize n_data, gint index)
 {
        GQuark oid;
-       gchar *name, *display;
+       gchar *display;
        gsize n_value;
        const guchar *value;
        const gchar *text;
        gboolean critical;
-       int len, res;
+       GNode *node;
 
        /* Make sure it is present */
-       len = 0;
-       name = g_strdup_printf ("tbsCertificate.extensions.?%u", index);
-       res = asn1_read_value (asn, name, NULL, &len);
-       g_free (name);
-
-       if (res == ASN1_ELEMENT_NOT_FOUND)
+       asn = egg_asn1x_node (asn, "tbsCertificate", "extensions", index, NULL);
+       if (asn == NULL)
                return FALSE;
 
        /* Dig out the OID */
-       name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnID", index);
-       oid = egg_asn1_read_oid (asn, name);
-       g_free (name);
+       oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "extnID", NULL));
        g_return_val_if_fail (oid, FALSE);
 
 
@@ -214,9 +209,7 @@ append_extension (GcrCertificateDetailsWidget *self, ASN1_TYPE asn,
 
 
        /* Extension value */
-       name = g_strdup_printf ("tbsCertificate.extensions.?%u.extnValue", index);
-       value = egg_asn1_read_content (asn, data, n_data, name, &n_value);
-       g_free (name);
+       value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "extnValue", NULL), &n_value);
 
        /* TODO: Parsing of extensions that we understand */
        display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
@@ -225,10 +218,11 @@ append_extension (GcrCertificateDetailsWidget *self, ASN1_TYPE asn,
 
 
        /* Critical */
-       name = g_strdup_printf ("tbsCertificate.extensions.?%u.critical", index);
-       if (egg_asn1_read_boolean (asn, name, &critical))
-               append_field_and_value (self, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
-       g_free (name);
+       node = egg_asn1x_node (asn, "critical", NULL);
+       if (node != NULL) {
+               if (egg_asn1x_get_boolean (node, &critical))
+                       append_field_and_value (self, _("Critical"), critical ? _("Yes") : _("No"), FALSE);
+       }
 
        return TRUE;
 }
@@ -280,10 +274,11 @@ refresh_display (GcrCertificateDetailsWidget *self)
        const guchar *data, *value;
        gsize n_data, n_value;
        const gchar *text;
-       guint version, size;
-       guint index;
+       gulong version;
+       guint index, size, n_bits;
        gchar *display;
-       ASN1_TYPE asn;
+       guchar *bits;
+       GNode *asn;
        GQuark oid;
        GDate date;
 
@@ -297,39 +292,39 @@ refresh_display (GcrCertificateDetailsWidget *self)
        data = gcr_certificate_get_der_data (self->pv->certificate, &n_data);
        g_return_if_fail (data);
 
-       asn = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
        g_return_if_fail (asn);
 
        /* The subject */
        append_heading (self, _("Subject Name"));
-       egg_dn_parse (asn, "tbsCertificate.subject.rdnSequence", on_parsed_dn_part, self);
+       egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), on_parsed_dn_part, self);
 
        /* The Issuer */
        append_heading (self, _("Issuer Name"));
-       egg_dn_parse (asn, "tbsCertificate.issuer.rdnSequence", on_parsed_dn_part, self);
+       egg_dn_parse (egg_asn1x_node (asn, "tbsCertificate", "issuer", "rdnSequence", NULL), on_parsed_dn_part, self);
 
        /* The Issued Parameters */
        append_heading (self, _("Issued Certificate"));
 
-       if (!egg_asn1_read_uint (asn, "tbsCertificate.version", &version))
+       if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "tbsCertificate", "version", NULL), &version))
                g_return_if_reached ();
-       display = g_strdup_printf ("%u", version + 1);
+       display = g_strdup_printf ("%lu", version + 1);
        append_field_and_value (self, _("Version"), display, FALSE);
        g_free (display);
 
-       value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.serialNumber", &n_value);
+       value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "tbsCertificate", "serialNumber", NULL), &n_value);
        g_return_if_fail (value);
        display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
        append_field_and_value (self, _("Serial Number"), display, TRUE);
        g_free (display);
 
        display = g_malloc0 (128);
-       if (egg_asn1_read_date (asn, "tbsCertificate.validity.notBefore", &date)) {
+       if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notBefore", NULL), &date)) {
                if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
                        g_return_if_reached ();
                append_field_and_value (self, _("Not Valid Before"), display, FALSE);
        }
-       if (egg_asn1_read_date (asn, "tbsCertificate.validity.notAfter", &date)) {
+       if (egg_asn1x_get_time_as_date (egg_asn1x_node (asn, "tbsCertificate", "validity", "notAfter", NULL), &date)) {
                if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
                        g_return_if_reached ();
                append_field_and_value (self, _("Not Valid After"), display, FALSE);
@@ -339,18 +334,18 @@ refresh_display (GcrCertificateDetailsWidget *self)
        /* Signature */
        append_heading (self, _("Signature"));
 
-       oid = egg_asn1_read_oid (asn, "signatureAlgorithm.algorithm");
+       oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "signatureAlgorithm", "algorithm", NULL));
        text = egg_oid_get_description (oid);
        append_field_and_value (self, _("Signature Algorithm"), text, FALSE);
 
-       value = egg_asn1_read_content (asn, data, n_data, "signatureAlgorithm.parameters", &n_value);
+       value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "signatureAlgorithm", "parameters", NULL), &n_value);
        if (value && n_value) {
                display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
                append_field_and_value (self, _("Signature Parameters"), display, TRUE);
                g_free (display);
        }
 
-       value = egg_asn1_read_content (asn, data, n_data, "signature", &n_value);
+       value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "signature", NULL), &n_value);
        g_return_if_fail (value);
        display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
        append_field_and_value (self, _("Signature"), display, TRUE);
@@ -359,11 +354,11 @@ refresh_display (GcrCertificateDetailsWidget *self)
        /* Public Key Info */
        append_heading (self, _("Public Key Info"));
 
-       oid = egg_asn1_read_oid (asn, "tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm");
+       oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", "algorithm", "algorithm", NULL));
        text = egg_oid_get_description (oid);
        append_field_and_value (self, _("Key Algorithm"), text, FALSE);
 
-       value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.subjectPublicKeyInfo.algorithm.parameters", &n_value);
+       value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", "algorithm", "parameters", NULL), &n_value);
        if (value && n_value) {
                display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
                append_field_and_value (self, _("Key Parameters"), display, TRUE);
@@ -377,11 +372,12 @@ refresh_display (GcrCertificateDetailsWidget *self)
                g_free (display);
        }
 
-       value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", &n_value);
-       g_return_if_fail (value);
-       display = egg_hex_encode_full (value, n_value, TRUE, ' ', 1);
+       bits = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "tbsCertificate", "subjectPublicKeyInfo", "subjectPublicKey", NULL), NULL, &n_bits);
+       g_return_if_fail (bits);
+       display = egg_hex_encode_full (bits, n_bits / 8, TRUE, ' ', 1);
        append_field_and_value (self, _("Public Key"), display, TRUE);
        g_free (display);
+       g_free (bits);
 
        /* Fingerprints */
        append_heading (self, _("Fingerprints"));
@@ -395,7 +391,7 @@ refresh_display (GcrCertificateDetailsWidget *self)
                        break;
        }
 
-       asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
 }
 
 /* -----------------------------------------------------------------------------
index cb2edcc..80c9395 100644 (file)
@@ -24,7 +24,8 @@
 #include "gcr-internal.h"
 #include "gcr-certificate.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-hex.h"
 
@@ -56,7 +57,7 @@
 typedef struct _GcrCertificateInfo {
        const guchar *der;
        gsize n_der;
-       ASN1_TYPE asn1;
+       GNode *asn1;
        guint key_size;
 } GcrCertificateInfo;
 
@@ -74,7 +75,7 @@ certificate_info_free (gpointer data)
        GcrCertificateInfo *info = data;
        if (info) {
                g_assert (info->asn1);
-               asn1_delete_structure (&info->asn1);
+               egg_asn1x_destroy (info->asn1);
                g_free (info);
        }
 }
@@ -83,7 +84,7 @@ static GcrCertificateInfo*
 certificate_info_load (GcrCertificate *cert)
 {
        GcrCertificateInfo *info;
-       ASN1_TYPE asn1;
+       GNode *asn1;
        const guchar *der;
        gsize n_der;
 
@@ -99,7 +100,7 @@ certificate_info_load (GcrCertificate *cert)
        }
 
        /* Cache is invalid or non existent */
-       asn1 = egg_asn1_decode ("PKIX1.Certificate", der, n_der);
+       asn1 = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", der, n_der);
        if (asn1 == NULL) {
                g_warning ("a derived class provided an invalid or unparseable X509 DER certificate data.");
                return NULL;
@@ -117,16 +118,16 @@ certificate_info_load (GcrCertificate *cert)
 static guint
 calculate_rsa_key_size (const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn;
+       GNode *asn;
        gsize n_content;
 
-       asn = egg_asn1_decode ("PK.RSAPublicKey", data, n_data);
+       asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPublicKey", data, n_data);
        g_return_val_if_fail (asn, 0);
 
-       if (!egg_asn1_read_content (asn, data, n_data, "modulus", &n_content))
+       if (!egg_asn1x_get_raw_value (egg_asn1x_node (asn, "modulus", NULL), &n_content))
                g_return_val_if_reached (0);
 
-       asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
 
        /* Removes the complement */
        return (n_content / 2) * 2 * 8;
@@ -135,16 +136,16 @@ calculate_rsa_key_size (const guchar *data, gsize n_data)
 static guint
 calculate_dsa_params_size (const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn;
+       GNode *asn;
        gsize n_content;
 
-       asn = egg_asn1_decode ("PK.DSAParameters", data, n_data);
+       asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", data, n_data);
        g_return_val_if_fail (asn, 0);
 
-       if (!egg_asn1_read_content (asn, data, n_data, "p", &n_content))
+       if (!egg_asn1x_get_raw_value (egg_asn1x_node (asn, "p", NULL), &n_content))
                g_return_val_if_reached (0);
 
-       asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
 
        /* Removes the complement */
        return (n_content / 2) * 2 * 8;
@@ -153,41 +154,41 @@ calculate_dsa_params_size (const guchar *data, gsize n_data)
 static guint
 calculate_key_size (GcrCertificateInfo *info)
 {
-       ASN1_TYPE asn;
+       GNode *asn;
        const guchar *data, *params;
-       gsize n_data, n_params, n_key;
-       guint key_size = 0;
+       gsize n_data, n_params;
+       guint key_size = 0, n_bits;
        guchar *key;
        GQuark oid;
 
-       data = egg_asn1_read_element (info->asn1, info->der, info->n_der, "tbsCertificate.subjectPublicKeyInfo", &n_data);
+       data = egg_asn1x_get_raw_element (egg_asn1x_node (info->asn1, "tbsCertificate", "subjectPublicKeyInfo", NULL), &n_data);
        g_return_val_if_fail (data != NULL, 0);
 
-       asn = egg_asn1_decode ("PKIX1.SubjectPublicKeyInfo", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "SubjectPublicKeyInfo", data, n_data);
        g_return_val_if_fail (asn, 0);
 
        /* Figure out the algorithm */
-       oid = egg_asn1_read_oid (asn, "algorithm.algorithm");
+       oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "algorithm", "algorithm", NULL));
        g_return_val_if_fail (oid, 0);
 
        /* RSA keys are stored in the main subjectPublicKey field */
        if (oid == OID_RSA_KEY) {
 
                /* A bit string so we cannot process in place */
-               key = egg_asn1_read_value (asn, "subjectPublicKey", &n_key, NULL);
+               key = egg_asn1x_get_bits_as_raw (egg_asn1x_node (asn, "subjectPublicKey", NULL), NULL, &n_bits);
                g_return_val_if_fail (key, 0);
-               key_size = calculate_rsa_key_size (key, n_key / 8);
+               key_size = calculate_rsa_key_size (key, n_bits / 8);
 
        /* The DSA key size is discovered by the prime in params */
        } else if (oid == OID_DSA_KEY) {
-               params = egg_asn1_read_element (asn, data, n_data, "algorithm.parameters", &n_params);
+               params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "algorithm", "parameters", NULL), &n_params);
                key_size = calculate_dsa_params_size (params, n_params);
 
        } else {
                g_message ("unsupported key algorithm in certificate: %s", g_quark_to_string (oid));
        }
 
-       asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
        g_free (key);
 
        return key_size;
@@ -320,7 +321,7 @@ gcr_certificate_get_issuer_part (GcrCertificate *self, const char *part)
        info = certificate_info_load (self);
        g_return_val_if_fail (info, NULL);
 
-       return egg_dn_read_part (info->asn1, "tbsCertificate.issuer.rdnSequence", part);
+       return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL), part);
 }
 
 /**
@@ -345,7 +346,7 @@ gcr_certificate_get_issuer_dn (GcrCertificate *self)
        info = certificate_info_load (self);
        g_return_val_if_fail (info, NULL);
 
-       return egg_dn_read (info->asn1, "tbsCertificate.issuer.rdnSequence");
+       return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL));
 }
 
 /**
@@ -391,7 +392,7 @@ gcr_certificate_get_subject_part (GcrCertificate *self, const char *part)
        info = certificate_info_load (self);
        g_return_val_if_fail (info, NULL);
 
-       return egg_dn_read_part (info->asn1, "tbsCertificate.subject.rdnSequence", part);
+       return egg_dn_read_part (egg_asn1x_node (info->asn1, "tbsCertificate", "subject", "rdnSequence", NULL), part);
 }
 
 /**
@@ -416,7 +417,7 @@ gcr_certificate_get_subject_dn (GcrCertificate *self)
        info = certificate_info_load (self);
        g_return_val_if_fail (info, NULL);
 
-       return egg_dn_read (info->asn1, "tbsCertificate.issuer.rdnSequence");
+       return egg_dn_read (egg_asn1x_node (info->asn1, "tbsCertificate", "issuer", "rdnSequence", NULL));
 }
 
 /**
@@ -442,7 +443,7 @@ gcr_certificate_get_issued_date (GcrCertificate *self)
        g_return_val_if_fail (info, NULL);
 
        date = g_date_new ();
-       if (!egg_asn1_read_date (info->asn1, "tbsCertificate.validity.notBefore", date)) {
+       if (!egg_asn1x_get_time_as_date (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notBefore", NULL), date)) {
                g_date_free (date);
                return NULL;
        }
@@ -473,7 +474,7 @@ gcr_certificate_get_expiry_date (GcrCertificate *self)
        g_return_val_if_fail (info, NULL);
 
        date = g_date_new ();
-       if (!egg_asn1_read_date (info->asn1, "tbsCertificate.validity.notAfter", date)) {
+       if (!egg_asn1x_get_time_as_date (egg_asn1x_node (info->asn1, "tbsCertificate", "validity", "notAfter", NULL), date)) {
                g_date_free (date);
                return NULL;
        }
@@ -600,6 +601,7 @@ guchar*
 gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length)
 {
        GcrCertificateInfo *info;
+       gconstpointer serial;
 
        g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
        g_return_val_if_fail (n_length, NULL);
@@ -607,7 +609,8 @@ gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length)
        info = certificate_info_load (self);
        g_return_val_if_fail (info, NULL);
 
-       return egg_asn1_read_value (info->asn1, "tbsCertificate.serialNumber", n_length, g_realloc);
+       serial = egg_asn1x_get_raw_value (egg_asn1x_node (info->asn1, "tbsCertificate", "serialNumber", NULL), n_length);
+       return g_memdup (serial, *n_length);
 }
 
 /**
index 2b0f4cd..7fe7561 100644 (file)
@@ -28,7 +28,8 @@
 #include "gcr-parser.h"
 #include "gcr-types.h"
 
-#include "egg/egg-asn1.h"
+#include "egg/egg-asn1x.h"
+#include "egg/egg-asn1-defs.h"
 #include "egg/egg-dn.h"
 #include "egg/egg-openssl.h"
 #include "egg/egg-secure-memory.h"
@@ -158,7 +159,7 @@ init_quarks (void)
  */
 
 static gboolean
-parsed_asn1_attribute (GcrParser *self, ASN1_TYPE asn, const guchar *data, gsize n_data,
+parsed_asn1_attribute (GcrParser *self, GNode *asn, const guchar *data, gsize n_data,
                        const gchar *part, CK_ATTRIBUTE_TYPE type)
 {
        const guchar *value;
@@ -167,13 +168,13 @@ parsed_asn1_attribute (GcrParser *self, ASN1_TYPE asn, const guchar *data, gsize
        g_assert (GCR_IS_PARSER (self));
        g_assert (asn);
        g_assert (data);
-       g_assert (part);
        g_assert (self->pv->parsed_attrs);
 
-       value = egg_asn1_read_content (asn, data, n_data, part, &n_value);
+       value = egg_asn1x_get_raw_value (egg_asn1x_node (asn, part, NULL), &n_value);
        if (value == NULL)
                return FALSE;
 
+       /* TODO: Convert to USG FROM STD */
        gp11_attributes_add_data (self->pv->parsed_attrs, type, value, n_value);
        return TRUE;
 }
@@ -295,10 +296,10 @@ static gint
 parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
 {
        gint res = GCR_ERROR_UNRECOGNIZED;
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
-       guint version;
+       GNode *asn = NULL;
+       gulong version;
 
-       asn = egg_asn1_decode ("PK.RSAPrivateKey", data, n_data);
+       asn = egg_asn1x_create_and_decode (pk_asn1_tab, "RSAPrivateKey", data, n_data);
        if (!asn)
                goto done;
 
@@ -306,13 +307,13 @@ parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
        parsed_ulong (self, CKA_KEY_TYPE, CKK_RSA);
        res = GCR_ERROR_FAILURE;
 
-       if (!egg_asn1_read_uint (asn, "version", &version))
+       if (!egg_asn1x_get_integer_as_ulong (egg_asn1x_node (asn, "version", NULL), &version))
                goto done;
 
        /* We only support simple version */
        if (version != 0) {
                res = GCR_ERROR_UNRECOGNIZED;
-               g_message ("unsupported version of RSA key: %u", version);
+               g_message ("unsupported version of RSA key: %lu", version);
                goto done;
        }
 
@@ -328,9 +329,7 @@ parse_der_private_key_rsa (GcrParser *self, const guchar *data, gsize n_data)
        res = SUCCESS;
 
 done:
-       if (asn)
-               asn1_delete_structure (&asn);
-
+       egg_asn1x_destroy (asn);
        if (res == GCR_ERROR_FAILURE)
                g_message ("invalid RSA key");
 
@@ -345,16 +344,15 @@ static gint
 parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
 {
        gint ret = GCR_ERROR_UNRECOGNIZED;
-       int res;
-       ASN1_TYPE asn;
+       GNode *asn = NULL;
 
-       asn = egg_asn1_decode ("PK.DSAPrivateKey", data, n_data);
+       asn = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivateKey", data, n_data);
        if (!asn)
                goto done;
 
        parsed_clear (self, CKO_PRIVATE_KEY);
        parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
-       res = GCR_ERROR_FAILURE;
+       ret = GCR_ERROR_FAILURE;
 
        if (!parsed_asn1_attribute (self, asn, data, n_data, "p", CKA_PRIME) ||
            !parsed_asn1_attribute (self, asn, data, n_data, "q", CKA_SUBPRIME) ||
@@ -366,9 +364,7 @@ parse_der_private_key_dsa (GcrParser *self, const guchar *data, gsize n_data)
        ret = SUCCESS;
 
 done:
-       if (asn)
-               asn1_delete_structure (&asn);
-
+       egg_asn1x_destroy (asn);
        if (ret == GCR_ERROR_FAILURE)
                g_message ("invalid DSA key");
 
@@ -380,34 +376,30 @@ parse_der_private_key_dsa_parts (GcrParser *self, const guchar *keydata, gsize n
                                  const guchar *params, gsize n_params)
 {
        gint ret = GCR_ERROR_UNRECOGNIZED;
-       int res;
-       ASN1_TYPE asn_params = ASN1_TYPE_EMPTY;
-       ASN1_TYPE asn_key = ASN1_TYPE_EMPTY;
+       GNode *asn_params = NULL;
+       GNode *asn_key = NULL;
 
-       asn_params = egg_asn1_decode ("PK.DSAParameters", params, n_params);
-       asn_key = egg_asn1_decode ("PK.DSAPrivatePart", keydata, n_keydata);
+       asn_params = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAParameters", params, n_params);
+       asn_key = egg_asn1x_create_and_decode (pk_asn1_tab, "DSAPrivatePart", keydata, n_keydata);
        if (!asn_params || !asn_key)
                goto done;
 
        parsed_clear (self, CKO_PRIVATE_KEY);
        parsed_ulong (self, CKA_KEY_TYPE, CKK_DSA);
-       res = GCR_ERROR_FAILURE;
+       ret = GCR_ERROR_FAILURE;
 
        if (!parsed_asn1_attribute (self, asn_params, params, n_params, "p", CKA_PRIME) ||
            !parsed_asn1_attribute (self, asn_params, params, n_params, "q", CKA_SUBPRIME) ||
            !parsed_asn1_attribute (self, asn_params, params, n_params, "g", CKA_BASE) ||
-           !parsed_asn1_attribute (self, asn_key, keydata, n_keydata, "", CKA_VALUE))
+           !parsed_asn1_attribute (self, asn_key, keydata, n_keydata, NULL, CKA_VALUE))
                goto done;
 
        parsed_fire (self);
        ret = SUCCESS;
 
 done:
-       if (asn_key)
-               asn1_delete_structure (&asn_key);
-       if (asn_params)
-               asn1_delete_structure (&asn_params);
-
+       egg_asn1x_destroy (asn_key);
+       egg_asn1x_destroy (asn_params);
        if (ret == GCR_ERROR_FAILURE)
                g_message ("invalid DSA key");
 
@@ -437,7 +429,6 @@ parse_der_private_key (GcrParser *self, const guchar *data, gsize n_data)
 static gint
 parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
        gint ret;
        CK_KEY_TYPE key_type;
        GQuark key_algo;
@@ -445,17 +436,18 @@ parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
        gsize n_keydata;
        const guchar *params;
        gsize n_params;
+       GNode *asn = NULL;
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-8-PrivateKeyInfo", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-PrivateKeyInfo", data, n_data);
        if (!asn)
                goto done;
 
        ret = GCR_ERROR_FAILURE;
        key_type = GP11_INVALID;
 
-       key_algo = egg_asn1_read_oid (asn, "privateKeyAlgorithm.algorithm");
+       key_algo = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "privateKeyAlgorithm", "algorithm", NULL));
        if (!key_algo)
                goto done;
        else if (key_algo == OID_PKIX1_RSA)
@@ -468,12 +460,11 @@ parse_der_pkcs8_plain (GcrParser *self, const guchar *data, gsize n_data)
                goto done;
        }
 
-       keydata = egg_asn1_read_content (asn, data, n_data, "privateKey", &n_keydata);
+       keydata = egg_asn1x_get_raw_value (egg_asn1x_node (asn, "privateKey", NULL), &n_keydata);
        if (!keydata)
                goto done;
 
-       params = egg_asn1_read_element (asn, data, n_data, "privateKeyAlgorithm.parameters",
-                                            &n_params);
+       params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "privateKeyAlgorithm", "parameters", NULL), &n_params);
 
        ret = SUCCESS;
 
@@ -502,8 +493,7 @@ done:
                g_message ("invalid PKCS#8 key");
        }
 
-       if (asn)
-               asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
        return ret;
 }
 
@@ -511,7 +501,7 @@ static gint
 parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 {
        PasswordState pstate = PASSWORD_STATE_INIT;
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gcry_cipher_hd_t cih = NULL;
        gcry_error_t gcry;
        gint ret, r;
@@ -524,18 +514,18 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-8-EncryptedPrivateKeyInfo", data, n_data);
        if (!asn)
                goto done;
 
        ret = GCR_ERROR_FAILURE;
 
        /* Figure out the type of encryption */
-       scheme = egg_asn1_read_oid (asn, "encryptionAlgorithm.algorithm");
+       scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptionAlgorithm", "algorithm", NULL));
        if (!scheme)
                goto done;
 
-       params = egg_asn1_read_element (asn, data, n_data, "encryptionAlgorithm.parameters", &n_params);
+       params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptionAlgorithm", "parameters", NULL), &n_params);
 
        parsed_clear (self, CKO_PRIVATE_KEY);
 
@@ -554,7 +544,7 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
                if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih))
                        break;
 
-               crypted = egg_asn1_read_value (asn, "encryptedData", &n_crypted, (EggAllocator)egg_secure_realloc);
+               crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedData", NULL), egg_secure_realloc, &n_crypted);
                if (!crypted)
                        break;
 
@@ -568,13 +558,12 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
                }
 
                /* Unpad the DER data */
-               l = egg_asn1_element_length (crypted, n_crypted);
+               l = egg_asn1x_element_length (crypted, n_crypted);
                if (l > 0)
                        n_crypted = l;
 
                /* Try to parse the resulting key */
                r = parse_der_pkcs8_plain (self, crypted, n_crypted);
-               egg_secure_free (crypted);
                crypted = NULL;
 
                if (r != GCR_ERROR_UNRECOGNIZED) {
@@ -588,8 +577,7 @@ parse_der_pkcs8_encrypted (GcrParser *self, const guchar *data, gsize n_data)
 done:
        if (cih)
                gcry_cipher_close (cih);
-       if (asn)
-               asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
        egg_secure_free (crypted);
 
        return ret;
@@ -614,18 +602,18 @@ parse_der_pkcs8 (GcrParser *self, const guchar *data, gsize n_data)
 static gint
 parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn;
+       GNode *asn;
        gchar *name;
 
-       asn = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "Certificate", data, n_data);
        if (asn == NULL)
                return GCR_ERROR_UNRECOGNIZED;
 
        parsed_clear (self, CKO_CERTIFICATE);
        parsed_ulong (self, CKA_CERTIFICATE_TYPE, CKC_X_509);
 
-       name = egg_dn_read_part (asn, "tbsCertificate.subject.rdnSequence", "CN");
-       asn1_delete_structure (&asn);
+       name = egg_dn_read_part (egg_asn1x_node (asn, "tbsCertificate", "subject", "rdnSequence", NULL), "CN");
+       egg_asn1x_destroy (asn);
 
        if (name != NULL) {
                parsed_label (self, name);
@@ -645,16 +633,16 @@ parse_der_certificate (GcrParser *self, const guchar *data, gsize n_data)
 static gint
 handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
+       GNode *node;
        gint ret;
-       gchar *part;
        const guchar *certificate;
        gsize n_certificate;
        int i;
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-7-SignedData", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-SignedData", data, n_data);
        if (!asn)
                goto done;
 
@@ -662,14 +650,14 @@ handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
 
        for (i = 0; TRUE; ++i) {
 
-               part = g_strdup_printf ("certificates.?%u", i + 1);
-               certificate = egg_asn1_read_element (asn, data, n_data, part, &n_certificate);
-               g_free (part);
+               node = egg_asn1x_node (asn, "certificates", i + 1, NULL);
 
                /* No more certificates? */
-               if (!certificate)
+               if (node == NULL)
                        break;
 
+               certificate = egg_asn1x_get_raw_element (node, &n_certificate);
+
                ret = parse_der_certificate (self, certificate, n_certificate);
                if (ret != SUCCESS)
                        goto done;
@@ -680,16 +668,15 @@ handle_pkcs7_signed_data (GcrParser *self, const guchar *data, gsize n_data)
        ret = SUCCESS;
 
 done:
-       if (asn)
-               asn1_delete_structure (&asn);
-
+       egg_asn1x_destroy (asn);
        return ret;
 }
 
 static gint
 parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
+       GNode *node;
        gint ret;
        const guchar* content = NULL;
        gsize n_content;
@@ -697,31 +684,33 @@ parse_der_pkcs7 (GcrParser *self, const guchar *data, gsize n_data)
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-7-ContentInfo", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-ContentInfo", data, n_data);
        if (!asn)
                goto done;
 
        ret = GCR_ERROR_FAILURE;
 
-       oid = egg_asn1_read_oid (asn, "contentType");
-       if (!oid)
+       node = egg_asn1x_node (asn, "contentType", NULL);
+       if (!node)
                goto done;
 
+       oid = egg_asn1x_get_oid_as_quark (node);
+       g_return_val_if_fail (oid, GCR_ERROR_FAILURE);
+
        /* Outer most one must just be plain data */
        if (oid != OID_PKCS7_SIGNED_DATA) {
                g_message ("unsupported outer content type in pkcs7: %s", g_quark_to_string (oid));
                goto done;
        }
 
-       content = egg_asn1_read_content (asn, data, n_data, "content", &n_content);
+       content = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "content", NULL), &n_content);
        if (!content)
                goto done;
 
        ret = handle_pkcs7_signed_data (self, content, n_content);
 
 done:
-       if (asn)
-               asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
        return ret;
 }
 
@@ -732,62 +721,61 @@ done:
 static gint
 handle_pkcs12_cert_bag (GcrParser *self, const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
-       const guchar *certificate;
-       gsize n_certificate;
+       GNode *asn = NULL;
+       GNode *asn_content = NULL;
+       guchar *certificate;
+       const guchar *element;
+       gsize n_certificate, n_element;
        gint ret;
 
        ret = GCR_ERROR_UNRECOGNIZED;
-
-       asn = egg_asn1_decode ("PKIX1.pkcs-12-CertBag", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-CertBag", data, n_data);
        if (!asn)
                goto done;
 
        ret = GCR_ERROR_FAILURE;
 
-       certificate = egg_asn1_read_content (asn, data, n_data, "certValue", &n_certificate);
-       if (!certificate)
+       element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "certValue", NULL), &n_element);
+       if (!element)
                goto done;
 
-       /*
-        * Wrapped in an OCTET STRING, so unwrap here, rather than allocating
-        * a whole bunch more memory for a full ASN.1 parsing context.
-        */
-       certificate = egg_asn1_element_content (certificate, n_certificate, &n_certificate);
+       asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element, n_element);
+       if (!asn_content)
+               goto done;
+
+       certificate = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_certificate);
        if (!certificate)
                goto done;
 
        ret = parse_der_certificate (self, certificate, n_certificate);
 
 done:
-       if (asn)
-               asn1_delete_structure (&asn);
-
+       egg_asn1x_destroy (asn_content);
+       egg_asn1x_destroy (asn);
+       g_free (certificate);
        return ret;
 }
 
 static gint
 handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gint ret, r;
-       int res, count = 0;
+       guint count = 0;
        GQuark oid;
        const guchar *element;
        gsize n_element;
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-12-SafeContents", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-SafeContents", data, n_data);
        if (!asn)
                goto done;
 
        ret = GCR_ERROR_FAILURE;
 
        /* Get the number of elements in this bag */
-       res = asn1_number_of_elements (asn, "", &count);
-       if (res != ASN1_SUCCESS)
-               goto done;
+       count = egg_asn1x_count (asn);
 
        /*
         * Now inside each bag are multiple elements. Who comes up
@@ -801,11 +789,11 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
         */
        if (count >= 1) {
 
-               oid = egg_asn1_read_oid (asn, "?1.bagId");
+               oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, 1, "bagId", NULL));
                if (!oid)
                        goto done;
 
-               element = egg_asn1_read_content (asn, data, n_data, "?1.bagValue", &n_element);
+               element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, 1, "bagValue", NULL), &n_element);
                if (!element)
                        goto done;
 
@@ -835,9 +823,7 @@ handle_pkcs12_bag (GcrParser *self, const guchar *data, gsize n_data)
        ret = SUCCESS;
 
 done:
-       if (asn)
-               asn1_delete_structure (&asn);
-
+       egg_asn1x_destroy (asn);
        return ret;
 }
 
@@ -845,7 +831,7 @@ static gint
 handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 {
        PasswordState pstate = PASSWORD_STATE_INIT;
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
        gcry_cipher_hd_t cih = NULL;
        gcry_error_t gcry;
        guchar *crypted = NULL;
@@ -858,18 +844,18 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-7-EncryptedData", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-EncryptedData", data, n_data);
        if (!asn)
                goto done;
 
        ret = GCR_ERROR_FAILURE;
 
        /* Check the encryption schema OID */
-       scheme = egg_asn1_read_oid (asn, "encryptedContentInfo.contentEncryptionAlgorithm.algorithm");
+       scheme = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "algorithm", NULL));
        if (!scheme)
                goto done;
 
-       params = egg_asn1_read_element (asn, data, n_data, "encryptedContentInfo.contentEncryptionAlgorithm.parameters", &n_params);
+       params = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "encryptedContentInfo", "contentEncryptionAlgorithm", "parameters", NULL), &n_params);
        if (!params)
                goto done;
 
@@ -892,8 +878,8 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
                        goto done;
                }
 
-               crypted = egg_asn1_read_value (asn, "encryptedContentInfo.encryptedContent",
-                                              &n_crypted, (EggAllocator)egg_secure_realloc);
+               crypted = egg_asn1x_get_string_as_raw (egg_asn1x_node (asn, "encryptedContentInfo", "encryptedContent", NULL),
+                                                      egg_secure_realloc, &n_crypted);
                if (!crypted)
                        goto done;
 
@@ -907,7 +893,7 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
                }
 
                /* Unpad the DER data */
-               l = egg_asn1_element_length (crypted, n_crypted);
+               l = egg_asn1x_element_length (crypted, n_crypted);
                if (l > 0)
                        n_crypted = l;
 
@@ -927,27 +913,27 @@ handle_pkcs12_encrypted_bag (GcrParser *self, const guchar *data, gsize n_data)
 done:
        if (cih)
                gcry_cipher_close (cih);
-       if (asn)
-               asn1_delete_structure (&asn);
+       egg_asn1x_destroy (asn);
        egg_secure_free (crypted);
-
        return ret;
 }
 
 static gint
 handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
+       GNode *asn_content = NULL;
        gint ret, r;
        const guchar *bag;
-       gsize n_bag;
-       gchar *part;
+       guchar *content = NULL;
+       gsize n_bag, n_content;
        GQuark oid;
        guint i;
+       GNode *node;
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-12-AuthenticatedSafe", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-AuthenticatedSafe", data, n_data);
        if (!asn)
                goto done;
 
@@ -957,34 +943,35 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
         * Inside each PKCS12 safe there are multiple bags.
         */
        for (i = 0; TRUE; ++i) {
-
-               part = g_strdup_printf ("?%u.contentType", i + 1);
-               oid = egg_asn1_read_oid (asn, part);
-               g_free (part);
+               node = egg_asn1x_node (asn, i + 1, "contentType", NULL);
 
                /* All done? no more bags */
-               if (!oid)
+               if (!node)
                        break;
 
-               part = g_strdup_printf ("?%u.content", i + 1);
-               bag = egg_asn1_read_content (asn, data, n_data, part, &n_bag);
-               g_free (part);
+               oid = egg_asn1x_get_oid_as_quark (node);
 
-               if (!bag) /* A parse error */
+               node = egg_asn1x_node (asn, i + 1, "content", NULL);
+               if (!node)
                        goto done;
 
+               bag = egg_asn1x_get_raw_element (node, &n_bag);
+               g_return_val_if_fail (bag, ret);
+
                /* A non encrypted bag, just parse */
                if (oid == OID_PKCS7_DATA) {
 
-                       /*
-                        * Wrapped in an OCTET STRING, so unwrap here, rather than allocating
-                        * a whole bunch more memory for a full ASN.1 parsing context.
-                        */
-                       bag = egg_asn1_element_content (bag, n_bag, &n_bag);
-                       if (!bag)
+                       egg_asn1x_destroy (asn_content);
+                       asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", bag, n_bag);
+                       if (!asn_content)
+                               goto done;
+
+                       g_free (content);
+                       content = egg_asn1x_get_string_as_raw (asn_content, NULL, &n_content);
+                       if (!content)
                                goto done;
 
-                       r = handle_pkcs12_bag (self, bag, n_bag);
+                       r = handle_pkcs12_bag (self, content, n_content);
 
                /* Encrypted data first needs decryption */
                } else if (oid == OID_PKCS7_ENCRYPTED_DATA) {
@@ -1005,28 +992,32 @@ handle_pkcs12_safe (GcrParser *self, const guchar *data, gsize n_data)
        ret = SUCCESS;
 
 done:
-       if (asn)
-               asn1_delete_structure (&asn);
-
+       egg_asn1x_destroy (asn);
+       egg_asn1x_destroy (asn_content);
+       g_free (content);
        return ret;
 }
 
 static gint
 parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
 {
-       ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+       GNode *asn = NULL;
+       GNode *asn_content = NULL;
        gint ret;
-       const guchar* content = NULL;
-       gsize n_content;
+       const guchar* element = NULL;
+       guchar *content = NULL;
+       gsize n_element, n_content;
        GQuark oid;
 
        ret = GCR_ERROR_UNRECOGNIZED;
 
-       asn = egg_asn1_decode ("PKIX1.pkcs-12-PFX", data, n_data);
+       asn = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-12-PFX", data, n_data);
        if (!asn)
                goto done;
 
-       oid = egg_asn1_read_oid (asn, "authSafe.contentType");
+       ret = GCR_ERROR_FAILURE;
+
+       oid = egg_asn1x_get_oid_as_quark (egg_asn1x_node (asn, "authSafe", "contentType", NULL));
        if (!oid)
                goto done;
 
@@ -1036,23 +1027,24 @@ parse_der_pkcs12 (GcrParser *self, const guchar *data, gsize n_data)
                goto done;
        }
 
-       content = egg_asn1_read_content (asn, data, n_data, "authSafe.content", &n_content);
-       if (!content)
+       element = egg_asn1x_get_raw_element (egg_asn1x_node (asn, "authSafe", "content", NULL), &n_element);
+       if (!element)
                goto done;
 
-       /*
-        * Wrapped in an OCTET STRING, so unwrap here, rather than allocating
-        * a whole bunch more memory for a full ASN.1 parsing context.
-        */
-       content = egg_asn1_element_content (content, n_content, &n_content);
+       asn_content = egg_asn1x_create_and_decode (pkix_asn1_tab, "pkcs-7-Data", element, n_element);
+       if (!asn_content)
+               goto done;
+
+       content = egg_asn1x_get_string_as_raw (asn_content, g_realloc, &n_content);
        if (!content)
                goto done;
 
        ret = handle_pkcs12_safe (self, content, n_content);
 
 done:
-       if (asn)
-               asn1_delete_structure (&asn);
+       g_free (content);
+       egg_asn1x_destroy (asn_content);
+       egg_asn1x_destroy (asn);
        return ret;
 }
 
@@ -1168,7 +1160,7 @@ handle_encrypted_pem (GcrParser *self, GQuark type, gint subformat,
                g_assert (decrypted);
 
                /* Unpad the DER data */
-               l = egg_asn1_element_length (decrypted, n_decrypted);
+               l = egg_asn1x_element_length (decrypted, n_decrypted);
                if (l > 0)
                        n_decrypted = l;
 
index 77ba059..b72d7c7 100644 (file)
@@ -25,7 +25,6 @@
 #include "gcr-internal.h"
 #include "gcr-simple-certificate.h"
 
-#include "egg/egg-asn1.h"
 #include "egg/egg-hex.h"
 
 #include <string.h>