--- /dev/null
+
+noinst_LTLIBRARIES = \
+ libegg.la \
+ libegg-buffer.la \
+ libegg-creds.la \
+ libegg-secure.la
+
+BUILT_SOURCES = \
+ asn1-def-pk.h asn1-def-pkix.h
+
+INCLUDES = \
+ -I$(top_srcdir)
+ -I$(top_builddir)
+
+libegg_la_CFLAGS = \
+ $(LIBTASN1_CFLAGS) \
+ $(GLIB_CFLAGS)
+
+libegg_la_SOURCES = \
+ egg-asn1.c egg-asn1.h \
+ egg-buffer.c egg-buffer.h \
+ egg-unix-credentials.c egg-unix-credentials.h \
+ egg-secure-memory.c egg-secure-memory.h
+
+asn1-def-pk.h: pk.asn
+ asn1Parser -o asn1-def-pk.h pk.asn
+
+asn1-def-pkix.h: pkix.asn
+ asn1Parser -o asn1-def-pkix.h pkix.asn
+
+EXTRA_DIST = \
+ pkix.asn \
+ pk.asn
+
+# --------------------------------------------------------------------
+# COMMON STUFF COMPILED INTO SMALLER COMPONENTS
+
+libegg_secure_la_SOURCES = \
+ egg-secure-memory.c egg-secure-memory.h
+
+libegg_buffer_la_SOURCES = \
+ egg-buffer.c egg-buffer.h
+
+libegg_creds_la_SOURCES = \
+ egg-unix-credentials.c egg-unix-credentials.h
+
+# -------------------------------------------------------------------
+
+if WITH_TESTS
+TESTS_DIR = tests
+else
+TESTS_DIR =
+endif
+
+SUBDIRS = . $(TESTS_DIR)
--- /dev/null
+/* -*- 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 <libtasn1.h>
+
+#include <string.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);
+
+ 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 if (len) {
+ *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;
+}
+
+gboolean
+egg_asn1_read_boolean (ASN1_TYPE asn, const gchar *part, gboolean *val)
+{
+ gchar buffer[32];
+ int n_buffer = sizeof (buffer) - 1;
+ int res;
+
+ memset (buffer, 0, sizeof (buffer));
+
+ res = asn1_read_value (asn, part, buffer, &n_buffer);
+ if (res != ASN1_SUCCESS)
+ return FALSE;
+
+ if (g_ascii_strcasecmp (buffer, "TRUE") == 0)
+ *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;
+ gsize n_buf;
+
+ buf = egg_asn1_read_value (asn, part, &n_buf, NULL);
+ if (!buf)
+ return 0;
+
+ quark = g_quark_try_string ((gchar*)buf);
+ g_free (buf);
+
+ if (quark == 0)
+ quark = g_quark_from_static_string ("0.UNKNOWN.OID");
+
+ 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
+
+time_t
+egg_asn1_parse_utc_time (const gchar *time)
+{
+ struct tm when;
+ guint n_time;
+ time_t result;
+ const char *p, *e;
+ int year;
+
+ g_assert (time);
+ n_time = strlen (time);
+
+ /* YYMMDDhhmmss.ffff Z | +0000 */
+ if (n_time < 6 || n_time >= 28)
+ return -1;
+
+ /* Reset everything to default legal values */
+ memset (&when, 0, sizeof (when));
+ 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 -1;
+
+ /* Make sure all that got parsed */
+ if (p != e)
+ return -1;
+
+ /* 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 */
+
+ /* Covnvert to seconds since epoch */
+ result = timegm (&when);
+
+ /* 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)
+ result -= off;
+ else
+ result += off;
+ }
+
+ /* Make sure everything got parsed */
+ if (p != e)
+ return -1;
+
+ return result;
+}
+
+time_t
+egg_asn1_parse_general_time (const gchar *time)
+{
+ struct tm when;
+ guint n_time;
+ time_t result;
+ const char *p, *e;
+
+ g_assert (time);
+ n_time = strlen (time);
+
+ /* YYYYMMDDhhmmss.ffff Z | +0000 */
+ if (n_time < 8 || n_time >= 30)
+ return -1;
+
+ /* Reset everything to default legal values */
+ memset (&when, 0, sizeof (when));
+ 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 -1;
+
+ /* Make sure all that got parsed */
+ if (p != e)
+ return -1;
+
+ /* Covnvert to seconds since epoch */
+ result = timegm (&when);
+
+ /* 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)
+ result -= off;
+ else
+ result += off;
+ }
+
+ /* Make sure everything got parsed */
+ if (p != e)
+ return -1;
+
+ return result;
+}
+
+gboolean
+egg_asn1_read_time (ASN1_TYPE asn, const gchar *part, time_t *val)
+{
+ #define MAX_TIME 1024
+ gchar ttime[MAX_TIME];
+ gchar *name;
+ int len, res;
+
+ len = sizeof (ttime) - 1;
+ res = asn1_read_value (asn, part, ttime, &len);
+ if (res != ASN1_SUCCESS)
+ return FALSE;
+
+ /* CHOICE */
+ if (strcmp (ttime, "generalTime") == 0) {
+ 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;
+
+ *val = egg_asn1_parse_general_time (ttime);
+
+ /* UTCTIME */
+ } else {
+ 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;
+
+ *val = egg_asn1_parse_utc_time (ttime);
+ }
+
+ if (*val < (time_t)0)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/* -------------------------------------------------------------------------------
+ * Reading DN's
+ */
+
+typedef struct _PrintableOid {
+ GQuark oid;
+ const gchar *oidstr;
+ const gchar *display;
+ gboolean is_choice;
+} PrintableOid;
+
+static PrintableOid printable_oids[] = {
+ { 0, "0.9.2342.19200300.100.1.25", "DC", FALSE },
+ { 0, "0.9.2342.19200300.100.1.1", "UID", TRUE },
+
+ { 0, "1.2.840.113549.1.9.1", "EMAIL", FALSE },
+ { 0, "1.2.840.113549.1.9.7", NULL, TRUE },
+ { 0, "1.2.840.113549.1.9.20", NULL, FALSE },
+
+ { 0, "1.3.6.1.5.5.7.9.1", "dateOfBirth", FALSE },
+ { 0, "1.3.6.1.5.5.7.9.2", "placeOfBirth", FALSE },
+ { 0, "1.3.6.1.5.5.7.9.3", "gender", FALSE },
+ { 0, "1.3.6.1.5.5.7.9.4", "countryOfCitizenship", FALSE },
+ { 0, "1.3.6.1.5.5.7.9.5", "countryOfResidence", FALSE },
+
+ { 0, "2.5.4.3", "CN", TRUE },
+ { 0, "2.5.4.4", "surName", TRUE },
+ { 0, "2.5.4.5", "serialNumber", FALSE },
+ { 0, "2.5.4.6", "C", FALSE, },
+ { 0, "2.5.4.7", "L", TRUE },
+ { 0, "2.5.4.8", "ST", TRUE },
+ { 0, "2.5.4.9", "STREET", TRUE },
+ { 0, "2.5.4.10", "O", TRUE },
+ { 0, "2.5.4.11", "OU", TRUE },
+ { 0, "2.5.4.12", "T", TRUE },
+ { 0, "2.5.4.20", "telephoneNumber", FALSE },
+ { 0, "2.5.4.42", "givenName", TRUE },
+ { 0, "2.5.4.43", "initials", TRUE },
+ { 0, "2.5.4.44", "generationQualifier", TRUE },
+ { 0, "2.5.4.46", "dnQualifier", FALSE },
+ { 0, "2.5.4.65", "pseudonym", TRUE },
+
+ { 0, NULL, NULL, FALSE }
+};
+
+static void
+init_printable_oids (void)
+{
+ static volatile gsize inited_oids = 0;
+ int i;
+
+ if (g_once_init_enter (&inited_oids)) {
+ for (i = 0; printable_oids[i].oidstr != NULL; ++i)
+ printable_oids[i].oid = g_quark_from_static_string (printable_oids[i].oidstr);
+ g_once_init_leave (&inited_oids, 1);
+ }
+}
+
+static PrintableOid*
+dn_find_printable (GQuark oid)
+{
+ int i;
+
+ g_return_val_if_fail (oid != 0, NULL);
+
+ for (i = 0; printable_oids[i].oidstr != NULL; ++i) {
+ if (printable_oids[i].oid == oid)
+ return &printable_oids[i];
+ }
+
+ return NULL;
+}
+
+static const char HEXC[] = "0123456789ABCDEF";
+
+static gchar*
+dn_print_hex_value (const guchar *data, gsize len)
+{
+ GString *result = g_string_sized_new (len * 2 + 1);
+ gsize i;
+
+ g_string_append_c (result, '#');
+ for (i = 0; i < len; ++i) {
+ g_string_append_c (result, HEXC[data[i] >> 4 & 0xf]);
+ g_string_append_c (result, HEXC[data[i] & 0xf]);
+ }
+
+ return g_string_free (result, FALSE);
+}
+
+static gchar*
+dn_print_oid_value_parsed (PrintableOid *printable, guchar *data, gsize len)
+{
+ const gchar *asn_name;
+ ASN1_TYPE asn1;
+ gchar *part;
+ gchar *value;
+
+ g_assert (printable);
+ g_assert (data);
+ g_assert (len);
+ g_assert (printable->oid);
+
+ asn_name = asn1_find_structure_from_oid (egg_asn1_get_pkix_asn1type (),
+ printable->oidstr);
+ 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);
+
+ if (!asn1) {
+ g_message ("couldn't decode value for OID: %s", printable->oidstr);
+ return NULL;
+ }
+
+ value = (gchar*)egg_asn1_read_value (asn1, "", NULL, NULL);
+
+ /*
+ * If it's a choice element, then we have to read depending
+ * on what's there.
+ */
+ if (value && printable->is_choice) {
+ if (strcmp ("printableString", value) == 0 ||
+ strcmp ("ia5String", value) == 0 ||
+ strcmp ("utf8String", value) == 0 ||
+ strcmp ("teletexString", value) == 0) {
+ part = value;
+ value = (gchar*)egg_asn1_read_value (asn1, part, NULL, NULL);
+ g_free (part);
+ } else {
+ g_free (value);
+ return NULL;
+ }
+ }
+
+ if (!value) {
+ g_message ("couldn't read value for OID: %s", printable->oidstr);
+ return NULL;
+ }
+
+ /*
+ * Now we make sure it's UTF-8.
+ */
+ if (!g_utf8_validate (value, -1, NULL)) {
+ gchar *hex = dn_print_hex_value ((guchar*)value, strlen (value));
+ g_free (value);
+ value = hex;
+ }
+
+ return value;
+}
+
+static gchar*
+dn_print_oid_value (PrintableOid *printable, guchar *data, gsize len)
+{
+ gchar *value;
+
+ g_assert (data);
+ g_assert (len);
+
+ if (printable) {
+ value = dn_print_oid_value_parsed (printable, data, len);
+ if (value != NULL)
+ return value;
+ }
+
+ return dn_print_hex_value (data, len);
+}
+
+static gchar*
+dn_parse_rdn (ASN1_TYPE asn, const gchar *part)
+{
+ PrintableOid *printable;
+ GQuark oid;
+ gchar *path;
+ guchar *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);
+
+ printable = dn_find_printable (oid);
+
+ g_return_val_if_fail (value, NULL);
+ display = dn_print_oid_value (printable, value, n_value);
+
+ result = g_strconcat (printable ? printable->display : g_quark_to_string (oid),
+ "=", display, NULL);
+ g_free (display);
+
+ return result;
+}
+
+gchar*
+egg_asn1_read_dn (ASN1_TYPE asn, const gchar *part)
+{
+ gboolean done = FALSE;
+ GString *result;
+ gchar *path;
+ gchar *rdn;
+ gint i, j;
+
+ g_return_val_if_fail (asn, NULL);
+ g_return_val_if_fail (part, NULL);
+
+ init_printable_oids ();
+
+ result = g_string_sized_new (64);
+
+ /* Each (possibly multi valued) RDN */
+ for (i = 1; !done; ++i) {
+
+ /* 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) {
+ done = j == 1;
+ break;
+ }
+
+ /* Account for multi valued RDNs */
+ if (j > 1)
+ g_string_append (result, "+");
+ else if (i > 1)
+ g_string_append (result, ", ");
+
+ g_string_append (result, rdn);
+ g_free (rdn);
+ }
+ }
+
+ /* Returns null when string is empty */
+ return g_string_free (result, (result->len == 0));
+}
+
+gchar*
+egg_asn1_read_dn_part (ASN1_TYPE asn, const gchar *part, const gchar *match)
+{
+ PrintableOid *printable = NULL;
+ gboolean done = FALSE;
+ guchar *value;
+ gsize n_value;
+ gchar *path;
+ 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);
+
+ init_printable_oids ();
+
+ /* Each (possibly multi valued) RDN */
+ for (i = 1; !done; ++i) {
+
+ /* 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) {
+ done = j == 1;
+ break;
+ }
+
+ /* Does it match either the OID or the displayable? */
+ if (g_ascii_strcasecmp (g_quark_to_string (oid), match) != 0) {
+ printable = dn_find_printable (oid);
+ if (!printable || !printable->display ||
+ !g_ascii_strcasecmp (printable->display, match) == 0)
+ 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);
+
+ g_return_val_if_fail (value, NULL);
+ return dn_print_oid_value (printable, value, n_value);
+ }
+ }
+
+ return NULL;
+}
--- /dev/null
+/* -*- 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>
+
+typedef void* (*EggAllocator) (void* p, unsigned long len);
+
+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);
+
+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);
+
+gchar* egg_asn1_read_dn (ASN1_TYPE asn, const gchar *part);
+
+gchar* egg_asn1_read_dn_part (ASN1_TYPE asn, const gchar *part, const gchar *match);
+
+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_parse_utc_time (const gchar* value);
+
+glong egg_asn1_parse_general_time (const gchar* value);
+
+#endif /*EGG_ASN1_H_*/
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-buffer.c - Generic data buffer, used by openssh, gnome-keyring
+
+ 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 <string.h>
+#include <stdarg.h>
+
+#include "egg-buffer.h"
+
+#define DEFAULT_ALLOCATOR ((EggBufferAllocator)realloc)
+
+int
+egg_buffer_init (EggBuffer *buffer, size_t reserve)
+{
+ return egg_buffer_init_full (buffer, reserve, NULL);
+}
+
+int
+egg_buffer_init_full (EggBuffer *buffer, size_t reserve, EggBufferAllocator allocator)
+{
+ memset (buffer, 0, sizeof (*buffer));
+
+ if (!allocator)
+ allocator = DEFAULT_ALLOCATOR;
+ if (reserve == 0)
+ reserve = 64;
+
+ buffer->buf = (allocator) (NULL, reserve);
+ if (!buffer->buf) {
+ buffer->failures++;
+ return 0;
+ }
+
+ buffer->len = 0;
+ buffer->allocated_len = reserve;
+ buffer->failures = 0;
+ buffer->allocator = allocator;
+
+ return 1;
+}
+
+void
+egg_buffer_init_static (EggBuffer* buffer, unsigned char *buf, size_t len)
+{
+ memset (buffer, 0, sizeof (*buffer));
+
+ buffer->buf = buf;
+ buffer->len = len;
+ buffer->allocated_len = len;
+ buffer->failures = 0;
+
+ /* A null allocator, and the buffer can't change in size */
+ buffer->allocator = NULL;
+}
+
+void
+egg_buffer_init_allocated (EggBuffer *buffer, unsigned char *buf, size_t len,
+ EggBufferAllocator allocator)
+{
+ memset (buffer, 0, sizeof (*buffer));
+
+ if (!allocator)
+ allocator = DEFAULT_ALLOCATOR;
+
+ buffer->buf = buf;
+ buffer->len = len;
+ buffer->allocated_len = len;
+ buffer->failures = 0;
+ buffer->allocator = allocator;
+}
+
+void
+egg_buffer_reset (EggBuffer *buffer)
+{
+ memset (buffer->buf, 0, buffer->allocated_len);
+ buffer->len = 0;
+ buffer->failures = 0;
+}
+
+void
+egg_buffer_uninit (EggBuffer *buffer)
+{
+ if (!buffer)
+ return;
+
+ /*
+ * Free the memory block using allocator. If no allocator,
+ * then this memory is ownerd elsewhere and not to be freed.
+ */
+ if (buffer->buf && buffer->allocator)
+ (buffer->allocator) (buffer->buf, 0);
+
+ memset (buffer, 0, sizeof (*buffer));
+}
+
+int
+egg_buffer_set_allocator (EggBuffer *buffer, EggBufferAllocator allocator)
+{
+ unsigned char *buf;
+
+ if (!allocator)
+ allocator = DEFAULT_ALLOCATOR;
+ if (buffer->allocator == allocator)
+ return 1;
+
+ /* Reallocate memory block using new allocator */
+ buf = (allocator) (NULL, buffer->allocated_len);
+ if (!buf)
+ return 0;
+
+ /* Copy stuff and free old memory */
+ memcpy (buf, buffer->buf, buffer->allocated_len);
+
+ /* If old wasn't static, then free it */
+ if (buffer->allocator)
+ (buffer->allocator) (buffer->buf, 0);
+
+ buffer->buf = buf;
+ buffer->allocator = allocator;
+
+ return 1;
+}
+
+int
+egg_buffer_equal (EggBuffer *b1, EggBuffer *b2)
+{
+ if (b1->len != b2->len)
+ return 0;
+ return memcmp (b1->buf, b2->buf, b1->len) == 0;
+}
+
+int
+egg_buffer_reserve (EggBuffer *buffer, size_t len)
+{
+ unsigned char *newbuf;
+ size_t newlen;
+
+ if (len < buffer->allocated_len)
+ return 1;
+
+ /* Calculate a new length, minimize number of buffer allocations */
+ newlen = buffer->allocated_len * 2;
+ if (len > newlen)
+ newlen += len;
+
+ /* Memory owned elsewhere can't be reallocated */
+ if (!buffer->allocator) {
+ buffer->failures++;
+ return 0;
+ }
+
+ /* Reallocate built in buffer using allocator */
+ newbuf = (buffer->allocator) (buffer->buf, newlen);
+ if (!newbuf) {
+ buffer->failures++;
+ return 0;
+ }
+
+ buffer->buf = newbuf;
+ buffer->allocated_len = newlen;
+
+ return 1;
+}
+
+int
+egg_buffer_resize (EggBuffer *buffer, size_t len)
+{
+ if (!egg_buffer_reserve (buffer, len))
+ return 0;
+
+ buffer->len = len;
+ return 1;
+}
+
+unsigned char*
+egg_buffer_add_empty (EggBuffer *buffer, size_t len)
+{
+ size_t pos = buffer->len;
+ if (!egg_buffer_reserve (buffer, buffer->len + len))
+ return NULL;
+ buffer->len += len;
+ return buffer->buf + pos;
+}
+
+int
+egg_buffer_append (EggBuffer *buffer, const unsigned char *val,
+ size_t len)
+{
+ if (!egg_buffer_reserve (buffer, buffer->len + len))
+ return 0; /* failures already incremented */
+ memcpy (buffer->buf + buffer->len, val, len);
+ buffer->len += len;
+ return 1;
+}
+
+int
+egg_buffer_add_byte (EggBuffer *buffer, unsigned char val)
+{
+ if (!egg_buffer_reserve (buffer, buffer->len + 1))
+ return 0; /* failures already incremented */
+ buffer->buf[buffer->len] = val;
+ buffer->len++;
+ return 1;
+}
+
+int
+egg_buffer_get_byte (EggBuffer *buffer, size_t offset,
+ size_t *next_offset, unsigned char *val)
+{
+ unsigned char *ptr;
+ if (buffer->len < 1 || offset > buffer->len - 1) {
+ buffer->failures++;
+ return 0;
+ }
+ ptr = (unsigned char*)buffer->buf + offset;
+ if (val != NULL)
+ *val = *ptr;
+ if (next_offset != NULL)
+ *next_offset = offset + 1;
+ return 1;
+}
+
+void
+egg_buffer_encode_uint16 (unsigned char* buf, uint16_t val)
+{
+ buf[0] = (val >> 8) & 0xff;
+ buf[1] = (val >> 0) & 0xff;
+}
+
+uint16_t
+egg_buffer_decode_uint16 (unsigned char* buf)
+{
+ uint16_t val = buf[0] << 8 | buf[1];
+ return val;
+}
+
+int
+egg_buffer_add_uint16 (EggBuffer *buffer, uint16_t val)
+{
+ if (!egg_buffer_reserve (buffer, buffer->len + 2))
+ return 0; /* failures already incremented */
+ buffer->len += 2;
+ egg_buffer_set_uint16 (buffer, buffer->len - 2, val);
+ return 1;
+}
+
+int
+egg_buffer_set_uint16 (EggBuffer *buffer, size_t offset, uint16_t val)
+{
+ unsigned char *ptr;
+ if (buffer->len < 2 || offset > buffer->len - 2) {
+ buffer->failures++;
+ return 0;
+ }
+ ptr = (unsigned char*)buffer->buf + offset;
+ egg_buffer_encode_uint16 (ptr, val);
+ return 1;
+}
+
+int
+egg_buffer_get_uint16 (EggBuffer *buffer, size_t offset,
+ size_t *next_offset, uint16_t *val)
+{
+ unsigned char *ptr;
+ if (buffer->len < 2 || offset > buffer->len - 2) {
+ buffer->failures++;
+ return 0;
+ }
+ ptr = (unsigned char*)buffer->buf + offset;
+ if (val != NULL)
+ *val = egg_buffer_decode_uint16 (ptr);
+ if (next_offset != NULL)
+ *next_offset = offset + 2;
+ return 1;
+}
+
+void
+egg_buffer_encode_uint32 (unsigned char* buf, uint32_t val)
+{
+ buf[0] = (val >> 24) & 0xff;
+ buf[1] = (val >> 16) & 0xff;
+ buf[2] = (val >> 8) & 0xff;
+ buf[3] = (val >> 0) & 0xff;
+}
+
+uint32_t
+egg_buffer_decode_uint32 (unsigned char* ptr)
+{
+ uint32_t val = ptr[0] << 24 | ptr[1] << 16 | ptr[2] << 8 | ptr[3];
+ return val;
+}
+
+int
+egg_buffer_add_uint32 (EggBuffer *buffer, uint32_t val)
+{
+ if (!egg_buffer_reserve (buffer, buffer->len + 4))
+ return 0; /* failures already incremented */
+ buffer->len += 4;
+ egg_buffer_set_uint32 (buffer, buffer->len - 4, val);
+ return 1;
+}
+
+int
+egg_buffer_set_uint32 (EggBuffer *buffer, size_t offset, uint32_t val)
+{
+ unsigned char *ptr;
+ if (buffer->len < 4 || offset > buffer->len - 4) {
+ buffer->failures++;
+ return 0;
+ }
+ ptr = (unsigned char*)buffer->buf + offset;
+ egg_buffer_encode_uint32 (ptr, val);
+ return 1;
+}
+
+int
+egg_buffer_get_uint32 (EggBuffer *buffer, size_t offset, size_t *next_offset,
+ uint32_t *val)
+{
+ unsigned char *ptr;
+ if (buffer->len < 4 || offset > buffer->len - 4) {
+ buffer->failures++;
+ return 0;
+ }
+ ptr = (unsigned char*)buffer->buf + offset;
+ if (val != NULL)
+ *val = egg_buffer_decode_uint32 (ptr);
+ if (next_offset != NULL)
+ *next_offset = offset + 4;
+ return 1;
+}
+
+int
+egg_buffer_add_uint64 (EggBuffer *buffer, uint64_t val)
+{
+ if (!egg_buffer_add_uint32 (buffer, ((val >> 32) & 0xffffffff)))
+ return 0;
+ return egg_buffer_add_uint32 (buffer, (val & 0xffffffff));
+}
+
+int
+egg_buffer_get_uint64 (EggBuffer *buffer, size_t offset,
+ size_t *next_offset, uint64_t *val)
+{
+ uint32_t a, b;
+ if (!egg_buffer_get_uint32 (buffer, offset, &offset, &a))
+ return 0;
+ if (!egg_buffer_get_uint32 (buffer, offset, &offset, &b))
+ return 0;
+ if (val != NULL)
+ *val = ((uint64_t)a) << 32 | b;
+ if (next_offset != NULL)
+ *next_offset = offset;
+ return 1;
+}
+
+int
+egg_buffer_add_byte_array (EggBuffer *buffer, const unsigned char *val,
+ size_t len)
+{
+ if (val == NULL)
+ return egg_buffer_add_uint32 (buffer, 0xffffffff);
+ if (len >= 0x7fffffff) {
+ buffer->failures++;
+ return 0;
+ }
+ if (!egg_buffer_add_uint32 (buffer, len))
+ return 0;
+ return egg_buffer_append (buffer, val, len);
+}
+
+unsigned char*
+egg_buffer_add_byte_array_empty (EggBuffer *buffer, size_t vlen)
+{
+ if (vlen >= 0x7fffffff) {
+ buffer->failures++;
+ return NULL;
+ }
+ if (!egg_buffer_add_uint32 (buffer, vlen))
+ return NULL;
+ return egg_buffer_add_empty (buffer, vlen);
+}
+
+int
+egg_buffer_get_byte_array (EggBuffer *buffer, size_t offset,
+ size_t *next_offset, const unsigned char **val,
+ size_t *vlen)
+{
+ uint32_t len;
+ if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len))
+ return 0;
+ if (len == 0xffffffff) {
+ if (next_offset)
+ *next_offset = offset;
+ if (val)
+ *val = NULL;
+ if (vlen)
+ *vlen = 0;
+ return 1;
+ } else if (len >= 0x7fffffff) {
+ buffer->failures++;
+ return 0;
+ }
+
+ if (buffer->len < len || offset > buffer->len - len) {
+ buffer->failures++;
+ return 0;
+ }
+
+ if (val)
+ *val = buffer->buf + offset;
+ if (vlen)
+ *vlen = len;
+ if (next_offset)
+ *next_offset = offset + len;
+
+ return 1;
+}
+
+int
+egg_buffer_add_string (EggBuffer *buffer, const char *str)
+{
+ if (str == NULL) {
+ return egg_buffer_add_uint32 (buffer, 0xffffffff);
+ } else {
+ size_t len = strlen (str);
+ if (len >= 0x7fffffff)
+ return 0;
+ if (!egg_buffer_add_uint32 (buffer, len))
+ return 0;
+ return egg_buffer_append (buffer, (unsigned char*)str, len);
+ }
+}
+
+int
+egg_buffer_get_string (EggBuffer *buffer, size_t offset, size_t *next_offset,
+ char **str_ret, EggBufferAllocator allocator)
+{
+ uint32_t len;
+
+ if (!allocator)
+ allocator = buffer->allocator;
+ if (!allocator)
+ allocator = DEFAULT_ALLOCATOR;
+
+ if (!egg_buffer_get_uint32 (buffer, offset, &offset, &len)) {
+ return 0;
+ }
+ if (len == 0xffffffff) {
+ *next_offset = offset;
+ *str_ret = NULL;
+ return 1;
+ } else if (len >= 0x7fffffff) {
+ return 0;
+ }
+
+ if (buffer->len < len ||
+ offset > buffer->len - len) {
+ return 0;
+ }
+
+ /* Make sure no null characters in string */
+ if (memchr (buffer->buf + offset, 0, len) != NULL)
+ return 0;
+
+ /* The passed allocator may be for non-pageable memory */
+ *str_ret = (allocator) (NULL, len + 1);
+ if (!*str_ret)
+ return 0;
+ memcpy (*str_ret, buffer->buf + offset, len);
+
+ /* Always zero terminate */
+ (*str_ret)[len] = 0;
+ *next_offset = offset + len;
+
+ return 1;
+}
+
+int
+egg_buffer_add_stringv (EggBuffer *buffer, const char** strv)
+{
+ const char **v;
+ uint32_t n = 0;
+
+ if (!strv)
+ return 0;
+
+ /* Add the number of strings coming */
+ for (v = strv; *v; ++v)
+ ++n;
+ if (!egg_buffer_add_uint32 (buffer, n))
+ return 0;
+
+ /* Add the individual strings */
+ for (v = strv; *v; ++v) {
+ if (!egg_buffer_add_string (buffer, *v))
+ return 0;
+ }
+
+ return 1;
+}
+
+int
+egg_buffer_get_stringv (EggBuffer *buffer, size_t offset, size_t *next_offset,
+ char ***strv_ret, EggBufferAllocator allocator)
+{
+ uint32_t n, i, j;
+ size_t len;
+
+ if (!allocator)
+ allocator = buffer->allocator;
+ if (!allocator)
+ allocator = DEFAULT_ALLOCATOR;
+
+ /* First the number of environment variable lines */
+ if (!egg_buffer_get_uint32 (buffer, offset, &offset, &n))
+ return 0;
+
+ /* Then that number of strings */
+ len = (n + 1) * sizeof (char*);
+ *strv_ret = (char**)(allocator) (NULL, len);
+ if (!*strv_ret)
+ return 0;
+
+ /* All null strings */
+ memset (*strv_ret, 0, len);
+
+ for (i = 0; i < n; ++i) {
+ if (!egg_buffer_get_string (buffer, offset, &offset,
+ &((*strv_ret)[i]), allocator)) {
+
+ /* Free all the strings on failure */
+ for (j = 0; j < i; ++j) {
+ if ((*strv_ret)[j])
+ (allocator) ((*strv_ret)[j], 0);
+ }
+
+ return 0;
+ }
+ }
+
+ if (next_offset != NULL)
+ *next_offset = offset;
+
+ return 1;
+}
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-buffer.h - Generic data buffer, used by openssh, gnome-keyring
+
+ 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_BUFFER_H
+#define EGG_BUFFER_H
+
+#include <stdlib.h>
+#include <stdint.h>
+
+/* -------------------------------------------------------------------
+ * EggBuffer
+ *
+ * IMPORTANT: This is pure vanila standard C, no glib. We need this
+ * because certain consumers of this protocol need to be built
+ * without linking in any special libraries. ie: the PKCS#11 module.
+ *
+ * Memory Allocation
+ *
+ * Callers can set their own allocator. If NULL is used then standard
+ * C library heap memory is used and failures will not be fatal. Memory
+ * failures will instead result in a zero return value or
+ * egg_buffer_has_error() returning one.
+ *
+ * If you use something like g_realloc as the allocator, then memory
+ * failures become fatal just like in a standard GTK program.
+ *
+ * Don't change the allocator manually in the EggBuffer structure. The
+ * egg_buffer_set_allocator() func will reallocate and handle things
+ * properly.
+ *
+ * Pointers into the Buffer
+ *
+ * Any write operation has the posibility of reallocating memory
+ * and invalidating any direct pointers into the buffer.
+ */
+
+/* The allocator for the EggBuffer. This follows the realloc() syntax and logic */
+typedef void* (*EggBufferAllocator) (void* p, unsigned long len);
+
+typedef struct _EggBuffer {
+ unsigned char *buf;
+ size_t len;
+ size_t allocated_len;
+ int failures;
+ EggBufferAllocator allocator;
+} EggBuffer;
+
+#define EGG_BUFFER_EMPTY { NULL, 0, 0, 0, NULL }
+
+int egg_buffer_init (EggBuffer *buffer, size_t reserve);
+
+int egg_buffer_init_full (EggBuffer *buffer,
+ size_t reserve,
+ EggBufferAllocator allocator);
+
+void egg_buffer_init_static (EggBuffer *buffer,
+ unsigned char *buf,
+ size_t len);
+
+void egg_buffer_init_allocated (EggBuffer *buffer,
+ unsigned char *buf,
+ size_t len,
+ EggBufferAllocator allocator);
+
+void egg_buffer_uninit (EggBuffer *buffer);
+
+int egg_buffer_set_allocator (EggBuffer *buffer,
+ EggBufferAllocator allocator);
+
+void egg_buffer_reset (EggBuffer *buffer);
+
+int egg_buffer_equal (EggBuffer *b1,
+ EggBuffer *b2);
+
+int egg_buffer_reserve (EggBuffer *buffer,
+ size_t len);
+
+int egg_buffer_resize (EggBuffer *buffer,
+ size_t len);
+
+int egg_buffer_append (EggBuffer *buffer,
+ const unsigned char *val,
+ size_t len);
+
+unsigned char* egg_buffer_add_empty (EggBuffer *buffer,
+ size_t len);
+
+int egg_buffer_add_byte (EggBuffer *buffer,
+ unsigned char val);
+
+int egg_buffer_get_byte (EggBuffer *buffer,
+ size_t offset,
+ size_t *next_offset,
+ unsigned char *val);
+
+void egg_buffer_encode_uint32 (unsigned char* buf,
+ uint32_t val);
+
+uint32_t egg_buffer_decode_uint32 (unsigned char* buf);
+
+int egg_buffer_add_uint32 (EggBuffer *buffer,
+ uint32_t val);
+
+int egg_buffer_set_uint32 (EggBuffer *buffer,
+ size_t offset,
+ uint32_t val);
+
+int egg_buffer_get_uint32 (EggBuffer *buffer,
+ size_t offset,
+ size_t *next_offset,
+ uint32_t *val);
+
+void egg_buffer_encode_uint16 (unsigned char* buf,
+ uint16_t val);
+
+uint16_t egg_buffer_decode_uint16 (unsigned char* buf);
+
+int egg_buffer_add_uint16 (EggBuffer *buffer,
+ uint16_t val);
+
+int egg_buffer_set_uint16 (EggBuffer *buffer,
+ size_t offset,
+ uint16_t val);
+
+int egg_buffer_get_uint16 (EggBuffer *buffer,
+ size_t offset,
+ size_t *next_offset,
+ uint16_t *val);
+
+int egg_buffer_add_byte_array (EggBuffer *buffer,
+ const unsigned char *val,
+ size_t len);
+
+int egg_buffer_get_byte_array (EggBuffer *buffer,
+ size_t offset,
+ size_t *next_offset,
+ const unsigned char **val,
+ size_t *vlen);
+
+unsigned char* egg_buffer_add_byte_array_empty (EggBuffer *buffer,
+ size_t vlen);
+
+int egg_buffer_add_string (EggBuffer *buffer,
+ const char *str);
+
+int egg_buffer_get_string (EggBuffer *buffer,
+ size_t offset,
+ size_t *next_offset,
+ char **str_ret,
+ EggBufferAllocator allocator);
+
+int egg_buffer_add_stringv (EggBuffer *buffer,
+ const char** strv);
+
+int egg_buffer_get_stringv (EggBuffer *buffer,
+ size_t offset,
+ size_t *next_offset,
+ char ***strv_ret,
+ EggBufferAllocator allocator);
+
+int egg_buffer_add_uint64 (EggBuffer *buffer,
+ uint64_t val);
+
+int egg_buffer_get_uint64 (EggBuffer *buffer,
+ size_t offset,
+ size_t *next_offset,
+ uint64_t *val);
+
+#define egg_buffer_length(b) ((b)->len)
+
+#define egg_buffer_has_error(b) ((b)->failures > 0)
+
+#endif /* EGG_BUFFER_H */
+
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-secure-memory.h - library for allocating memory that is non-pageable
+
+ 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>
+*/
+
+/*
+ * IMPORTANT: This is pure vanila standard C, no glib. We need this
+ * because certain consumers of this protocol need to be built
+ * without linking in any special libraries. ie: the PKCS#11 module.
+ */
+
+#include "config.h"
+
+#include "egg-secure-memory.h"
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+
+/*
+ * Use this to force all memory through malloc
+ * for use with valgrind and the like
+ */
+#define FORCE_MALLOC_MEMORY 0
+#define FORCE_FALLBACK_MEMORY 0
+
+#define DEBUG_SECURE_MEMORY 0
+
+#if DEBUG_SECURE_MEMORY
+#define DEBUG_ALLOC(msg, n) fprintf(stderr, "%s %lu bytes\n", msg, n);
+#else
+#define DEBUG_ALLOC(msg, n)
+#endif
+
+#define DEFAULT_BLOCK_SIZE 16384
+
+/* Use our own assert to guarantee no glib allocations */
+#ifndef ASSERT
+#ifdef G_DISABLE_ASSERT
+#define ASSERT(x)
+#else
+#define ASSERT(x) assert(x)
+#endif
+#endif
+
+#define DO_LOCK() \
+ egg_memory_lock ();
+
+#define DO_UNLOCK() \
+ egg_memory_unlock ();
+
+#define MEM_ALIGN (sizeof(void*) > sizeof(long) ? sizeof(void*) : sizeof(long))
+
+/* -----------------------------------------------------------------------------
+ * BLOCK SUBALLOCATION
+ */
+
+/* suba - sub-allocate memory from larger chunk of memory
+ * Copyright (c) 2003 Michael B. Allen <mba2000 ioplex.com>
+ *
+ * The MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+typedef size_t ref_t; /* suba offset from start of memory to object */
+
+#define SUBA_MAGIC "\xFF\x15\x15\x15SUBA"
+#define CELL_MAGIC 0x7777CE11
+#define ALIGN(s) ((((s) / MEM_ALIGN) + (((s) % MEM_ALIGN) ? 1 : 0)) * MEM_ALIGN)
+#define POFF (ALIGN(sizeof(size_t)) + ALIGN(sizeof(unsigned int)))
+#define C2P(c) ((char *)(c) + POFF)
+#define P2C(p) ((struct cell *)((char *)(p) - POFF))
+#define ISADJ(c1,c2) ((struct cell *)(C2P(c1) + (c1)->size) == (struct cell *)(c2))
+#define SREF(s,p) (ref_t)((char *)(p) - (char *)(s))
+#define SADR(s,r) (void *)((char *)(s) + (r))
+#define RECLAIM_DEPTH_MAX 2
+
+struct allocator {
+ unsigned char magic[8]; /* suba header identifier */
+ ref_t tail; /* offset to first cell in free list */
+ size_t mincell; /* min cell size must be at least sizeof cell */
+ size_t size; /* total size of memory area */
+ size_t alloc_total; /* total bytes utilized from this allocator */
+ size_t free_total; /* total bytes released from this allocator */
+ size_t size_total; /* total bytes requested from this allocator */
+ ref_t userref;
+};
+
+struct cell {
+ size_t size;
+ unsigned int magic;
+ ref_t next; /* reference to next cell in free list */
+};
+
+static void*
+suba_addr (const struct allocator *suba, const ref_t ref)
+{
+ if (suba && ref > 0 && ref <= suba->size) {
+ return (char *)suba + ref;
+ }
+ return NULL;
+}
+
+static ref_t
+suba_ref (const struct allocator *suba, const void *ptr)
+{
+ if (suba && ptr) {
+ ref_t ref = (char *)ptr - (char *)suba;
+ if (ref > 0 && ref <= suba->size) {
+ return ref;
+ }
+ }
+ return 0;
+}
+
+static struct allocator *
+suba_init (void *mem, size_t size, size_t mincell)
+{
+ struct allocator *suba = mem;
+ size_t hdrsiz;
+ struct cell *c;
+
+ hdrsiz = ALIGN(sizeof *suba);
+
+ ASSERT (mem != NULL);
+ ASSERT (size > (hdrsiz + POFF));
+
+ memset(suba, 0, hdrsiz);
+ memcpy(suba->magic, SUBA_MAGIC, 8);
+ suba->tail = hdrsiz;
+ suba->mincell = mincell < ALIGN (sizeof (*c)) ? ALIGN (sizeof (*c)) : ALIGN (mincell);
+ suba->size = size;
+
+ c = suba_addr(suba, hdrsiz);
+ c->size = size - (hdrsiz + POFF);
+ c->next = suba->tail;
+
+ return suba;
+}
+
+static void *
+suba_alloc(struct allocator *suba, size_t size)
+{
+ struct cell *c1, *c2, *c3;
+ size_t s = size;
+
+ size = size < suba->mincell ? suba->mincell : ALIGN(size);
+
+ c2 = SADR(suba, suba->tail);
+ for ( ;; ) {
+ c1 = c2;
+ if ((c2 = suba_addr(suba, c1->next)) == NULL) {
+ errno = EFAULT;
+ return NULL;
+ }
+ if (c2->size >= size) {
+ break; /* found a cell large enough */
+ }
+ if (c1->next == suba->tail) {
+ return NULL;
+ }
+ }
+
+ if ((c2->size - size) > suba->mincell) {
+ /* split new cell */
+ c3 = (struct cell *)(C2P(c2) + size);
+ c3->size = c2->size - (size + POFF);
+ if (c1 == c2) {
+ c1 = c3;
+ } else {
+ c3->next = c2->next;
+ }
+ c1->next = SREF(suba, c3);
+ c2->size = size;
+ if (c2 == SADR(suba, suba->tail)) {
+ suba->tail = SREF(suba, c3);
+ }
+ } else if (c1->next == suba->tail) {
+ /* never use the last cell! */
+ } else {
+ /* use the entire cell */
+ c1->next = c2->next;
+ }
+
+ suba->alloc_total += POFF + c2->size;
+ suba->size_total += s;
+
+ c2->magic = CELL_MAGIC;
+ DEBUG_ALLOC ("gkr-secure-memory: allocated ", (unsigned long)size);
+
+ /* TODO: Fix suba, so always allocates zero */
+ memset (C2P(c2), 0, size);
+
+ return C2P(c2);
+}
+
+static void
+suba_free(void *suba0, void *ptr)
+{
+ struct allocator *suba = suba0;
+ struct cell *c1, *c2, *c3;
+ volatile char *vp;
+ size_t len;
+ ref_t ref;
+ int j1, j2;
+
+ if (!ptr)
+ return;
+
+ c1 = SADR(suba, suba->tail);
+
+ /* Find out what cell we're talking about */
+ c2 = P2C(ptr);
+ if ((ref = suba_ref(suba, c2)) == 0) {
+ ASSERT(0 && "invalid memory pointer passed to gkr-secure-memory");
+ return;
+ }
+ if (c2->magic != CELL_MAGIC) {
+ ASSERT(0 && "invalid memory pointer passed to gkr-secure-memory");
+ return;
+ }
+
+ /* Clear out memory */
+ vp = (volatile char*)ptr;
+ len = c2->size;
+ while (len) {
+ *vp = 0xaa;
+ vp++;
+ len--;
+ }
+
+ suba->free_total += POFF + c2->size;
+ suba->alloc_total -= (POFF + c2->size);
+
+ c2->magic = 0;
+ DEBUG_ALLOC ("gkr-secure-memory: freed ", (unsigned long)c2->size);
+
+ /* splice the cell back into the list */
+ if (c2 > c1) { /* append to end of list */
+ if (ISADJ(c1,c2)) { /* join with last cell */
+ c1->size += POFF + c2->size;
+ return;
+ }
+ c2->next = c1->next;
+ suba->tail = c1->next = ref;
+ return;
+ }
+
+ while (c1->next < ref) { /* find insertion point */
+ c1 = SADR(suba, c1->next);
+ }
+ c3 = SADR(suba, c1->next);
+
+ j1 = ISADJ(c1,c2); /* c1 and c2 need to be joined */
+ j2 = ISADJ(c2,c3); /* c2 and c3 need to be joined */
+
+ if (j1) {
+ if (j2) { /* splice all three cells together */
+ if (SREF(suba, c3) == suba->tail) {
+ suba->tail = SREF(suba, c1);
+ }
+ c1->next = c3->next;
+ c1->size += POFF + c3->size;
+ }
+ c1->size += POFF + c2->size;
+ } else {
+ if (j2) {
+ if (SREF(suba, c3) == suba->tail) {
+ suba->tail = ref;
+ }
+ c2->next = c3->next == SREF(suba, c3) ? ref : c3->next;
+ c2->size += POFF + c3->size;
+ } else {
+ c2->next = c1->next;
+ }
+ c1->next = ref;
+ }
+}
+
+static void *
+suba_realloc(struct allocator *suba, void *ptr, size_t size)
+{
+ struct cell *c;
+ void *p;
+
+ if (ptr == NULL)
+ return suba_alloc(suba, size);
+ if (size == 0) {
+ suba_free(suba, ptr);
+ return NULL;
+ }
+ c = P2C(ptr);
+ if (c->size < size || (c->size - ALIGN(size)) > suba->mincell) {
+ p = suba_alloc(suba, size);
+ } else {
+ return ptr;
+ }
+ if (p) {
+ memcpy(p, ptr, c->size);
+ suba_free(suba, ptr);
+ }
+
+ return p;
+}
+
+static int
+suba_print_cell(struct allocator *suba, const char *msg, struct cell *c)
+{
+ ref_t ref = suba_ref(suba, c);
+ if (ref >= ALIGN(sizeof *suba) && (ref + POFF + c->size) <= 10000000) {
+ fprintf(stderr, "%s: %8u-%-8u %8u %-8u\n", msg,
+ (unsigned int)ref, (unsigned int)(ref + POFF + c->size),
+ (unsigned int)c->size, (unsigned int)c->next);
+ } else {
+ fprintf(stderr, "%s: %8u-err %8u %-8u\n", msg,
+ (unsigned int)ref, (unsigned int)c->size,
+ (unsigned int)c->next);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+suba_print_free_list(struct allocator *suba)
+{
+ struct cell *c;
+ char buf[10];
+ int count = 0;
+ int ret = 1;
+
+ c = suba_addr(suba, suba->tail);
+ while (c->next < suba->tail) {
+ c = suba_addr(suba, c->next);
+ sprintf(buf, "%d", count++);
+ if (!suba_print_cell(suba, buf, c)) {
+ ret = 0;
+ }
+ }
+ c = suba_addr(suba, c->next);
+ sprintf(buf, "%d", count++);
+ if (!suba_print_cell(suba, buf, c)) {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static size_t
+suba_allocation_size (struct allocator *suba, void *ptr)
+{
+ struct cell *c = P2C(ptr);
+ if (c->magic != CELL_MAGIC) {
+ ASSERT(0 && "invalid memory pointer passed to gkr-secure-memory");
+ return 0;
+ }
+ return c->size;
+}
+
+/* -----------------------------------------------------------------------------
+ * PAGE SOURCE -- Where blocks of locked memory pages come from.
+ */
+
+static int lock_warning = 1;
+
+static void*
+get_locked_pages (unsigned long *sz)
+{
+ void *pages;
+ unsigned long pgsize;
+
+ ASSERT (sz);
+ ASSERT (*sz);
+
+ /* Make sure sz is a multiple of the page size */
+ pgsize = getpagesize ();
+ *sz = (*sz + pgsize -1) & ~(pgsize - 1);
+
+#if FORCE_MALLOC_MEMORY
+ pages = malloc (*sz);
+ memset (pages, 0, *sz);
+ lock_warning = 1;
+ return pages;
+
+#elif defined(HAVE_MLOCK)
+ pages = mmap (0, *sz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (pages == MAP_FAILED) {
+ if (lock_warning)
+ fprintf (stderr, "couldn't map %lu bytes of private memory: %s\n",
+ *sz, strerror (errno));
+ lock_warning = 0;
+ return NULL;
+ }
+
+ if (mlock (pages, *sz) < 0) {
+ if (lock_warning && errno != EPERM) {
+ fprintf (stderr, "couldn't lock %lu bytes of private memory: %s\n",
+ *sz, strerror (errno));
+ lock_warning = 0;
+ }
+ munmap (pages, *sz);
+ return NULL;
+ }
+
+ DEBUG_ALLOC ("gkr-secure-memory: new block ", *sz);
+
+ lock_warning = 1;
+ return pages;
+
+#else
+ if (lock_warning)
+ fprintf (stderr, "your system does not support private memory");
+ lock_warning = 0;
+ return NULL;
+#endif
+
+}
+
+static void
+rel_locked_pages (void *pages, unsigned long sz)
+{
+ ASSERT (pages);
+ ASSERT (sz % getpagesize () == 0);
+
+#if FORCE_MALLOC_MEMORY
+ free (pages);
+
+#elif defined(HAVE_MLOCK)
+ if (munlock (pages, sz) < 0)
+ fprintf (stderr, "couldn't unlock private memory: %s\n", strerror (errno));
+
+ if (munmap (pages, sz) < 0)
+ fprintf (stderr, "couldn't unmap private anonymous memory: %s\n", strerror (errno));
+
+ DEBUG_ALLOC ("gkr-secure-memory: freed block ", sz);
+
+#else
+ ASSERT (FALSE);
+#endif
+}
+
+/* -----------------------------------------------------------------------------
+ * MANAGE DIFFERENT BLOCKS
+ */
+
+typedef struct _MemBlock {
+ unsigned long size;
+ struct allocator *suba;
+ struct _MemBlock *next;
+} MemBlock;
+
+static MemBlock *most_recent_block = NULL;
+
+static MemBlock*
+block_create (unsigned long size)
+{
+ MemBlock *bl;
+ void *blmem;
+
+#if FORCE_FALLBACK_MEMORY
+ /* We can force all all memory to be malloced */
+ return NULL;
+#endif
+
+ size += sizeof (MemBlock);
+
+ /* The size above is a minimum, we're free to go bigger */
+ if (size < DEFAULT_BLOCK_SIZE)
+ size = DEFAULT_BLOCK_SIZE;
+
+ blmem = get_locked_pages (&size);
+ if (!blmem)
+ return NULL;
+
+ bl = (MemBlock*)blmem;
+ bl->size = size;
+ bl->suba = suba_init (((unsigned char*)blmem) + sizeof (MemBlock),
+ size - sizeof (MemBlock), 32);
+ ASSERT (bl->suba);
+
+ bl->next = most_recent_block;
+ most_recent_block = bl;
+
+ return bl;
+}
+
+static void
+block_destroy (MemBlock *bl)
+{
+ MemBlock *b;
+
+ ASSERT (bl && bl->suba);
+ ASSERT (bl->size > 0);
+ ASSERT (bl->suba->alloc_total == 0);
+
+ /* Is the most recent block, simple */
+ if (bl == most_recent_block) {
+ most_recent_block = bl->next;
+
+ /* Take it out of our list */
+ } else {
+ for (b = most_recent_block; b; b = b->next) {
+ if (b->next == bl) {
+ b->next = bl->next;
+ break;
+ }
+ }
+ ASSERT (b != NULL && "couldn't find memory block in list");
+ }
+
+ /* Memory is all in one block, nothing fancy to free */
+ rel_locked_pages(bl, bl->size);
+}
+
+static int
+block_belongs (MemBlock *bl, const void *p)
+{
+ ASSERT (bl);
+ ASSERT (bl->size > 0);
+
+ /* This does not check for invalid memory */
+ return ((char*)p) >= ((char*)bl) &&
+ ((char*)p) < (((char*)bl) + bl->size);
+}
+
+void*
+egg_secure_alloc (unsigned long sz)
+{
+ return egg_secure_alloc_full (sz, GKR_SECURE_USE_FALLBACK);
+}
+
+void*
+egg_secure_alloc_full (unsigned long sz, int flags)
+{
+ MemBlock *bl;
+ void *p = NULL;
+
+ if (sz > 0xFFFFFFFF / 2) {
+ fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", sz);
+ return NULL;
+ }
+
+ DO_LOCK ();
+
+ for (bl = most_recent_block; bl; bl = bl->next) {
+ p = suba_alloc (bl->suba, sz);
+ if (p)
+ break;
+ }
+
+ /* None of the current blocks have space, allocate new */
+ if (!p) {
+ bl = block_create (sz);
+ if (bl) {
+ p = suba_alloc (bl->suba, sz);
+ ASSERT (p);
+ }
+ }
+
+ DO_UNLOCK ();
+
+ if (!p && (flags & GKR_SECURE_USE_FALLBACK)) {
+ p = egg_memory_fallback (NULL, sz);
+ if (p) /* Our returned memory is always zeroed */
+ memset (p, 0, sz);
+ }
+
+ if (!p)
+ errno = ENOMEM;
+
+ return p;
+}
+
+void*
+egg_secure_realloc (void *p, unsigned long sz)
+{
+ return egg_secure_realloc_full (p, sz, GKR_SECURE_USE_FALLBACK);
+}
+
+void*
+egg_secure_realloc_full (void *p, unsigned long sz, int flags)
+{
+ MemBlock *bl = NULL;
+ unsigned long oldsz = 0;
+ int donew = 0;
+ void *n = NULL;
+
+ if (sz > 0xFFFFFFFF / 2) {
+ fprintf (stderr, "tried to allocate an insane amount of memory: %lu\n", sz);
+ ASSERT (0 && "tried to allocate an insane amount of memory");
+ return NULL;
+ }
+
+ if (p == NULL)
+ return egg_secure_alloc_full (sz, flags);
+ if (!sz) {
+ egg_secure_free_full (p, flags);
+ return NULL;
+ }
+
+ DO_LOCK ();
+
+ /* Find out where it belongs to */
+ for (bl = most_recent_block; bl; bl = bl->next) {
+ if (block_belongs (bl, p)) {
+ oldsz = suba_allocation_size (bl->suba, p);
+ n = suba_realloc (bl->suba, p, sz);
+ break;
+ }
+ }
+
+ /* If it didn't work we may need to allocate a new block */
+ if (bl && !n)
+ donew = 1;
+
+ if (bl && bl->suba->alloc_total == 0)
+ block_destroy (bl);
+
+ DO_UNLOCK ();
+
+ if (!bl) {
+ if ((flags & GKR_SECURE_USE_FALLBACK)) {
+ /*
+ * In this case we can't zero the returned memory,
+ * because we don't know what the block size was.
+ */
+ return egg_memory_fallback (p, sz);
+ } else {
+ fprintf (stderr, "memory does not belong to gnome-keyring: 0x%08lx\n", (unsigned long)p);
+ ASSERT (0 && "memory does does not belong to gnome-keyring");
+ return NULL;
+ }
+ }
+
+ if (donew) {
+ n = egg_secure_alloc_full (sz, flags);
+ if (n) {
+ memcpy (n, p, oldsz);
+ egg_secure_free_full (p, flags);
+ }
+ }
+
+ if (!n)
+ errno = ENOMEM;
+
+ return n;
+}
+
+void
+egg_secure_free (void *p)
+{
+ egg_secure_free_full (p, GKR_SECURE_USE_FALLBACK);
+}
+
+void
+egg_secure_free_full (void *p, int flags)
+{
+ MemBlock *bl = NULL;
+
+ DO_LOCK ();
+
+ /* Find out where it belongs to */
+ for (bl = most_recent_block; bl; bl = bl->next) {
+ if (block_belongs (bl, p)) {
+ suba_free (bl->suba, p);
+ break;
+ }
+ }
+
+ if (bl && bl->suba->alloc_total == 0)
+ block_destroy (bl);
+
+ DO_UNLOCK ();
+
+ if (!bl) {
+ if ((flags & GKR_SECURE_USE_FALLBACK)) {
+ egg_memory_fallback (p, 0);
+ } else {
+ fprintf (stderr, "memory does not belong to gnome-keyring: 0x%08lx\n", (unsigned long)p);
+ ASSERT (0 && "memory does does not belong to gnome-keyring");
+ }
+ }
+}
+
+int
+egg_secure_check (const void *p)
+{
+ MemBlock *bl = NULL;
+
+ DO_LOCK ();
+
+ /* Find out where it belongs to */
+ for (bl = most_recent_block; bl; bl = bl->next) {
+ if (block_belongs (bl, p))
+ break;
+ }
+
+ DO_UNLOCK ();
+
+ return bl == NULL ? 0 : 1;
+}
+
+void
+egg_secure_dump_blocks (void)
+{
+ MemBlock *bl = NULL;
+
+ DO_LOCK ();
+
+ /* Find out where it belongs to */
+ for (bl = most_recent_block; bl; bl = bl->next) {
+ fprintf (stderr, "----------------------------------------------------\n");
+ fprintf (stderr, " BLOCK at: 0x%08lx len: %lu\n", (unsigned long)bl, bl->size);
+ fprintf (stderr, "\n");
+ suba_print_free_list (bl->suba);
+ }
+
+ DO_UNLOCK ();
+}
+
+char*
+egg_secure_strdup (const char *str)
+{
+ unsigned long len;
+ char *res;
+
+ if (!str)
+ return NULL;
+
+ len = strlen (str) + 1;
+ res = (char*)egg_secure_alloc (len);
+ strcpy (res, str);
+ return res;
+}
+
+void
+egg_secure_strclear (char *str)
+{
+ volatile char *vp;
+ size_t len;
+
+ if (!str)
+ return;
+
+ vp = (volatile char*)str;
+ len = strlen (str);
+ while (len) {
+ *vp = 0xAA;
+ vp++;
+ len--;
+ }
+}
+
+void
+egg_secure_strfree (char *str)
+{
+ /*
+ * If we're using unpageable 'secure' memory, then the free call
+ * should zero out the memory, but because on certain platforms
+ * we may be using normal memory, zero it out here just in case.
+ */
+
+ egg_secure_strclear (str);
+ egg_secure_free_full (str, GKR_SECURE_USE_FALLBACK);
+}
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* egg-secure-memory.h - library for allocating memory that is non-pageable
+
+ 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_SECURE_MEMORY_H
+#define EGG_SECURE_MEMORY_H
+
+/* -------------------------------------------------------------------
+ * Low Level Secure Memory
+ *
+ * IMPORTANT: This is pure vanila standard C, no glib. We need this
+ * because certain consumers of this protocol need to be built
+ * without linking in any special libraries. ie: the PKCS#11 module.
+ *
+ * Thread locking
+ *
+ * In order to use these functions in a module the following functions
+ * must be defined somewhere, and provide appropriate locking for
+ * secure memory between threads:
+ */
+
+extern void egg_memory_lock (void);
+
+extern void egg_memory_unlock (void);
+
+/*
+ * Allocation Fallbacks
+ *
+ * If we cannot allocate secure memory, then this function
+ * (defined elsewhere) will be called which has a chance to
+ * allocate other memory abort or do whatever.
+ *
+ * Same call semantics as realloc with regard to NULL and zeros
+ */
+extern void* egg_memory_fallback (void *p, unsigned long sz);
+
+
+/*
+ * Main functionality
+ *
+ * Allocations return NULL on failure.
+ */
+
+#define GKR_SECURE_USE_FALLBACK 0x0001
+
+void* egg_secure_alloc (unsigned long sz);
+
+void* egg_secure_alloc_full (unsigned long, int flags);
+
+void* egg_secure_realloc (void *p, unsigned long sz);
+
+void* egg_secure_realloc_full (void *p, unsigned long sz, int fallback);
+
+void egg_secure_free (void* p);
+
+void egg_secure_free_full (void* p, int fallback);
+
+int egg_secure_check (const void* p);
+
+void egg_secure_dump_blocks (void);
+
+char* egg_secure_strdup (const char *str);
+
+void egg_secure_strclear (char *str);
+
+void egg_secure_strfree (char *str);
+
+#endif /* EGG_SECURE_MEMORY_H */
--- /dev/null
+PK { }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+-- This file contains parts of PKCS-1 structures and some stuff
+-- required for DSA keys.
+
+RSAPublicKey ::= SEQUENCE {
+ modulus INTEGER, -- n
+ publicExponent INTEGER -- e
+}
+
+--
+-- Representation of RSA private key with information for the
+-- CRT algorithm.
+--
+RSAPrivateKey ::= SEQUENCE {
+ version Version,
+ modulus INTEGER, -- (Usually large) n
+ publicExponent INTEGER, -- (Usually small) e
+ privateExponent INTEGER, -- (Usually large) d
+ prime1 INTEGER, -- (Usually large) p
+ prime2 INTEGER, -- (Usually large) q
+ exponent1 INTEGER, -- (Usually large) d mod (p-1)
+ exponent2 INTEGER, -- (Usually large) d mod (q-1)
+ coefficient INTEGER, -- (Usually large) (inverse of q) mod p
+ otherPrimeInfos OtherPrimeInfos OPTIONAL
+}
+
+Version ::= INTEGER { two-prime(0), multi(1) }
+-- version must be multi if otherPrimeInfos present --
+
+OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
+
+OtherPrimeInfo ::= SEQUENCE {
+ prime INTEGER, -- ri
+ exponent INTEGER, -- di
+ coefficient INTEGER -- ti
+}
+
+-- for signature calculation
+-- added by nmav
+
+AlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters ANY DEFINED BY algorithm OPTIONAL
+}
+ -- contains a value of the type
+ -- registered for use with the
+ -- algorithm object identifier value
+
+DigestInfo ::= SEQUENCE {
+ digestAlgorithm DigestAlgorithmIdentifier,
+ digest Digest
+}
+
+DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+
+Digest ::= OCTET STRING
+
+DSAPublicPart ::= INTEGER
+
+DSAPublicKey ::= SEQUENCE {
+ version INTEGER, -- should be zero
+ p INTEGER,
+ q INTEGER,
+ g INTEGER,
+ Y INTEGER -- public
+}
+
+DSAParameters ::= SEQUENCE {
+ p INTEGER,
+ q INTEGER,
+ g INTEGER
+}
+
+DSASignatureValue ::= SEQUENCE {
+ r INTEGER,
+ s INTEGER
+}
+
+DSAPrivatePart ::= INTEGER
+
+DSAPrivateKey ::= SEQUENCE {
+ version INTEGER, -- should be zero
+ p INTEGER,
+ q INTEGER,
+ g INTEGER,
+ Y INTEGER, -- public
+ priv INTEGER
+}
+
+-- from PKCS#3
+DHParameter ::= SEQUENCE {
+ prime INTEGER, -- p
+ base INTEGER, -- g
+ privateValueLength INTEGER OPTIONAL
+}
+
+
+END
--- /dev/null
+
+PKIX1 { }
+
+DEFINITIONS IMPLICIT TAGS ::=
+
+BEGIN
+
+-- This contains both PKIX1Implicit88 and RFC2630 ASN.1 modules.
+
+-- ISO arc for standard certificate and CRL extensions
+
+id-ce OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 29}
+
+
+-- authority key identifier OID and syntax
+
+id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 35 }
+
+AuthorityKeyIdentifier ::= SEQUENCE {
+ keyIdentifier [0] KeyIdentifier OPTIONAL,
+ authorityCertIssuer [1] GeneralNames OPTIONAL,
+ authorityCertSerialNumber [2] CertificateSerialNumber OPTIONAL }
+ -- authorityCertIssuer and authorityCertSerialNumber shall both
+ -- be present or both be absgent
+
+KeyIdentifier ::= OCTET STRING
+
+-- subject key identifier OID and syntax
+
+id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::= { id-ce 14 }
+
+SubjectKeyIdentifier ::= KeyIdentifier
+
+-- key usage extension OID and syntax
+
+id-ce-keyUsage OBJECT IDENTIFIER ::= { id-ce 15 }
+
+KeyUsage ::= BIT STRING {
+ digitalSignature (0),
+ nonRepudiation (1),
+ keyEncipherment (2),
+ dataEncipherment (3),
+ keyAgreement (4),
+ keyCertSign (5),
+ cRLSign (6),
+ encipherOnly (7),
+ decipherOnly (8) }
+
+-- private key usage period extension OID and syntax
+
+id-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::= { id-ce 16 }
+
+PrivateKeyUsagePeriod ::= SEQUENCE {
+ notBefore [0] GeneralizedTime OPTIONAL,
+ notAfter [1] GeneralizedTime OPTIONAL }
+ -- either notBefore or notAfter shall be present
+
+-- certificate policies extension OID and syntax
+
+id-ce-certificatePolicies OBJECT IDENTIFIER ::= { id-ce 32 }
+
+CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+
+PolicyInformation ::= SEQUENCE {
+ policyIdentifier CertPolicyId,
+ policyQualifiers SEQUENCE SIZE (1..MAX) OF
+ PolicyQualifierInfo OPTIONAL }
+
+CertPolicyId ::= OBJECT IDENTIFIER
+
+PolicyQualifierInfo ::= SEQUENCE {
+ policyQualifierId PolicyQualifierId,
+ qualifier ANY DEFINED BY policyQualifierId }
+
+-- Implementations that recognize additional policy qualifiers shall
+-- augment the following definition for PolicyQualifierId
+
+PolicyQualifierId ::=
+ OBJECT IDENTIFIER -- ( id-qt-cps | id-qt-unotice )
+
+-- CPS pointer qualifier
+
+CPSuri ::= IA5String
+
+-- user notice qualifier
+
+UserNotice ::= SEQUENCE {
+ noticeRef NoticeReference OPTIONAL,
+ explicitText DisplayText OPTIONAL}
+
+NoticeReference ::= SEQUENCE {
+ organization DisplayText,
+ noticeNumbers SEQUENCE OF INTEGER }
+
+DisplayText ::= CHOICE {
+ visibleString VisibleString (SIZE (1..200)),
+ bmpString BMPString (SIZE (1..200)),
+ utf8String UTF8String (SIZE (1..200)) }
+
+-- policy mapping extension OID and syntax
+
+id-ce-policyMappings OBJECT IDENTIFIER ::= { id-ce 33 }
+
+PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
+ issuerDomainPolicy CertPolicyId,
+ subjectDomainPolicy CertPolicyId }
+
+-- subject alternative name extension OID and syntax
+
+-- Directory string type --
+
+DirectoryString ::= CHOICE {
+ teletexString TeletexString (SIZE (1..MAX)),
+ printableString PrintableString (SIZE (1..MAX)),
+ universalString UniversalString (SIZE (1..MAX)),
+ utf8String UTF8String (SIZE (1..MAX)),
+ bmpString BMPString (SIZE(1..MAX)),
+ -- IA5String is added here to handle old UID encoded as ia5String --
+ -- See tests/userid/ for more information. It shouldn't be here, --
+ -- so if it causes problems, considering dropping it. --
+ ia5String IA5String (SIZE(1..MAX)) }
+
+id-ce-subjectAltName OBJECT IDENTIFIER ::= { id-ce 17 }
+
+SubjectAltName ::= GeneralNames
+
+GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+
+GeneralName ::= CHOICE {
+ otherName [0] AnotherName,
+ rfc822Name [1] IA5String,
+ dNSName [2] IA5String,
+ x400Address [3] ORAddress,
+-- Changed to work with the libtasn1 parser.
+ directoryName [4] EXPLICIT RDNSequence, --Name,
+ ediPartyName [5] EDIPartyName,
+ uniformResourceIdentifier [6] IA5String,
+ iPAddress [7] OCTET STRING,
+ registeredID [8] OBJECT IDENTIFIER }
+
+-- AnotherName replaces OTHER-NAME ::= TYPE-IDENTIFIER, as
+-- TYPE-IDENTIFIER is not supported in the '88 ASN.1 syntax
+
+AnotherName ::= SEQUENCE {
+ type-id OBJECT IDENTIFIER,
+ value [0] EXPLICIT ANY DEFINED BY type-id }
+
+EDIPartyName ::= SEQUENCE {
+ nameAssigner [0] DirectoryString OPTIONAL,
+ partyName [1] DirectoryString }
+
+-- issuer alternative name extension OID and syntax
+
+id-ce-issuerAltName OBJECT IDENTIFIER ::= { id-ce 18 }
+
+IssuerAltName ::= GeneralNames
+
+id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::= { id-ce 9 }
+
+SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+
+-- basic constraints extension OID and syntax
+
+id-ce-basicConstraints OBJECT IDENTIFIER ::= { id-ce 19 }
+
+BasicConstraints ::= SEQUENCE {
+ cA BOOLEAN DEFAULT FALSE,
+ pathLenConstraint INTEGER (0..MAX) OPTIONAL }
+
+-- name constraints extension OID and syntax
+
+id-ce-nameConstraints OBJECT IDENTIFIER ::= { id-ce 30 }
+
+NameConstraints ::= SEQUENCE {
+ permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+
+GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+
+GeneralSubtree ::= SEQUENCE {
+ base GeneralName,
+ minimum [0] BaseDistance DEFAULT 0,
+ maximum [1] BaseDistance OPTIONAL }
+
+BaseDistance ::= INTEGER (0..MAX)
+
+-- policy constraints extension OID and syntax
+
+id-ce-policyConstraints OBJECT IDENTIFIER ::= { id-ce 36 }
+
+PolicyConstraints ::= SEQUENCE {
+ requireExplicitPolicy [0] SkipCerts OPTIONAL,
+ inhibitPolicyMapping [1] SkipCerts OPTIONAL }
+
+SkipCerts ::= INTEGER (0..MAX)
+
+-- CRL distribution points extension OID and syntax
+
+id-ce-cRLDistributionPoints OBJECT IDENTIFIER ::= {id-ce 31}
+
+CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+
+DistributionPoint ::= SEQUENCE {
+ distributionPoint [0] EXPLICIT DistributionPointName OPTIONAL,
+ reasons [1] ReasonFlags OPTIONAL,
+ cRLIssuer [2] GeneralNames OPTIONAL
+}
+
+DistributionPointName ::= CHOICE {
+ fullName [0] GeneralNames,
+ nameRelativeToCRLIssuer [1] RelativeDistinguishedName
+}
+
+ReasonFlags ::= BIT STRING {
+ unused (0),
+ keyCompromise (1),
+ cACompromise (2),
+ affiliationChanged (3),
+ superseded (4),
+ cessationOfOperation (5),
+ certificateHold (6),
+ privilegeWithdrawn (7),
+ aACompromise (8) }
+
+-- extended key usage extension OID and syntax
+
+id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37}
+
+ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+
+KeyPurposeId ::= OBJECT IDENTIFIER
+
+-- extended key purpose OIDs
+id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
+id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
+id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
+id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
+id-kp-ipsecEndSystem OBJECT IDENTIFIER ::= { id-kp 5 }
+id-kp-ipsecTunnel OBJECT IDENTIFIER ::= { id-kp 6 }
+id-kp-ipsecUser OBJECT IDENTIFIER ::= { id-kp 7 }
+id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
+
+-- authority info access
+
+id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
+
+AuthorityInfoAccessSyntax ::=
+ SEQUENCE SIZE (1..MAX) OF AccessDescription
+
+AccessDescription ::= SEQUENCE {
+ accessMethod OBJECT IDENTIFIER,
+ accessLocation GeneralName }
+
+-- CRL number extension OID and syntax
+
+id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 }
+
+CRLNumber ::= INTEGER (0..MAX)
+
+-- issuing distribution point extension OID and syntax
+
+id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
+
+IssuingDistributionPoint ::= SEQUENCE {
+ distributionPoint [0] DistributionPointName OPTIONAL,
+ onlyContainsUserCerts [1] BOOLEAN DEFAULT FALSE,
+ onlyContainsCACerts [2] BOOLEAN DEFAULT FALSE,
+ onlySomeReasons [3] ReasonFlags OPTIONAL,
+ indirectCRL [4] BOOLEAN DEFAULT FALSE }
+
+
+id-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-ce 27 }
+
+-- deltaCRLIndicator ::= BaseCRLNumber
+
+BaseCRLNumber ::= CRLNumber
+
+-- CRL reasons extension OID and syntax
+
+id-ce-cRLReasons OBJECT IDENTIFIER ::= { id-ce 21 }
+
+CRLReason ::= ENUMERATED {
+ unspecified (0),
+ keyCompromise (1),
+ cACompromise (2),
+ affiliationChanged (3),
+ superseded (4),
+ cessationOfOperation (5),
+ certificateHold (6),
+ removeFromCRL (8) }
+
+-- certificate issuer CRL entry extension OID and syntax
+
+id-ce-certificateIssuer OBJECT IDENTIFIER ::= { id-ce 29 }
+
+CertificateIssuer ::= GeneralNames
+
+-- hold instruction extension OID and syntax
+
+id-ce-holdInstructionCode OBJECT IDENTIFIER ::= { id-ce 23 }
+
+HoldInstructionCode ::= OBJECT IDENTIFIER
+
+-- ANSI x9 holdinstructions
+
+-- ANSI x9 arc holdinstruction arc
+holdInstruction OBJECT IDENTIFIER ::=
+ {joint-iso-itu-t(2) member-body(2) us(840) x9cm(10040) 2}
+
+-- ANSI X9 holdinstructions referenced by this standard
+id-holdinstruction-none OBJECT IDENTIFIER ::=
+ {holdInstruction 1} -- deprecated
+id-holdinstruction-callissuer OBJECT IDENTIFIER ::=
+ {holdInstruction 2}
+id-holdinstruction-reject OBJECT IDENTIFIER ::=
+ {holdInstruction 3}
+
+-- invalidity date CRL entry extension OID and syntax
+
+id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 }
+
+InvalidityDate ::= GeneralizedTime
+
+
+-- --------------------------------------
+-- EXPLICIT
+-- --------------------------------------
+
+-- UNIVERSAL Types defined in '93 and '98 ASN.1
+-- but required by this specification
+
+VisibleString ::= [UNIVERSAL 26] IMPLICIT OCTET STRING
+
+NumericString ::= [UNIVERSAL 18] IMPLICIT OCTET STRING
+
+IA5String ::= [UNIVERSAL 22] IMPLICIT OCTET STRING
+
+TeletexString ::= [UNIVERSAL 20] IMPLICIT OCTET STRING
+
+PrintableString ::= [UNIVERSAL 19] IMPLICIT OCTET STRING
+
+UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING
+ -- UniversalString is defined in ASN.1:1993
+
+BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING
+ -- BMPString is the subtype of UniversalString and models
+ -- the Basic Multilingual Plane of ISO/IEC/ITU 10646-1
+
+UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING
+ -- The content of this type conforms to RFC 2279.
+
+
+-- PKIX specific OIDs
+
+id-pkix OBJECT IDENTIFIER ::=
+ { iso(1) identified-organization(3) dod(6) internet(1)
+ security(5) mechanisms(5) pkix(7) }
+
+-- PKIX arcs
+
+id-pe OBJECT IDENTIFIER ::= { id-pkix 1 }
+ -- arc for private certificate extensions
+id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
+ -- arc for policy qualifier types
+id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+ -- arc for extended key purpose OIDS
+id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+ -- arc for access descriptors
+
+-- policyQualifierIds for Internet policy qualifiers
+
+id-qt-cps OBJECT IDENTIFIER ::= { id-qt 1 }
+ -- OID for CPS qualifier
+id-qt-unotice OBJECT IDENTIFIER ::= { id-qt 2 }
+ -- OID for user notice qualifier
+
+-- access descriptor definitions
+
+id-ad-ocsp OBJECT IDENTIFIER ::= { id-ad 1 }
+id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
+
+-- attribute data types --
+
+Attribute ::= SEQUENCE {
+ type AttributeType,
+ values SET OF AttributeValue
+ -- at least one value is required --
+}
+
+AttributeType ::= OBJECT IDENTIFIER
+
+AttributeValue ::= ANY DEFINED BY type
+
+AttributeTypeAndValue ::= SEQUENCE {
+ type AttributeType,
+ value AttributeValue }
+
+-- suggested naming attributes: Definition of the following
+-- information object set may be augmented to meet local
+-- requirements. Note that deleting members of the set may
+-- prevent interoperability with conforming implementations.
+-- presented in pairs: the AttributeType followed by the
+-- type definition for the corresponding AttributeValue
+
+-- Arc for standard naming attributes
+id-at OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4}
+
+-- Attributes of type NameDirectoryString
+id-at-initials AttributeType ::= { id-at 43 }
+X520initials ::= DirectoryString
+
+id-at-generationQualifier AttributeType ::= { id-at 44 }
+X520generationQualifier ::= DirectoryString
+
+id-at-surname AttributeType ::= { id-at 4 }
+X520surName ::= DirectoryString
+
+id-at-givenName AttributeType ::= { id-at 42 }
+X520givenName ::= DirectoryString
+
+id-at-name AttributeType ::= { id-at 41 }
+X520name ::= DirectoryString
+
+id-at-commonName AttributeType ::= {id-at 3}
+X520CommonName ::= DirectoryString
+
+id-at-localityName AttributeType ::= {id-at 7}
+X520LocalityName ::= DirectoryString
+
+id-at-stateOrProvinceName AttributeType ::= {id-at 8}
+X520StateOrProvinceName ::= DirectoryString
+
+id-at-organizationName AttributeType ::= {id-at 10}
+X520OrganizationName ::= DirectoryString
+
+id-at-organizationalUnitName AttributeType ::= {id-at 11}
+X520OrganizationalUnitName ::= DirectoryString
+
+id-at-title AttributeType ::= {id-at 12}
+X520Title ::= DirectoryString
+
+id-at-description AttributeType ::= {id-at 13}
+X520Description ::= DirectoryString
+
+id-at-dnQualifier AttributeType ::= {id-at 46}
+X520dnQualifier ::= PrintableString
+
+id-at-countryName AttributeType ::= {id-at 6}
+X520countryName ::= PrintableString (SIZE (2)) -- IS 3166 codes
+
+id-at-serialNumber AttributeType ::= {id-at 5}
+X520serialNumber ::= PrintableString
+
+id-at-telephoneNumber AttributeType ::= {id-at 20}
+X520telephoneNumber ::= PrintableString
+
+id-at-facsimileTelephoneNumber AttributeType ::= {id-at 23}
+X520facsimileTelephoneNumber ::= PrintableString
+
+id-at-pseudonym AttributeType ::= {id-at 65}
+X520pseudonym ::= DirectoryString
+
+id-at-name AttributeType ::= {id-at 41}
+X520name ::= DirectoryString
+
+id-at-streetAddress AttributeType ::= {id-at 9}
+X520streetAddress ::= DirectoryString
+
+id-at-postalAddress AttributeType ::= {id-at 16}
+X520postalAddress ::= PostalAddress
+
+PostalAddress ::= SEQUENCE OF DirectoryString
+
+
+ -- Legacy attributes
+
+pkcs OBJECT IDENTIFIER ::=
+ { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) }
+
+pkcs-9 OBJECT IDENTIFIER ::=
+ { pkcs 9 }
+
+
+emailAddress AttributeType ::= { pkcs-9 1 }
+
+Pkcs9email ::= IA5String (SIZE (1..ub-emailaddress-length))
+
+-- naming data types --
+
+Name ::= CHOICE { -- only one possibility for now --
+ rdnSequence RDNSequence }
+
+RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+DistinguishedName ::= RDNSequence
+
+RelativeDistinguishedName ::=
+ SET SIZE (1 .. MAX) OF AttributeTypeAndValue
+
+
+
+-- --------------------------------------------------------
+-- certificate and CRL specific structures begin here
+-- --------------------------------------------------------
+
+Certificate ::= SEQUENCE {
+ tbsCertificate TBSCertificate,
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING }
+
+TBSCertificate ::= SEQUENCE {
+ version [0] EXPLICIT Version DEFAULT v1,
+ serialNumber CertificateSerialNumber,
+ signature AlgorithmIdentifier,
+ issuer Name,
+ validity Validity,
+ subject Name,
+ subjectPublicKeyInfo SubjectPublicKeyInfo,
+ issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
+ -- If present, version shall be v2 or v3
+ subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
+ -- If present, version shall be v2 or v3
+ extensions [3] EXPLICIT Extensions OPTIONAL
+ -- If present, version shall be v3 --
+}
+
+Version ::= INTEGER { v1(0), v2(1), v3(2) }
+
+CertificateSerialNumber ::= INTEGER
+
+Validity ::= SEQUENCE {
+ notBefore Time,
+ notAfter Time }
+
+Time ::= CHOICE {
+ utcTime UTCTime,
+ generalTime GeneralizedTime }
+
+UniqueIdentifier ::= BIT STRING
+
+SubjectPublicKeyInfo ::= SEQUENCE {
+ algorithm AlgorithmIdentifier,
+ subjectPublicKey BIT STRING }
+
+Extensions ::= SEQUENCE SIZE (1..MAX) OF Extension
+
+Extension ::= SEQUENCE {
+ extnID OBJECT IDENTIFIER,
+ critical BOOLEAN DEFAULT FALSE,
+ extnValue OCTET STRING }
+
+
+-- ------------------------------------------
+-- CRL structures
+-- ------------------------------------------
+
+CertificateList ::= SEQUENCE {
+ tbsCertList TBSCertList,
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING }
+
+TBSCertList ::= SEQUENCE {
+ version Version OPTIONAL,
+ -- if present, shall be v2
+ signature AlgorithmIdentifier,
+ issuer Name,
+ thisUpdate Time,
+ nextUpdate Time OPTIONAL,
+ revokedCertificates SEQUENCE OF SEQUENCE {
+ userCertificate CertificateSerialNumber,
+ revocationDate Time,
+ crlEntryExtensions Extensions OPTIONAL
+ -- if present, shall be v2
+ } OPTIONAL,
+ crlExtensions [0] EXPLICIT Extensions OPTIONAL
+ -- if present, shall be v2 --
+}
+
+-- Version, Time, CertificateSerialNumber, and Extensions were
+-- defined earlier for use in the certificate structure
+
+AlgorithmIdentifier ::= SEQUENCE {
+ algorithm OBJECT IDENTIFIER,
+ parameters ANY DEFINED BY algorithm OPTIONAL }
+ -- contains a value of the type
+ -- registered for use with the
+ -- algorithm object identifier value
+
+-- Algorithm OIDs and parameter structures
+
+pkcs-1 OBJECT IDENTIFIER ::= {
+ pkcs 1 }
+
+rsaEncryption OBJECT IDENTIFIER ::= { pkcs-1 1 }
+
+md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
+
+md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
+
+sha1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
+
+id-dsa-with-sha1 OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) x9-57 (10040) x9algorithm(4) 3 }
+
+Dss-Sig-Value ::= SEQUENCE {
+ r INTEGER,
+ s INTEGER
+}
+
+dhpublicnumber OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) ansi-x942(10046) number-type(2) 1 }
+
+DomainParameters ::= SEQUENCE {
+ p INTEGER, -- odd prime, p=jq +1
+ g INTEGER, -- generator, g
+ q INTEGER, -- factor of p-1
+ j INTEGER OPTIONAL, -- subgroup factor, j>= 2
+ validationParms ValidationParms OPTIONAL }
+
+ValidationParms ::= SEQUENCE {
+ seed BIT STRING,
+ pgenCounter INTEGER }
+
+id-dsa OBJECT IDENTIFIER ::= {
+ iso(1) member-body(2) us(840) x9-57(10040) x9algorithm(4) 1 }
+
+Dss-Parms ::= SEQUENCE {
+ p INTEGER,
+ q INTEGER,
+ g INTEGER }
+
+-- x400 address syntax starts here
+-- OR Names
+
+ORAddress ::= SEQUENCE {
+ built-in-standard-attributes BuiltInStandardAttributes,
+ built-in-domain-defined-attributes
+ BuiltInDomainDefinedAttributes OPTIONAL,
+ -- see also teletex-domain-defined-attributes
+ extension-attributes ExtensionAttributes OPTIONAL }
+-- The OR-address is semantically absent from the OR-name if the
+-- built-in-standard-attribute sequence is empty and the
+-- built-in-domain-defined-attributes and extension-attributes are
+-- both omitted.
+
+-- Built-in Standard Attributes
+
+BuiltInStandardAttributes ::= SEQUENCE {
+ country-name CountryName OPTIONAL,
+ administration-domain-name AdministrationDomainName OPTIONAL,
+ network-address [0] EXPLICIT NetworkAddress OPTIONAL,
+ -- see also extended-network-address
+ terminal-identifier [1] EXPLICIT TerminalIdentifier OPTIONAL,
+ private-domain-name [2] EXPLICIT PrivateDomainName OPTIONAL,
+ organization-name [3] EXPLICIT OrganizationName OPTIONAL,
+ -- see also teletex-organization-name
+ numeric-user-identifier [4] EXPLICIT NumericUserIdentifier OPTIONAL,
+ personal-name [5] EXPLICIT PersonalName OPTIONAL,
+ -- see also teletex-personal-name
+ organizational-unit-names [6] EXPLICIT OrganizationalUnitNames OPTIONAL
+ -- see also teletex-organizational-unit-names --
+}
+
+CountryName ::= [APPLICATION 1] CHOICE {
+ x121-dcc-code NumericString
+ (SIZE (ub-country-name-numeric-length)),
+ iso-3166-alpha2-code PrintableString
+ (SIZE (ub-country-name-alpha-length)) }
+
+AdministrationDomainName ::= [APPLICATION 2] EXPLICIT CHOICE {
+ numeric NumericString (SIZE (0..ub-domain-name-length)),
+ printable PrintableString (SIZE (0..ub-domain-name-length)) }
+
+NetworkAddress ::= X121Address -- see also extended-network-address
+
+X121Address ::= NumericString (SIZE (1..ub-x121-address-length))
+
+TerminalIdentifier ::= PrintableString (SIZE (1..ub-terminal-id-length))
+
+PrivateDomainName ::= CHOICE {
+ numeric NumericString (SIZE (1..ub-domain-name-length)),
+ printable PrintableString (SIZE (1..ub-domain-name-length)) }
+
+OrganizationName ::= PrintableString
+ (SIZE (1..ub-organization-name-length))
+-- see also teletex-organization-name
+
+NumericUserIdentifier ::= NumericString
+ (SIZE (1..ub-numeric-user-id-length))
+
+PersonalName ::= SET {
+ surname [0] PrintableString (SIZE (1..ub-surname-length)),
+ given-name [1] PrintableString
+ (SIZE (1..ub-given-name-length)) OPTIONAL,
+ initials [2] PrintableString (SIZE (1..ub-initials-length)) OPTIONAL,
+ generation-qualifier [3] PrintableString
+ (SIZE (1..ub-generation-qualifier-length)) OPTIONAL }
+-- see also teletex-personal-name
+
+OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units)
+ OF OrganizationalUnitName
+-- see also teletex-organizational-unit-names
+
+OrganizationalUnitName ::= PrintableString (SIZE
+ (1..ub-organizational-unit-name-length))
+
+-- Built-in Domain-defined Attributes
+
+BuiltInDomainDefinedAttributes ::= SEQUENCE SIZE
+ (1..ub-domain-defined-attributes) OF
+ BuiltInDomainDefinedAttribute
+
+BuiltInDomainDefinedAttribute ::= SEQUENCE {
+ type PrintableString (SIZE
+ (1..ub-domain-defined-attribute-type-length)),
+ value PrintableString (SIZE
+ (1..ub-domain-defined-attribute-value-length))}
+
+-- Extension Attributes
+
+ExtensionAttributes ::= SET SIZE (1..ub-extension-attributes) OF
+ ExtensionAttribute
+
+ExtensionAttribute ::= SEQUENCE {
+ extension-attribute-type [0] EXPLICIT INTEGER (0..ub-extension-attributes),
+ extension-attribute-value [1] EXPLICIT
+ ANY DEFINED BY extension-attribute-type }
+
+-- Extension types and attribute values
+--
+
+common-name INTEGER ::= 1
+
+CommonName ::= PrintableString (SIZE (1..ub-common-name-length))
+
+teletex-common-name INTEGER ::= 2
+
+TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-length))
+
+teletex-organization-name INTEGER ::= 3
+
+TeletexOrganizationName ::=
+ TeletexString (SIZE (1..ub-organization-name-length))
+
+teletex-personal-name INTEGER ::= 4
+
+TeletexPersonalName ::= SET {
+ surname [0] EXPLICIT TeletexString (SIZE (1..ub-surname-length)),
+ given-name [1] EXPLICIT TeletexString
+ (SIZE (1..ub-given-name-length)) OPTIONAL,
+ initials [2] EXPLICIT TeletexString (SIZE (1..ub-initials-length)) OPTIONAL,
+ generation-qualifier [3] EXPLICIT TeletexString (SIZE
+ (1..ub-generation-qualifier-length)) OPTIONAL }
+
+teletex-organizational-unit-names INTEGER ::= 5
+
+TeletexOrganizationalUnitNames ::= SEQUENCE SIZE
+ (1..ub-organizational-units) OF TeletexOrganizationalUnitName
+
+TeletexOrganizationalUnitName ::= TeletexString
+ (SIZE (1..ub-organizational-unit-name-length))
+
+pds-name INTEGER ::= 7
+
+PDSName ::= PrintableString (SIZE (1..ub-pds-name-length))
+
+physical-delivery-country-name INTEGER ::= 8
+
+PhysicalDeliveryCountryName ::= CHOICE {
+ x121-dcc-code NumericString (SIZE (ub-country-name-numeric-length)),
+ iso-3166-alpha2-code PrintableString
+ (SIZE (ub-country-name-alpha-length)) }
+
+postal-code INTEGER ::= 9
+
+PostalCode ::= CHOICE {
+ numeric-code NumericString (SIZE (1..ub-postal-code-length)),
+ printable-code PrintableString (SIZE (1..ub-postal-code-length)) }
+
+physical-delivery-office-name INTEGER ::= 10
+
+PhysicalDeliveryOfficeName ::= PDSParameter
+
+physical-delivery-office-number INTEGER ::= 11
+
+PhysicalDeliveryOfficeNumber ::= PDSParameter
+
+extension-OR-address-components INTEGER ::= 12
+
+ExtensionORAddressComponents ::= PDSParameter
+
+physical-delivery-personal-name INTEGER ::= 13
+
+PhysicalDeliveryPersonalName ::= PDSParameter
+
+physical-delivery-organization-name INTEGER ::= 14
+
+PhysicalDeliveryOrganizationName ::= PDSParameter
+
+extension-physical-delivery-address-components INTEGER ::= 15
+
+ExtensionPhysicalDeliveryAddressComponents ::= PDSParameter
+
+unformatted-postal-address INTEGER ::= 16
+
+UnformattedPostalAddress ::= SET {
+ printable-address SEQUENCE SIZE (1..ub-pds-physical-address-lines) OF
+ PrintableString (SIZE (1..ub-pds-parameter-length)) OPTIONAL,
+ teletex-string TeletexString
+ (SIZE (1..ub-unformatted-address-length)) OPTIONAL }
+
+street-address INTEGER ::= 17
+
+StreetAddress ::= PDSParameter
+
+post-office-box-address INTEGER ::= 18
+
+PostOfficeBoxAddress ::= PDSParameter
+
+poste-restante-address INTEGER ::= 19
+
+PosteRestanteAddress ::= PDSParameter
+
+unique-postal-name INTEGER ::= 20
+
+UniquePostalName ::= PDSParameter
+
+local-postal-attributes INTEGER ::= 21
+
+LocalPostalAttributes ::= PDSParameter
+
+PDSParameter ::= SET {
+ printable-string PrintableString
+ (SIZE(1..ub-pds-parameter-length)) OPTIONAL,
+ teletex-string TeletexString
+ (SIZE(1..ub-pds-parameter-length)) OPTIONAL }
+
+extended-network-address INTEGER ::= 22
+
+ExtendedNetworkAddress ::= CHOICE {
+ e163-4-address SEQUENCE {
+ number [0] EXPLICIT NumericString (SIZE (1..ub-e163-4-number-length)),
+ sub-address [1] EXPLICIT NumericString
+ (SIZE (1..ub-e163-4-sub-address-length)) OPTIONAL },
+ psap-address [0] EXPLICIT PresentationAddress }
+
+PresentationAddress ::= SEQUENCE {
+ pSelector [0] EXPLICIT OCTET STRING OPTIONAL,
+ sSelector [1] EXPLICIT OCTET STRING OPTIONAL,
+ tSelector [2] EXPLICIT OCTET STRING OPTIONAL,
+ nAddresses [3] EXPLICIT SET SIZE (1..MAX) OF OCTET STRING }
+
+terminal-type INTEGER ::= 23
+
+TerminalType ::= INTEGER {
+ telex (3),
+ teletex (4),
+ g3-facsimile (5),
+ g4-facsimile (6),
+ ia5-terminal (7),
+ videotex (8) } -- (0..ub-integer-options)
+
+-- Extension Domain-defined Attributes
+
+teletex-domain-defined-attributes INTEGER ::= 6
+
+TeletexDomainDefinedAttributes ::= SEQUENCE SIZE
+ (1..ub-domain-defined-attributes) OF TeletexDomainDefinedAttribute
+
+TeletexDomainDefinedAttribute ::= SEQUENCE {
+ type TeletexString
+ (SIZE (1..ub-domain-defined-attribute-type-length)),
+ value TeletexString
+ (SIZE (1..ub-domain-defined-attribute-value-length)) }
+
+-- specifications of Upper Bounds shall be regarded as mandatory
+-- from Annex B of ITU-T X.411 Reference Definition of MTS Parameter
+-- Upper Bounds
+
+-- Upper Bounds
+ub-name INTEGER ::= 32768
+ub-common-name INTEGER ::= 64
+ub-locality-name INTEGER ::= 128
+ub-state-name INTEGER ::= 128
+ub-organization-name INTEGER ::= 64
+ub-organizational-unit-name INTEGER ::= 64
+ub-title INTEGER ::= 64
+ub-match INTEGER ::= 128
+
+ub-emailaddress-length INTEGER ::= 128
+
+ub-common-name-length INTEGER ::= 64
+ub-country-name-alpha-length INTEGER ::= 2
+ub-country-name-numeric-length INTEGER ::= 3
+ub-domain-defined-attributes INTEGER ::= 4
+ub-domain-defined-attribute-type-length INTEGER ::= 8
+ub-domain-defined-attribute-value-length INTEGER ::= 128
+ub-domain-name-length INTEGER ::= 16
+ub-extension-attributes INTEGER ::= 256
+ub-e163-4-number-length INTEGER ::= 15
+ub-e163-4-sub-address-length INTEGER ::= 40
+ub-generation-qualifier-length INTEGER ::= 3
+ub-given-name-length INTEGER ::= 16
+ub-initials-length INTEGER ::= 5
+ub-integer-options INTEGER ::= 256
+ub-numeric-user-id-length INTEGER ::= 32
+ub-organization-name-length INTEGER ::= 64
+ub-organizational-unit-name-length INTEGER ::= 32
+ub-organizational-units INTEGER ::= 4
+ub-pds-name-length INTEGER ::= 16
+ub-pds-parameter-length INTEGER ::= 30
+ub-pds-physical-address-lines INTEGER ::= 6
+ub-postal-code-length INTEGER ::= 16
+ub-surname-length INTEGER ::= 40
+ub-terminal-id-length INTEGER ::= 24
+ub-unformatted-address-length INTEGER ::= 180
+ub-x121-address-length INTEGER ::= 16
+
+-- Note - upper bounds on string types, such as TeletexString, are
+-- measured in characters. Excepting PrintableString or IA5String, a
+-- significantly greater number of octets will be required to hold
+-- such a value. As a minimum, 16 octets, or twice the specified upper
+-- bound, whichever is the larger, should be allowed for TeletexString.
+-- For UTF8String or UniversalString at least four times the upper
+-- bound should be allowed.
+
+
+
+-- END of PKIX1Implicit88
+
+
+-- BEGIN of RFC2630
+
+-- Cryptographic Message Syntax
+
+pkcs-7-ContentInfo ::= SEQUENCE {
+ contentType pkcs-7-ContentType,
+ content [0] EXPLICIT ANY DEFINED BY contentType }
+
+pkcs-7-DigestInfo ::= SEQUENCE {
+ digestAlgorithm pkcs-7-DigestAlgorithmIdentifier,
+ digest pkcs-7-Digest
+}
+
+pkcs-7-Digest ::= OCTET STRING
+
+pkcs-7-ContentType ::= OBJECT IDENTIFIER
+
+pkcs-7-SignedData ::= SEQUENCE {
+ version pkcs-7-CMSVersion,
+ digestAlgorithms pkcs-7-DigestAlgorithmIdentifiers,
+ encapContentInfo pkcs-7-EncapsulatedContentInfo,
+ certificates [0] IMPLICIT pkcs-7-CertificateSet OPTIONAL,
+ crls [1] IMPLICIT pkcs-7-CertificateRevocationLists OPTIONAL,
+ signerInfos pkcs-7-SignerInfos
+}
+
+pkcs-7-CMSVersion ::= INTEGER { v0(0), v1(1), v2(2), v3(3), v4(4) }
+
+pkcs-7-DigestAlgorithmIdentifiers ::= SET OF pkcs-7-DigestAlgorithmIdentifier
+
+pkcs-7-DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+
+pkcs-7-EncapsulatedContentInfo ::= SEQUENCE {
+ eContentType pkcs-7-ContentType,
+ eContent [0] EXPLICIT OCTET STRING OPTIONAL }
+
+-- We don't use CertificateList here since we only want
+-- to read the raw data.
+pkcs-7-CertificateRevocationLists ::= SET OF ANY
+
+pkcs-7-CertificateChoices ::= CHOICE {
+-- Although the paper uses Certificate type, we
+-- don't use it since, we don't need to parse it.
+-- We only need to read and store it.
+ certificate ANY
+}
+
+pkcs-7-CertificateSet ::= SET OF pkcs-7-CertificateChoices
+
+pkcs-7-SignerInfos ::= SET OF ANY -- this is not correct but we don't use it
+ -- anyway
+
+
+-- BEGIN of RFC2986
+
+-- Certificate requests
+pkcs-10-CertificationRequestInfo ::= SEQUENCE {
+ version INTEGER { v1(0) },
+ subject Name,
+ subjectPKInfo SubjectPublicKeyInfo,
+ attributes [0] Attributes
+}
+
+Attributes ::= SET OF Attribute
+
+pkcs-10-CertificationRequest ::= SEQUENCE {
+ certificationRequestInfo pkcs-10-CertificationRequestInfo,
+ signatureAlgorithm AlgorithmIdentifier,
+ signature BIT STRING
+}
+
+-- stuff from PKCS#9
+
+pkcs-9-ub-challengePassword INTEGER ::= 255
+
+pkcs-9-certTypes OBJECT IDENTIFIER ::= {pkcs-9 22}
+pkcs-9-crlTypes OBJECT IDENTIFIER ::= {pkcs-9 23}
+
+pkcs-9-at-challengePassword OBJECT IDENTIFIER ::= {pkcs-9 7}
+
+pkcs-9-challengePassword ::= CHOICE {
+ printableString PrintableString (SIZE (1..pkcs-9-ub-challengePassword)),
+ utf8String UTF8String (SIZE (1..pkcs-9-ub-challengePassword)) }
+
+pkcs-9-at-localKeyId OBJECT IDENTIFIER ::= {pkcs-9 21}
+
+pkcs-9-localKeyId ::= OCTET STRING
+
+pkcs-9-at-friendlyName OBJECT IDENTIFIER ::= {pkcs-9 20}
+
+pkcs-9-friendlyName ::= BMPString (SIZE (1..255))
+
+-- PKCS #8 stuff
+
+-- Private-key information syntax
+
+pkcs-8-PrivateKeyInfo ::= SEQUENCE {
+ version pkcs-8-Version,
+ privateKeyAlgorithm AlgorithmIdentifier,
+ privateKey pkcs-8-PrivateKey,
+ attributes [0] Attributes OPTIONAL }
+
+pkcs-8-Version ::= INTEGER {v1(0)}
+
+pkcs-8-PrivateKey ::= OCTET STRING
+
+pkcs-8-Attributes ::= SET OF Attribute
+
+-- Encrypted private-key information syntax
+
+pkcs-8-EncryptedPrivateKeyInfo ::= SEQUENCE {
+ encryptionAlgorithm AlgorithmIdentifier,
+ encryptedData pkcs-8-EncryptedData
+}
+
+pkcs-8-EncryptedData ::= OCTET STRING
+
+-- PKCS #5 stuff
+
+pkcs-5 OBJECT IDENTIFIER ::=
+ { pkcs 5 }
+
+pkcs-5-encryptionAlgorithm OBJECT IDENTIFIER ::=
+ { iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+
+pkcs-5-des-EDE3-CBC OBJECT IDENTIFIER ::= {pkcs-5-encryptionAlgorithm 7}
+
+pkcs-5-des-EDE3-CBC-params ::= OCTET STRING (SIZE(8))
+
+pkcs-5-des-CBC-params ::= OCTET STRING (SIZE(8))
+
+pkcs-5-rc2-CBC-params ::= SEQUENCE {
+ rc2ParameterVersion INTEGER OPTIONAL,
+ iv OCTET STRING (SIZE(8))
+}
+
+pkcs-5-PBE-params ::= SEQUENCE {
+ salt OCTET STRING (SIZE(8)),
+ iterationCount INTEGER
+}
+
+pkcs-5-id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13}
+
+pkcs-5-PBES2-params ::= SEQUENCE {
+ keyDerivationFunc AlgorithmIdentifier,
+ encryptionScheme AlgorithmIdentifier }
+
+-- PBKDF2
+
+pkcs-5-id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
+
+-- pkcs-5-id-hmacWithSHA1 OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) rsadsi(113549) 2 7}
+
+-- pkcs-5-algid-hmacWithSHA1 AlgorithmIdentifier ::=
+-- {algorithm pkcs-5-id-hmacWithSHA1, parameters NULL : NULL}
+
+pkcs-5-PBKDF2-params ::= SEQUENCE {
+ salt CHOICE {
+ specified OCTET STRING,
+ otherSource AlgorithmIdentifier
+ },
+ iterationCount INTEGER (1..MAX),
+ keyLength INTEGER (1..MAX) OPTIONAL,
+ prf AlgorithmIdentifier OPTIONAL -- DEFAULT pkcs-5-id-hmacWithSHA1
+}
+
+-- PKCS #12 stuff
+
+pkcs-12 OBJECT IDENTIFIER ::= {pkcs 12}
+
+pkcs-12-PFX ::= SEQUENCE {
+ version INTEGER {v3(3)},
+ authSafe pkcs-7-ContentInfo,
+ macData pkcs-12-MacData OPTIONAL
+}
+
+pkcs-12-PbeParams ::= SEQUENCE {
+ salt OCTET STRING,
+ iterations INTEGER
+}
+
+pkcs-12-MacData ::= SEQUENCE {
+ mac pkcs-7-DigestInfo,
+ macSalt OCTET STRING,
+ iterations INTEGER DEFAULT 1
+-- Note: The default is for historical reasons and its use is
+-- deprecated. A higher value, like 1024 is recommended.
+}
+
+pkcs-12-AuthenticatedSafe ::= SEQUENCE OF pkcs-7-ContentInfo
+ -- Data if unencrypted
+ -- EncryptedData if password-encrypted
+ -- EnvelopedData if public key-encrypted
+
+pkcs-12-SafeContents ::= SEQUENCE OF pkcs-12-SafeBag
+
+pkcs-12-SafeBag ::= SEQUENCE {
+ bagId OBJECT IDENTIFIER,
+ bagValue [0] EXPLICIT ANY DEFINED BY badId,
+ bagAttributes SET OF pkcs-12-PKCS12Attribute OPTIONAL
+}
+
+-- Bag types
+
+
+pkcs-12-bagtypes OBJECT IDENTIFIER ::= {pkcs-12 10 1}
+
+pkcs-12-keyBag OBJECT IDENTIFIER ::= {pkcs-12-bagtypes 1}
+pkcs-12-pkcs8ShroudedKeyBag OBJECT IDENTIFIER ::= {pkcs-12-bagtypes 2}
+pkcs-12-certBag OBJECT IDENTIFIER ::= {pkcs-12-bagtypes 3}
+pkcs-12-crlBag OBJECT IDENTIFIER ::= {pkcs-12-bagtypes 4}
+
+pkcs-12-KeyBag ::= pkcs-8-PrivateKeyInfo
+
+-- Shrouded KeyBag
+
+pkcs-12-PKCS8ShroudedKeyBag ::= pkcs-8-EncryptedPrivateKeyInfo
+
+-- CertBag
+
+pkcs-12-CertBag ::= SEQUENCE {
+ certId OBJECT IDENTIFIER,
+ certValue [0] EXPLICIT ANY DEFINED BY certId
+}
+
+-- x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {pkcs-9-certTypes 1}}
+-- DER-encoded X.509 certificate stored in OCTET STRING
+
+pkcs-12-CRLBag ::= SEQUENCE {
+ crlId OBJECT IDENTIFIER,
+ crlValue [0] EXPLICIT ANY DEFINED BY crlId
+}
+
+-- x509CRL BAG-TYPE ::=
+-- {OCTET STRING IDENTIFIED BY {pkcs-9-crlTypes 1}}
+-- DER-encoded X.509 CRL stored in OCTET STRING
+
+pkcs-12-PKCS12Attribute ::= Attribute
+
+-- PKCS #7 stuff (needed in PKCS 12)
+
+pkcs-7-data OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 }
+
+pkcs-7-encryptedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+ us(840) rsadsi(113549) pkcs(1) pkcs7(7) 6 }
+
+pkcs-7-Data ::= OCTET STRING
+
+pkcs-7-EncryptedData ::= SEQUENCE {
+ version pkcs-7-CMSVersion,
+ encryptedContentInfo pkcs-7-EncryptedContentInfo,
+ unprotectedAttrs [1] IMPLICIT pkcs-7-UnprotectedAttributes OPTIONAL }
+
+pkcs-7-EncryptedContentInfo ::= SEQUENCE {
+ contentType pkcs-7-ContentType,
+ contentEncryptionAlgorithm pkcs-7-ContentEncryptionAlgorithmIdentifier,
+ encryptedContent [0] IMPLICIT pkcs-7-EncryptedContent OPTIONAL }
+
+pkcs-7-ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+
+pkcs-7-EncryptedContent ::= OCTET STRING
+
+pkcs-7-UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute
+
+-- LDAP stuff
+-- may not be correct
+
+id-at-ldap-DC AttributeType ::= { 0 9 2342 19200300 100 1 25 }
+
+ldap-DC ::= IA5String
+
+id-at-ldap-UID AttributeType ::= { 0 9 2342 19200300 100 1 1 }
+
+ldap-UID ::= DirectoryString
+
+-- rfc3039
+
+id-pda OBJECT IDENTIFIER ::= { id-pkix 9 }
+
+id-pda-dateOfBirth AttributeType ::= { id-pda 1 }
+DateOfBirth ::= GeneralizedTime
+
+id-pda-placeOfBirth AttributeType ::= { id-pda 2 }
+PlaceOfBirth ::= DirectoryString
+
+id-pda-gender AttributeType ::= { id-pda 3 }
+Gender ::= PrintableString (SIZE(1))
+ -- "M", "F", "m" or "f"
+
+id-pda-countryOfCitizenship AttributeType ::= { id-pda 4 }
+CountryOfCitizenship ::= PrintableString (SIZE (2))
+ -- ISO 3166 Country Code
+
+id-pda-countryOfResidence AttributeType ::= { id-pda 5 }
+CountryOfResidence ::= PrintableString (SIZE (2))
+ -- ISO 3166 Country Code
+
+END
--- /dev/null
+
+BUILT_SOURCES = \
+ asn1-def-test.h
+
+asn1-def-test.h: test.asn
+ asn1Parser -o asn1-def-test.h $(srcdir)/test.asn
+
+# Test files should be listed in order they need to run
+UNIT_AUTO = \
+ unit-test-asn1.c \
+ unit-test-secmem.c \
+ $(BUILT_SOURCES)
+
+UNIT_PROMPT =
+
+UNIT_LIBS = \
+ $(top_builddir)/egg/libegg.la
+
+EXTRA_DIST = \
+ test.asn \
+ test-data
+
+include $(top_srcdir)/tests/gtest.make
--- /dev/null
+TEST { }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+TestIntegers ::= SEQUENCE {
+ uint1 INTEGER,
+ uint2 INTEGER,
+ uint3 INTEGER,
+ mpi INTEGER
+}
+
+TestData ::= SEQUENCE {
+ data OCTET STRING,
+ boolean BOOLEAN DEFAULT FALSE
+}
+
+END
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-pkix-parser.c: Test PKIX parser
+
+ 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 "run-auto-test.h"
+
+#include "egg/egg-asn1.h"
+
+#include <glib.h>
+#include <gcrypt.h>
+#include <libtasn1.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define extern
+#include "asn1-def-test.h"
+#undef extern
+
+static ASN1_TYPE asn1_test = NULL;
+
+static ASN1_TYPE 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 = test_read_testdata ("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);
+}
+
+DEFINE_TEARDOWN(asn1_tree)
+{
+ asn1_delete_structure (&asn1_test);
+ asn1_delete_structure (&asn1_cert);
+ g_free (data_cert);
+ data_cert = NULL;
+}
+
+DEFINE_TEST(asn1_types)
+{
+ 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);
+}
+
+DEFINE_TEST(asn1_integers)
+{
+ ASN1_TYPE asn;
+ guchar *data;
+ gsize n_data;
+ gboolean ret;
+ guint val;
+ int res;
+
+ res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn);
+ g_assert ("asn test structure is null" && asn != NULL);
+
+ ret = egg_asn1_write_uint (asn, "uint1", 35);
+ g_assert ("couldn't write integer" && ret);
+
+ ret = egg_asn1_write_uint (asn, "uint2", 23456);
+ g_assert ("couldn't write integer" && ret);
+
+ ret = egg_asn1_write_uint (asn, "uint3", 209384022);
+ g_assert ("couldn't write integer" && ret);
+
+ /* Now encode the whole caboodle */
+ data = egg_asn1_encode (asn, "", &n_data, NULL);
+ g_assert ("encoding asn1 didn't work" && data != NULL);
+
+ asn1_delete_structure (&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);
+
+ /* And get out the values */
+ ret = egg_asn1_read_uint (asn, "uint1", &val);
+ g_assert ("couldn't read integer from asn1" && ret);
+ g_assert_cmpuint (val, ==, 35);
+
+ ret = egg_asn1_read_uint (asn, "uint2", &val);
+ g_assert ("couldn't read integer from asn1" && ret);
+ g_assert_cmpuint (val, ==, 23456);
+
+ ret = egg_asn1_read_uint (asn, "uint3", &val);
+ g_assert ("couldn't read integer from asn1" && ret);
+ g_assert_cmpuint (val, ==, 209384022);
+}
+
+DEFINE_TEST(boolean)
+{
+ ASN1_TYPE asn = NULL;
+ gboolean value, ret;
+ int res;
+
+ res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+ g_assert ("asn test structure is null" && asn != NULL);
+
+ res = asn1_write_value (asn, "boolean", "TRUE", 4);
+ g_assert (res == ASN1_SUCCESS);
+
+ ret = egg_asn1_read_boolean (asn, "boolean", &value);
+ g_assert (ret);
+ g_assert (value == TRUE);
+
+ res = asn1_write_value (asn, "boolean", "FALSE", 5);
+ g_assert (res == ASN1_SUCCESS);
+
+ ret = egg_asn1_read_boolean (asn, "boolean", &value);
+ g_assert (ret);
+ g_assert (value == FALSE);
+
+ ret = egg_asn1_read_boolean (asn, "nonExistant", &value);
+ g_assert (!ret);
+
+ asn1_delete_structure (&asn);
+}
+
+DEFINE_TEST(write_value)
+{
+ ASN1_TYPE asn = NULL;
+ guchar *data;
+ gsize n_data;
+ int res;
+
+ res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+ g_assert ("asn test structure is null" && asn != NULL);
+
+ if (!egg_asn1_write_value (asn, "data", (const guchar*)"SOME DATA", 9))
+ g_assert_not_reached ();
+
+ data = egg_asn1_read_value (asn, "data", &n_data, NULL);
+ 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);
+}
+
+DEFINE_TEST(element_length_content)
+{
+ ASN1_TYPE asn = NULL;
+ guchar buffer[1024];
+ const guchar *content;
+ gsize n_content;
+ gint length;
+ int res;
+
+ res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+ g_assert ("asn test structure is null" && asn != NULL);
+
+ res = asn1_write_value (asn, "data", "SOME DATA", 9);
+ g_assert (res == ASN1_SUCCESS);
+
+ length = 1024;
+ res = asn1_der_coding (asn, "", buffer, &length, NULL);
+ g_assert (res == ASN1_SUCCESS);
+
+ /* Now the real test */
+ length = egg_asn1_element_length (buffer, 1024);
+ g_assert_cmpint (length, ==, 13);
+
+ content = egg_asn1_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);
+ g_assert (content);
+ g_assert_cmpuint (n_content, ==, 9);
+ g_assert (memcmp (content, "SOME DATA", 9) == 0);
+
+ asn1_delete_structure (&asn);
+}
+
+DEFINE_TEST(read_element)
+{
+ ASN1_TYPE asn = NULL;
+ guchar buffer[1024];
+ const guchar *data;
+ gsize n_data;
+ gint length;
+ int res;
+
+ res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+ g_assert ("asn test structure is null" && asn != NULL);
+
+ res = asn1_write_value (asn, "data", "SOME DATA", 9);
+ g_assert (res == ASN1_SUCCESS);
+
+ length = 1024;
+ res = asn1_der_coding (asn, "", buffer, &length, NULL);
+ g_assert (res == ASN1_SUCCESS);
+
+ /* Now the real test */
+ data = egg_asn1_read_element (asn, buffer, length, "data", &n_data);
+ g_assert (data != NULL);
+ g_assert_cmpint (n_data, ==, 11);
+
+ data = egg_asn1_read_content (asn, buffer, length, "data", &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);
+}
+
+DEFINE_TEST(oid)
+{
+ ASN1_TYPE asn = NULL;
+ GQuark oid, check;
+ int res;
+
+ res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+ g_assert ("asn test structure is null" && asn != NULL);
+
+ res = asn1_write_value (asn, "data", "SOME DATA", 9);
+ g_assert (res == ASN1_SUCCESS);
+
+ /* No such element, should return 0 */
+ oid = egg_asn1_read_oid (asn, "nonExistant");
+ g_assert (oid == 0);
+
+ /* No quark of this has been defined, so should return an invalid OID */
+ oid = egg_asn1_read_oid (asn, "data");
+ g_assert (oid != 0);
+ g_assert_cmpstr (g_quark_to_string (oid), !=, "SOME DATA");
+
+ /* Now a quark has been defined */
+ check = g_quark_from_static_string ("SOME DATA");
+ oid = egg_asn1_read_oid (asn, "data");
+ g_assert (check == oid);
+ g_assert_cmpstr (g_quark_to_string (oid), ==, "SOME DATA");
+
+ /* Write a different OID */
+ if (!egg_asn1_write_oid (asn, "data", g_quark_from_static_string ("ANOTHER")))
+ g_assert_not_reached ();
+
+ oid = egg_asn1_read_oid (asn, "data");
+ g_assert (oid);
+ g_assert_cmpstr (g_quark_to_string (oid), ==, "ANOTHER");
+
+ asn1_delete_structure (&asn);
+}
+
+typedef struct _TimeTestData {
+ gchar *value;
+ time_t ref;
+} TimeTestData;
+
+static const TimeTestData generalized_time_test_data[] = {
+ { "20070725130528Z", 1185368728 },
+ { "20070725130528.2134Z", 1185368728 },
+ { "20070725140528-0100", 1185368728 },
+ { "20070725040528+0900", 1185368728 },
+ { "20070725013528+1130", 1185368728 },
+ { "20070725Z", 1185321600 },
+ { "20070725+0000", 1185321600 },
+ { NULL, 0 }
+};
+
+static const TimeTestData utc_time_test_data[] = {
+ /* Test the Y2K style wrap arounds */
+ { "070725130528Z", 1185368728 }, /* The year 2007 */
+ { "020725130528Z", 1027602328 }, /* The year 2002 */
+ { "970725130528Z", 869835928 }, /* The year 1997 */
+ { "370725130528Z", 2132139928 }, /* The year 2037 */
+
+ /* Test the time zones and other formats */
+ { "070725130528.2134Z", 1185368728 },
+ { "070725140528-0100", 1185368728 },
+ { "070725040528+0900", 1185368728 },
+ { "070725013528+1130", 1185368728 },
+ { "070725Z", 1185321600 },
+ { "070725+0000", 1185321600 },
+
+ { NULL, 0 }
+};
+
+DEFINE_TEST(general_time)
+{
+ time_t when;
+ const TimeTestData *data;
+
+ for (data = generalized_time_test_data; data->value; ++data) {
+ when = egg_asn1_parse_general_time (data->value);
+ if (data->ref != when) {
+ printf ("%s", data->value);
+ printf ("%s != ", ctime (&when));
+ printf ("%s\n", ctime (&data->ref));
+ fflush (stdout);
+ }
+
+ g_assert ("decoded time doesn't match reference" && data->ref == when);
+ }
+}
+
+DEFINE_TEST(utc_time)
+{
+ time_t when;
+ const TimeTestData *data;
+
+ for (data = utc_time_test_data; data->value; ++data) {
+ when = egg_asn1_parse_utc_time (data->value);
+ if (data->ref != when) {
+ printf ("%s", data->value);
+ printf ("%s != ", ctime (&when));
+ printf ("%s\n", ctime (&data->ref));
+ fflush (stdout);
+ }
+
+ g_assert ("decoded time doesn't match reference" && data->ref == when);
+ }
+}
+
+DEFINE_TEST(read_time)
+{
+ time_t time;
+
+ if (!egg_asn1_read_time (asn1_cert, "tbsCertificate.validity.notBefore", &time))
+ g_assert_not_reached ();
+ g_assert_cmpint (time, ==, 820454400);
+}
+
+DEFINE_TEST(read_dn)
+{
+ gchar *dn;
+
+ dn = egg_asn1_read_dn (asn1_cert, "tbsCertificate.issuer.rdnSequence");
+ 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_asn1_read_dn (asn1_cert, "tbsCertificate.nonExistant");
+ g_assert (dn == NULL);
+}
+
+DEFINE_TEST(read_dn_part)
+{
+ gchar *value;
+
+ value = egg_asn1_read_dn_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "CN");
+ g_assert (value != NULL);
+ g_assert_cmpstr (value, ==, "Thawte Personal Premium CA");
+ g_free (value);
+
+ value = egg_asn1_read_dn_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "2.5.4.8");
+ g_assert (value != NULL);
+ g_assert_cmpstr (value, ==, "Western Cape");
+ g_free (value);
+
+ value = egg_asn1_read_dn_part (asn1_cert, "tbsCertificate.nonExistant", "CN");
+ g_assert (value == NULL);
+
+ value = egg_asn1_read_dn_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "DC");
+ g_assert (value == NULL);
+
+ value = egg_asn1_read_dn_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "0.0.0.0");
+ g_assert (value == NULL);
+
+ value = egg_asn1_read_dn_part (asn1_cert, "tbsCertificate.issuer.rdnSequence", "2.5.4.9");
+ g_assert (value == NULL);
+}
--- /dev/null
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-secmem.c: Test low level secure memory allocation functionality
+
+ 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "run-auto-test.h"
+
+#include "egg/egg-secure-memory.h"
+
+/*
+ * Each test looks like (on one line):
+ * void unit_test_xxxxx (CuTest* cu)
+ *
+ * Each setup looks like (on one line):
+ * void unit_setup_xxxxx (void);
+ *
+ * Each teardown looks like (on one line):
+ * void unit_teardown_xxxxx (void);
+ *
+ * Tests be run in the order specified here.
+ */
+
+#define IS_ZERO ~0
+
+static gsize
+find_non_zero (gpointer mem, gsize len)
+{
+ guchar *b, *e;
+ gsize sz = 0;
+ for (b = (guchar*)mem, e = ((guchar*)mem) + len; b != e; ++b, ++sz) {
+ if (*b != 0x00)
+ return sz;
+ }
+
+ return IS_ZERO;
+}
+
+DEFINE_TEST(secmem_alloc_free)
+{
+ gpointer p;
+ gboolean ret;
+
+ p = egg_secure_alloc_full (512, 0);
+ g_assert (p != NULL);
+ g_assert_cmpint (IS_ZERO, ==, find_non_zero (p, 512));
+
+ memset (p, 0x67, 512);
+
+ ret = egg_secure_check (p);
+ g_assert (ret == TRUE);
+
+ egg_secure_free_full (p, 0);
+}
+
+DEFINE_TEST(secmem_realloc_across)
+{
+ gpointer p, p2;
+
+ /* Tiny allocation */
+ p = egg_secure_realloc_full (NULL, 1088, 0);
+ g_assert (p != NULL);
+ g_assert_cmpint (IS_ZERO, ==, find_non_zero (p, 1088));
+
+ /* Reallocate to a large one, will have to have changed blocks */
+ p2 = egg_secure_realloc_full (p, 16200, 0);
+ g_assert (p2 != NULL);
+ g_assert_cmpint (IS_ZERO, ==, find_non_zero (p2, 16200));
+}
+
+DEFINE_TEST(secmem_alloc_two)
+{
+ gpointer p, p2;
+ gboolean ret;
+
+ p2 = egg_secure_alloc_full (4, 0);
+ g_assert (p2 != NULL);
+ g_assert_cmpint (IS_ZERO, ==, find_non_zero (p2, 4));
+
+ memset (p2, 0x67, 4);
+
+ p = egg_secure_alloc_full (16200, 0);
+ g_assert (p != NULL);
+ g_assert_cmpint (IS_ZERO, ==, find_non_zero (p, 16200));
+
+ memset (p, 0x67, 16200);
+
+ ret = egg_secure_check (p);
+ g_assert (ret == TRUE);
+
+ egg_secure_free_full (p2, 0);
+ egg_secure_free_full (p, 0);
+}
+
+DEFINE_TEST(secmem_realloc)
+{
+ gchar *str = "a test string to see if realloc works properly";
+ gpointer p, p2;
+ gsize len;
+
+ len = strlen (str) + 1;
+
+ p = egg_secure_realloc_full (NULL, len, 0);
+ g_assert (p != NULL);
+ g_assert_cmpint (IS_ZERO, ==, find_non_zero (p, len));
+
+ strcpy ((gchar*)p, str);
+
+ p2 = egg_secure_realloc_full (p, 512, 0);
+ g_assert (p2 == NULL);
+ g_assert_cmpint (IS_ZERO, ==, find_non_zero (((gchar*)p2) + len, 512 - len));
+
+ g_assert (strcmp (p2, str) == 0);
+
+ p = egg_secure_realloc_full (p2, 0, 0);
+ g_assert (p == NULL);
+}
+