gnome-keyring r1480 - in trunk: . egg egg/tests gcr gcr/tests po



Author: nnielsen
Date: Wed Jan 28 01:38:38 2009
New Revision: 1480
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1480&view=rev

Log:
	* egg/egg-asn1.c:
	* egg/egg-asn1.h:
	* egg/egg-hex.c:
	* egg/egg-hex.h:
	* egg/pkix.asn:
	* egg/tests/unit-test-asn1.c:
	* egg/tests/unit-test-hex.c:
	* gcr/gcr-certificate.c: (added)
	* gcr/gcr-certificate.h: (added)
	* gcr/gcr-certificate-basics-widget.c: (added)
	* gcr/gcr-certificate-basics-widget.glade: (added)
	* gcr/gcr-certificate-basics-widget.h: (added)
	* gcr/gcr-certificate-details-widget.c: (added)
	* gcr/gcr-certificate-details-widget.h: (added)
	* gcr/gcr-library.c:
	* gcr/gcr-parser.c: 
	* gcr/Makefile.am:
	* gcr/tests/Makefile.am:
	* gcr/tests/ui-test-details.c: (added)
	* gcr/tests/unit-test-certificate.c: (added) Add basic UI widgets for 
	displaying a certificate. 

Added:
   trunk/gcr/gcr-certificate-basics-widget.c
   trunk/gcr/gcr-certificate-basics-widget.glade
   trunk/gcr/gcr-certificate-basics-widget.h
   trunk/gcr/gcr-certificate-details-widget.c
   trunk/gcr/gcr-certificate-details-widget.h
   trunk/gcr/gcr-certificate.c
   trunk/gcr/gcr-certificate.h
   trunk/gcr/tests/ui-test-details.c
   trunk/gcr/tests/unit-test-certificate.c
Modified:
   trunk/ChangeLog
   trunk/egg/egg-asn1.c
   trunk/egg/egg-asn1.h
   trunk/egg/egg-hex.c
   trunk/egg/egg-hex.h
   trunk/egg/pkix.asn
   trunk/egg/tests/unit-test-asn1.c
   trunk/egg/tests/unit-test-hex.c
   trunk/gcr/   (props changed)
   trunk/gcr/Makefile.am
   trunk/gcr/gcr-library.c
   trunk/gcr/gcr-parser.c
   trunk/gcr/tests/   (props changed)
   trunk/gcr/tests/Makefile.am
   trunk/po/ChangeLog
   trunk/po/POTFILES.in
   trunk/po/POTFILES.skip

Modified: trunk/egg/egg-asn1.c
==============================================================================
--- trunk/egg/egg-asn1.c	(original)
+++ trunk/egg/egg-asn1.c	Wed Jan 28 01:38:38 2009
@@ -29,6 +29,8 @@
 
 #include <string.h>
 
+#include <glib/gi18n-lib.h>
+
 /* 
  * HACK: asn1Parser defines these arrays as extern const, which gives 
  * gcc a fit. So we def it out. 
@@ -439,25 +441,27 @@
 }
 #endif //NOT_HAVE_TIMEGM
 
-time_t
-egg_asn1_parse_utc_time (const gchar *time)
+static gboolean
+parse_utc_time (const gchar *time, struct tm* when, gint *offset)
 {
-	struct tm when;
 	guint n_time;
-	time_t result;
 	const char *p, *e;
 	int year;
 
-	g_assert (time);	
+	g_assert (when);
+	g_assert (time);
+	g_assert (offset);
+	
 	n_time = strlen (time);
 	
 	/* YYMMDDhhmmss.ffff Z | +0000 */
 	if (n_time < 6 || n_time >= 28) 
-		return -1;
+		return FALSE;
 	
 	/* Reset everything to default legal values */
-	memset (&when, 0, sizeof (when));
-	when.tm_mday = 1;
+	memset (when, 0, sizeof (*when));
+	*offset = 0;
+	when->tm_mday = 1;
 	
 	/* Select the digits part of it */
 	p = time;
@@ -471,48 +475,41 @@
 		 * 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;
+		when->tm_year = two_to_four_digit_year (year) - 1900;
 	}
 	if (p + 2 <= e) {
-		when.tm_mon = atoin (p, 2) - 1;
+		when->tm_mon = atoin (p, 2) - 1;
 		p += 2;
 	}
 	if (p + 2 <= e) {
-		when.tm_mday = atoin (p, 2);
+		when->tm_mday = atoin (p, 2);
 		p += 2;
 	}
 	if (p + 2 <= e) {
-		when.tm_hour = atoin (p, 2);
+		when->tm_hour = atoin (p, 2);
 		p += 2;
 	}
 	if (p + 2 <= e) {
-		when.tm_min = atoin (p, 2);
+		when->tm_min = atoin (p, 2);
 		p += 2;
 	}
 	if (p + 2 <= e) {
-		when.tm_sec = atoin (p, 2);
+		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;
+	if (when->tm_year < 0 || when->tm_year > 9999 ||
+	    when->tm_mon < 0 || when->tm_mon > 11 ||
+	    when->tm_mday < 1 || when->tm_mday > 31 ||
+	    when->tm_hour < 0 || when->tm_hour > 23 ||
+	    when->tm_min < 0 || when->tm_min > 59 ||
+	    when->tm_sec < 0 || when->tm_sec > 59)
+	    	return FALSE;
 	    	
 	/* Make sure all that got parsed */
 	if (p != e)
-		return -1;
+		return FALSE;
 
-	/* 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;
 		
@@ -543,81 +540,113 @@
 
 		/* Use TZ offset */		
 		if (neg)
-			result -= off;
+			*offset = 0 - off;
 		else
-			result += off;
+			*offset = off;
 	}
 
 	/* Make sure everything got parsed */	
 	if (p != e)
-		return -1;
+		return FALSE;
 
+	return TRUE;
+}
+
+static time_t
+when_to_time (struct tm *when, gint offset)
+{
+	time_t result;
+	
+	g_assert (when);
+	
+	/* In order to work with 32 bit time_t. */
+  	if (sizeof (time_t) <= 4 && when->tm_year >= 2038)
+		return (time_t) 2145914603;  /* 2037-12-31 23:23:23 */
+	
+	/* Convert to seconds since epoch */
+	result = timegm (when);
+	if (result >= 0) 
+		result += offset;
+	
 	return result;
 }
 
 time_t
-egg_asn1_parse_general_time (const gchar *time)
+egg_asn1_time_parse_utc (const gchar *time)
 {
 	struct tm when;
-	guint n_time;
-	time_t result;
+	gint offset;
+	
+	g_return_val_if_fail (time, -1);
+	
+	if (!parse_utc_time (time, &when, &offset))
+		return -1;
+	
+	return when_to_time (&when, offset);
+}
+
+static gboolean
+parse_general_time (const gchar *time, struct tm* when, gint *offset)
+{
 	const char *p, *e;
+	guint n_time;
 
-	g_assert (time);	
+	g_assert (time);
+	g_assert (when);
+	g_assert (offset);
+	
 	n_time = strlen (time);
 	
 	/* YYYYMMDDhhmmss.ffff Z | +0000 */
 	if (n_time < 8 || n_time >= 30) 
-		return -1;
+		return FALSE;
 	
 	/* Reset everything to default legal values */
-	memset (&when, 0, sizeof (when));
-	when.tm_mday = 1;
+	memset (when, 0, sizeof (*when));
+	*offset = 0;
+	when->tm_mday = 1;
 	
 	/* Select the digits part of it */
 	p = time;
 	for (e = p; *e >= '0' && *e <= '9'; ++e);
 	
 	if (p + 4 <= e) {
-		when.tm_year = atoin (p, 4) - 1900;
+		when->tm_year = atoin (p, 4) - 1900;
 		p += 4;
 	}
 	if (p + 2 <= e) {
-		when.tm_mon = atoin (p, 2) - 1;
+		when->tm_mon = atoin (p, 2) - 1;
 		p += 2;
 	}
 	if (p + 2 <= e) {
-		when.tm_mday = atoin (p, 2);
+		when->tm_mday = atoin (p, 2);
 		p += 2;
 	}
 	if (p + 2 <= e) {
-		when.tm_hour = atoin (p, 2);
+		when->tm_hour = atoin (p, 2);
 		p += 2;
 	}
 	if (p + 2 <= e) {
-		when.tm_min = atoin (p, 2);
+		when->tm_min = atoin (p, 2);
 		p += 2;
 	}
 	if (p + 2 <= e) {
-		when.tm_sec = atoin (p, 2);
+		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;
+	if (when->tm_year < 0 || when->tm_year > 9999 ||
+	    when->tm_mon < 0 || when->tm_mon > 11 ||
+	    when->tm_mday < 1 || when->tm_mday > 31 ||
+	    when->tm_hour < 0 || when->tm_hour > 23 ||
+	    when->tm_min < 0 || when->tm_min > 59 ||
+	    when->tm_sec < 0 || when->tm_sec > 59)
+	    	return FALSE;
 	
 	/* Make sure all that got parsed */
 	if (p != e)
-		return -1;
+		return FALSE;
 		
-	/* Covnvert to seconds since epoch */
-	result = timegm (&when);
-	
 	/* Now the remaining optional stuff */
 	e = time + n_time;
 		
@@ -648,25 +677,43 @@
 
 		/* Use TZ offset */		
 		if (neg)
-			result -= off;
+			*offset = 0 - off;
 		else
-			result += off;
+			*offset = off;
 	}
 
 	/* Make sure everything got parsed */	
 	if (p != e)
-		return -1;
+		return FALSE;
 
-	return result;
+	return TRUE;
 }
 
-gboolean
-egg_asn1_read_time (ASN1_TYPE asn, const gchar *part, time_t *val)
+time_t
+egg_asn1_time_parse_general (const gchar *time)
 {
-	#define MAX_TIME 1024
-	gchar ttime[MAX_TIME];
+	struct tm when;
+	gint offset;
+	
+	g_return_val_if_fail (time, -1);
+	
+	if (!parse_general_time (time, &when, &offset))
+		return -1;
+	
+	return when_to_time (&when, offset);
+}
+
+static gboolean
+read_asn1_time (ASN1_TYPE asn, const gchar *part, struct tm *when, gint *offset)
+{
+	gchar ttime[256];
 	gchar *name;
 	int len, res;
+	
+	g_assert (asn);
+	g_assert (part);
+	g_assert (when);
+	g_assert (offset);
 
 	len = sizeof (ttime) - 1;
 	res = asn1_read_value (asn, part, ttime, &len);
@@ -681,8 +728,7 @@
 		g_free (name);
 		if (res != ASN1_SUCCESS)
 			return FALSE;
-		
-		*val = egg_asn1_parse_general_time (ttime);
+		return parse_general_time (ttime, when, offset);
 		
 	/* UTCTIME */
 	} else {
@@ -692,16 +738,45 @@
 		g_free (name);
 		if (res != ASN1_SUCCESS)
 			return FALSE;
-	
-		*val = egg_asn1_parse_utc_time (ttime);
+		return parse_utc_time (ttime, when, offset);
     	}
 
-	if (*val < (time_t)0)
+	return FALSE;	
+}
+
+gboolean
+egg_asn1_read_time (ASN1_TYPE asn, const gchar *part, time_t *val)
+{
+	struct tm when;
+	gint offset;
+	
+	g_return_val_if_fail (asn, FALSE);
+	g_return_val_if_fail (part, FALSE);
+	g_return_val_if_fail (val, FALSE);
+	
+	if (!read_asn1_time (asn, part, &when, &offset))
 		return FALSE;
-		
-	return TRUE;	
+	
+	*val = when_to_time (&when, offset);
+	return TRUE;
 }
 
+gboolean
+egg_asn1_read_date (ASN1_TYPE asn, const gchar *part, GDate *date)
+{
+	struct tm when;
+	gint offset;
+	
+	g_return_val_if_fail (asn, FALSE);
+	g_return_val_if_fail (part, FALSE);
+	g_return_val_if_fail (date, FALSE);
+	
+	if (!read_asn1_time (asn, part, &when, &offset))
+		return FALSE;
+	
+	g_date_set_dmy (date, when.tm_mday, when.tm_mon + 1, when.tm_year + 1900);
+	return g_date_valid (date);
+}
 
 /* -------------------------------------------------------------------------------
  * Reading DN's
@@ -710,42 +785,43 @@
 typedef struct _PrintableOid {
 	GQuark oid;
 	const gchar *oidstr;
-	const gchar *display;
+	const gchar *attr;
+	const gchar *description;
 	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, "0.9.2342.19200300.100.1.25", "DC", N_("Domain Component"), FALSE },
+	{ 0, "0.9.2342.19200300.100.1.1", "UID", N_("User ID"), 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, "1.2.840.113549.1.9.1", "EMAIL", N_("Email"), FALSE },
+	{ 0, "1.2.840.113549.1.9.7", NULL, NULL, TRUE },
+	{ 0, "1.2.840.113549.1.9.20", NULL, NULL, FALSE },
+	
+	{ 0, "1.3.6.1.5.5.7.9.1", "dateOfBirth", N_("Date of Birth"), FALSE },
+	{ 0, "1.3.6.1.5.5.7.9.2", "placeOfBirth", N_("Place of Birth"), FALSE },
+	{ 0, "1.3.6.1.5.5.7.9.3", "gender", N_("Gender"), FALSE },
+        { 0, "1.3.6.1.5.5.7.9.4", "countryOfCitizenship", N_("Country of Citizenship"), FALSE },
+        { 0, "1.3.6.1.5.5.7.9.5", "countryOfResidence", N_("Country of Residence"), FALSE },
+
+	{ 0, "2.5.4.3", "CN", N_("Common Name"), TRUE },
+	{ 0, "2.5.4.4", "surName", N_("Surname"), TRUE },
+	{ 0, "2.5.4.5", "serialNumber", N_("Serial Number"), FALSE },
+	{ 0, "2.5.4.6", "C", N_("Country"), FALSE, },
+	{ 0, "2.5.4.7", "L", N_("Locality"), TRUE },
+	{ 0, "2.5.4.8", "ST", N_("State"), TRUE },
+	{ 0, "2.5.4.9", "STREET", N_("Street"), TRUE },
+	{ 0, "2.5.4.10", "O", N_("Organization"), TRUE },
+	{ 0, "2.5.4.11", "OU", N_("Organizational Unit"), TRUE },
+	{ 0, "2.5.4.12", "T", N_("Title"), TRUE },
+	{ 0, "2.5.4.20", "telephoneNumber", N_("Telephone Number"), FALSE },
+	{ 0, "2.5.4.42", "givenName", N_("Given Name"), TRUE },
+	{ 0, "2.5.4.43", "initials", N_("Initials"), TRUE },
+	{ 0, "2.5.4.44", "generationQualifier", N_("Generation Qualifier"), TRUE },
+	{ 0, "2.5.4.46", "dnQualifier", N_("DN Qualifier"), FALSE },
+	{ 0, "2.5.4.65", "pseudonym", N_("Pseudonym"), TRUE },
 
-	{ 0, NULL, NULL, FALSE }
+	{ 0, NULL, NULL, NULL, FALSE }
 };
 
 static void
@@ -794,7 +870,7 @@
 }
 
 static gchar* 
-dn_print_oid_value_parsed (PrintableOid *printable, guchar *data, gsize len)
+dn_print_oid_value_parsed (PrintableOid *printable, const guchar *data, gsize len)
 {
 	const gchar *asn_name;
 	ASN1_TYPE asn1;
@@ -857,7 +933,7 @@
 }
 
 static gchar*
-dn_print_oid_value (PrintableOid *printable, guchar *data, gsize len)
+dn_print_oid_value (PrintableOid *printable, const guchar *data, gsize len)
 {
 	gchar *value;
 	
@@ -903,7 +979,7 @@
 	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), 
+	result = g_strconcat (printable && printable->attr ? printable->attr : g_quark_to_string (oid), 
 			      "=", display, NULL);
 	g_free (display);
 	
@@ -992,8 +1068,8 @@
 			/* 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)
+				if (!printable || !printable->attr || 
+				    !g_ascii_strcasecmp (printable->attr, match) == 0)
 					continue;
 			}
 
@@ -1010,3 +1086,98 @@
 	
 	return NULL;
 }
+
+gboolean
+egg_asn1_dn_parse (ASN1_TYPE asn, const gchar *part, 
+                   EggAsn1DnCallback callback, gpointer user_data)
+{
+	gboolean done = FALSE;
+	gchar *path;
+	guchar *value;
+	gsize n_value;
+	GQuark oid;
+	guint i, j;
+	
+	g_return_val_if_fail (asn, FALSE);
+	
+	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) {
+			
+			/* Dig out the type */
+			path = g_strdup_printf ("%s%s?%u.?%u.type", 
+			                        part ? part : "", 
+			                        part ? "." : "", i, j);
+			oid = egg_asn1_read_oid (asn, path);
+			g_free (path);
+
+			if (!oid) {
+				done = j == 1;
+				break;
+			}
+
+			/* Print the value as nicely as we can */
+			path = g_strdup_printf ("%s%s?%u.?%u.value", 
+			                        part ? part : "", 
+			                        part ? "." : "", i, j);
+			value = egg_asn1_read_value (asn, path, &n_value, NULL);
+			g_free (path);
+
+			if (!value) {
+				done = j == 1;
+				break;
+			}
+			
+			if (callback) 
+				(callback) (i, oid, value, n_value, user_data);
+			
+			g_free (value);
+		}
+	}
+	
+	return i > 1;
+}
+
+const gchar*
+egg_asn1_dn_oid_attr (GQuark oid)
+{
+	PrintableOid *printable;
+	
+	g_return_val_if_fail (oid, NULL);
+	
+	printable = dn_find_printable (oid);
+	if (!printable)
+		return g_quark_to_string (oid);
+	
+	return printable->attr;	
+}
+
+const gchar*
+egg_asn1_dn_oid_desc (GQuark oid)
+{
+	PrintableOid *printable;
+	
+	g_return_val_if_fail (oid, NULL);
+	
+	printable = dn_find_printable (oid);
+	if (!printable)
+		return g_quark_to_string (oid);
+	
+	return gettext (printable->description);
+}
+
+gchar*
+egg_asn1_dn_print_value (GQuark oid, const guchar *value, gsize n_value)
+{
+	PrintableOid *printable;
+	
+	g_return_val_if_fail (oid, NULL);
+	g_return_val_if_fail (value || !n_value, NULL);
+	
+	printable = dn_find_printable (oid);
+	return dn_print_oid_value (printable, value, n_value);
+}

Modified: trunk/egg/egg-asn1.h
==============================================================================
--- trunk/egg/egg-asn1.h	(original)
+++ trunk/egg/egg-asn1.h	Wed Jan 28 01:38:38 2009
@@ -28,7 +28,7 @@
 
 #include <libtasn1.h>
 
-typedef void* (*EggAllocator) (void* p, unsigned long len);
+typedef void* (*EggAllocator) (void* p, gsize);
 
 ASN1_TYPE          egg_asn1_get_pk_asn1type               (void);
 
@@ -56,6 +56,8 @@
 
 gboolean           egg_asn1_read_time                     (ASN1_TYPE asn, const gchar *part, time_t *val);
 
+gboolean           egg_asn1_read_date                     (ASN1_TYPE asn, const gchar *part, GDate *date);
+
 const guchar*      egg_asn1_read_content                  (ASN1_TYPE asn, const guchar *data, gsize n_data, 
                                                            const gchar *part, gsize *n_content);
 
@@ -64,16 +66,30 @@
                                                                  
 gboolean           egg_asn1_write_uint                    (ASN1_TYPE asn, const gchar *part, guint val);
 
+gint               egg_asn1_element_length                (const guchar *data, gsize n_data);
+
+const guchar*      egg_asn1_element_content               (const guchar *data, gsize n_data, gsize *n_content);
+
 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_time_parse_utc                (const gchar* value);
+
+glong              egg_asn1_time_parse_general            (const gchar* value);
+
+
+typedef void       (*EggAsn1DnCallback)                   (guint index, GQuark oid, const guchar *value,
+                                                           gsize n_value, gpointer user_data);
+
+gboolean           egg_asn1_dn_parse                      (ASN1_TYPE asn, const gchar *part, 
+                                                           EggAsn1DnCallback callback, gpointer user_data);
+
+const gchar*       egg_asn1_dn_oid_attr                   (GQuark oid);
 
-glong              egg_asn1_parse_utc_time                (const gchar* value);
+const gchar*       egg_asn1_dn_oid_desc                   (GQuark oid);
 
-glong              egg_asn1_parse_general_time            (const gchar* value);
+gchar*             egg_asn1_dn_print_value                (GQuark oid, const guchar *value, gsize n_value);
 
 #endif /*EGG_ASN1_H_*/

Modified: trunk/egg/egg-hex.c
==============================================================================
--- trunk/egg/egg-hex.c	(original)
+++ trunk/egg/egg-hex.c	Wed Jan 28 01:38:38 2009
@@ -81,24 +81,37 @@
 gchar* 
 egg_hex_encode (const guchar *data, gsize n_data)
 {
-	gchar *result, *encoded;
+	return egg_hex_encode_full (data, n_data, 0);
+}
+
+gchar*
+egg_hex_encode_full (const guchar *data, gsize n_data, guint group)
+{
+	GString *result;
+	gsize bytes;
 	guchar j;
 	
 	g_return_val_if_fail (data || !n_data, NULL);
+
+	result = g_string_sized_new (n_data * 2 + 1);
+	bytes = 0;
 	
-	encoded = result = g_malloc0 (n_data * 2 + 1);
-	
-	while(n_data > 0) {
+	while (n_data > 0) {
+		
+		if (group && bytes && (bytes % group) == 0)
+			g_string_append_c (result, ' ');
+
 		j = *(data) >> 4 & 0xf;
-		*(encoded++) = HEXC[j];
-    
+		g_string_append_c (result, HEXC[j]);
+		
 		j = *(data++) & 0xf;
-		*(encoded++) = HEXC[j];
+		g_string_append_c (result, HEXC[j]);
     
-		n_data--;
+		++bytes;
+		--n_data;
 	}
 
 	/* Make sure still null terminated */
-	g_assert (encoded[n_data * 2] == 0);
-	return result;
+	return g_string_free (result, FALSE);
 }
+

Modified: trunk/egg/egg-hex.h
==============================================================================
--- trunk/egg/egg-hex.h	(original)
+++ trunk/egg/egg-hex.h	Wed Jan 28 01:38:38 2009
@@ -25,10 +25,14 @@
 #include <glib.h>
 
 guchar*               egg_hex_decode                         (const gchar *data, 
-                                                                   gssize n_data, 
-                                                                   gsize *n_decoded);
+                                                              gssize n_data, 
+                                                              gsize *n_decoded);
 
 gchar*                egg_hex_encode                         (const guchar *data, 
-                                                                   gsize n_data);
+                                                              gsize n_data);
+
+gchar*                egg_hex_encode_full                    (const guchar *data, 
+                                                              gsize n_data,
+                                                              guint group);
 
 #endif /* EGG_HEX_H_ */

Modified: trunk/egg/pkix.asn
==============================================================================
--- trunk/egg/pkix.asn	(original)
+++ trunk/egg/pkix.asn	Wed Jan 28 01:38:38 2009
@@ -1195,15 +1195,14 @@
 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 }
+id-at-domainComponent AttributeType ::= { 0 9 2342 19200300 100 1 25 }
 
-ldap-DC ::= IA5String
+domainComponent ::= IA5String
 
-id-at-ldap-UID AttributeType ::= { 0 9 2342 19200300 100 1 1 }
+id-at-userId AttributeType ::= { 0 9 2342 19200300 100 1 1 }
 
-ldap-UID ::= DirectoryString
+userId ::= DirectoryString
 
 -- rfc3039
 

Modified: trunk/egg/tests/unit-test-asn1.c
==============================================================================
--- trunk/egg/tests/unit-test-asn1.c	(original)
+++ trunk/egg/tests/unit-test-asn1.c	Wed Jan 28 01:38:38 2009
@@ -331,7 +331,7 @@
 	const TimeTestData *data;
 	
 	for (data = generalized_time_test_data; data->value; ++data) {
-		when = egg_asn1_parse_general_time (data->value);
+		when = egg_asn1_time_parse_general (data->value);
 		if (data->ref != when) {
 			printf ("%s", data->value);
 			printf ("%s != ", ctime (&when));
@@ -349,7 +349,7 @@
 	const TimeTestData *data;
 	
 	for (data = utc_time_test_data; data->value; ++data) {
-		when = egg_asn1_parse_utc_time (data->value);
+		when = egg_asn1_time_parse_utc (data->value);
 		if (data->ref != when) {
 			printf ("%s", data->value);
 			printf ("%s != ", ctime (&when));
@@ -370,6 +370,16 @@
 	g_assert_cmpint (time, ==, 820454400);
 }
 
+DEFINE_TEST(read_date)
+{
+	GDate date;
+	if (!egg_asn1_read_date (asn1_cert, "tbsCertificate.validity.notAfter", &date))
+		g_assert_not_reached ();
+	g_assert_cmpint (date.day, ==, 31);
+	g_assert_cmpint (date.month, ==, 12);
+	g_assert_cmpint (date.year, ==, 2020);
+}
+
 DEFINE_TEST(read_dn)
 {
 	gchar *dn;
@@ -384,6 +394,79 @@
 	g_assert (dn == NULL);
 }
 
+DEFINE_TEST(dn_oid)
+{
+	GQuark oid;
+	
+	oid = g_quark_from_static_string ("0.9.2342.19200300.100.1.25");
+	g_assert_cmpstr (egg_asn1_dn_oid_attr (oid), ==, "DC");
+	g_assert_cmpstr (egg_asn1_dn_oid_desc (oid), ==, "Domain Component");
+	
+	/* Should return OID for invalid oids */
+	oid = g_quark_from_static_string ("1.1.1.1.1");
+	g_assert_cmpstr (egg_asn1_dn_oid_attr (oid), ==, "1.1.1.1.1");
+	g_assert_cmpstr (egg_asn1_dn_oid_desc (oid), ==, "1.1.1.1.1");	
+}
+
+DEFINE_TEST(dn_value)
+{
+	const guchar value[] = { 0x13, 0x1a, 0x54, 0x68, 0x61, 0x77, 0x74, 0x65, 0x20, 0x50, 0x65, 0x72, 0x73, 0x6f, 0x6e, 0x61, 0x6c, 0x20, 0x50, 0x72, 0x65, 0x6d, 0x69, 0x75, 0x6d, 0x20, 0x43, 0x41 };
+	gsize n_value = 28;
+	GQuark oid;
+	gchar *text;
+	
+	/* Some printable strings */
+	oid = g_quark_from_static_string ("2.5.4.3");
+	text = egg_asn1_dn_print_value (oid, value, n_value);
+	g_assert_cmpstr (text, ==, "Thawte Personal Premium CA");
+	g_free (text);
+
+	/* Unknown oid */
+	oid = g_quark_from_static_string ("1.1.1.1.1.1");
+	text = egg_asn1_dn_print_value (oid, value, n_value);
+	g_assert_cmpstr (text, ==, "#131A54686177746520506572736F6E616C205072656D69756D204341");
+	g_free (text);
+}
+
+static int last_index = 0;
+
+static void
+concatenate_dn (guint index, GQuark oid, const guchar *value, gsize n_value, gpointer user_data)
+{
+	GString *dn = user_data;
+	gchar *text;
+	
+	g_assert (oid);
+	g_assert (value);
+	g_assert (n_value);
+	
+	g_assert (index == last_index);
+	++last_index;
+	
+	if (index != 1) {
+		g_string_append (dn, ", ");
+	}
+	
+	g_string_append (dn, egg_asn1_dn_oid_attr (oid));
+	g_string_append_c (dn, '=');
+	
+	text = egg_asn1_dn_print_value (oid, value, n_value);
+	g_string_append (dn, text);
+	g_free (text);
+}
+
+DEFINE_TEST(parse_dn)
+{
+	GString *dn = g_string_new ("");
+	last_index = 1;
+	
+	if (!egg_asn1_dn_parse (asn1_cert, "tbsCertificate.issuer.rdnSequence", concatenate_dn, dn))
+		g_assert_not_reached ();
+	
+	g_assert_cmpstr (dn->str, ==, "C=ZA, ST=Western Cape, L=Cape Town, O=Thawte Consulting, OU=Certification Services Division, CN=Thawte Personal Premium CA, EMAIL=personal-premium thawte com");
+	g_string_free (dn, TRUE);
+}
+
 DEFINE_TEST(read_dn_part)
 {
 	gchar *value;

Modified: trunk/egg/tests/unit-test-hex.c
==============================================================================
--- trunk/egg/tests/unit-test-hex.c	(original)
+++ trunk/egg/tests/unit-test-hex.c	Wed Jan 28 01:38:38 2009
@@ -31,6 +31,7 @@
 
 static const guchar TEST_DATA[] = { 0x05, 0xD6, 0x95, 0x96, 0x10, 0x12, 0xAE, 0x35 };
 static const gchar *TEST_HEX = "05D695961012AE35";
+static const gchar *TEST_HEX_DELIM = "05 D6 95 96 10 12 AE 35";
 static const gchar *TEST_HEX_SPACE = "\n05 D695 \r961012AE35\n\n";
 
 DEFINE_TEST(hex_encode)
@@ -42,6 +43,21 @@
 	g_assert_cmpstr (hex, ==, TEST_HEX);
 }
 
+DEFINE_TEST(hex_encode_spaces)
+{
+	gchar *hex;
+	
+	/* Encode without spaces */
+	hex = egg_hex_encode_full (TEST_DATA, sizeof (TEST_DATA), 0);
+	g_assert (hex);
+	g_assert_cmpstr (hex, ==, TEST_HEX);
+	
+	/* Encode without spaces */
+	hex = egg_hex_encode_full (TEST_DATA, sizeof (TEST_DATA), 1);
+	g_assert (hex);
+	g_assert_cmpstr (hex, ==, TEST_HEX_DELIM);
+}
+
 DEFINE_TEST(hex_decode)
 {
 	guchar *data;

Modified: trunk/gcr/Makefile.am
==============================================================================
--- trunk/gcr/Makefile.am	(original)
+++ trunk/gcr/Makefile.am	Wed Jan 28 01:38:38 2009
@@ -5,6 +5,7 @@
 uidir = $(datadir)/gcr/ui/
 
 GLADE_FILES = \
+	gcr-certificate-basics-widget.glade \
 	gcr-import-dialog.glade
 	
 .glade.ui: 
@@ -20,7 +21,9 @@
     	-I$(top_srcdir) \
     	$(GTK_CFLAGS) \
     	$(GOBJECT_CFLAGS) \
-	$(GLIB_CFLAGS)
+	$(GLIB_CFLAGS) \
+	$(LIBGCRYPT_CFLAGS) \
+	$(LIBTASN1_CFLAGS)
 
 BUILT_SOURCES = \
 	gcr-marshal.c gcr-marshal.h
@@ -28,6 +31,9 @@
 lib_LTLIBRARIES = libgcr.la
 
 libgcr_la_SOURCES = \
+	gcr-certificate.c gcr-certificate.h \
+	gcr-certificate-basics-widget.c gcr-certificate-basics-widget.h \
+	gcr-certificate-details-widget.c gcr-certificate-details-widget.h \
 	gcr-import-dialog.c gcr-import-dialog.h \
 	gcr-importer.c gcr-importer.h  \
 	gcr-internal.h \
@@ -50,7 +56,9 @@
 	$(top_builddir)/egg/libegg-secure-entry.la \
 	$(top_builddir)/gp11/libgp11.la \
 	$(GOBJECT_LIBS) \
-	$(GLIB_LIBS)
+	$(GLIB_LIBS) \
+	$(LIBGCRYPT_LIBS) \
+	$(LIBTASN1_LIBS)
 
 gcr-marshal.h: gcr-marshal.list $(GLIB_GENMARSHAL)
 	$(GLIB_GENMARSHAL) $< --header --prefix=_gcr_marshal > $@
@@ -70,7 +78,6 @@
 EXTRA_DIST = \
 	gcr.pc.in \
 	gcr-marshal.list \
-	gcr-import-dialog.glade \
 	$(GLADE_FILES)
     
 CLEANFILES = \

Added: trunk/gcr/gcr-certificate-basics-widget.c
==============================================================================
--- (empty file)
+++ trunk/gcr/gcr-certificate-basics-widget.c	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,306 @@
+/* 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gcr-certificate.h"
+#include "gcr-certificate-basics-widget.h"
+
+#include <glib/gi18n-lib.h>
+
+enum {
+	PROP_0,
+	PROP_CERTIFICATE
+};
+
+struct _GcrCertificateBasicsWidgetPrivate {
+	GcrCertificate *certificate;
+	GtkBuilder *builder;
+};
+
+G_DEFINE_TYPE (GcrCertificateBasicsWidget, gcr_certificate_basics_widget, GTK_TYPE_ALIGNMENT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static void
+set_certificate_part_label (GtkBuilder *builder, const char *name, const gchar *value)
+{
+	GtkWidget *widget;
+	gchar *markup;
+	
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, name));
+	g_return_if_fail (GTK_IS_LABEL (widget));
+	if(value)
+	{
+		markup = g_markup_escape_text (value, -1);
+		gtk_label_set_markup (GTK_LABEL (widget), markup);
+		g_free (markup);
+	}
+	else
+	{
+		gtk_label_set_markup (GTK_LABEL (widget), _("<i>Not Part of Certificate</i>"));
+	}
+}
+
+static void
+set_certificate_part_date (GtkBuilder *builder, const char *name, const GDate *value)
+{
+	GtkWidget *widget;
+	gchar *formatted;
+	
+	widget = GTK_WIDGET (gtk_builder_get_object (builder, name));
+	g_return_if_fail (GTK_IS_LABEL (widget));
+	if(value)
+	{
+		formatted = g_new (gchar, 11);
+		g_date_strftime (formatted, 11, "%Y-%m-%d", value);
+		gtk_label_set_text (GTK_LABEL (widget), formatted);
+		g_free (formatted);
+	}
+	else
+	{
+		gtk_label_set_markup (GTK_LABEL (widget), _("<i>unknown</i>"));
+	}
+}
+
+static void
+refresh_display (GcrCertificateBasicsWidget *self)
+{
+	gchar *value;
+	GDate *date;
+	
+	/* Issued To / Subject */
+	
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_subject_cn (self->pv->certificate);
+	set_certificate_part_label (self->pv->builder, "issued-to-cn", value);
+	g_free (value);
+	
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_subject_part (self->pv->certificate, "o");
+	set_certificate_part_label (self->pv->builder, "issued-to-o", value);
+	g_free (value);
+
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_subject_part (self->pv->certificate, "ou");
+	set_certificate_part_label (self->pv->builder, "issued-to-ou", value);
+	g_free (value);
+
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_serial_number_hex (self->pv->certificate);
+	set_certificate_part_label (self->pv->builder, "issued-to-serial", value);
+	g_free (value);
+	
+	
+	/* Issued By / Issuer */
+	
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_issuer_cn (self->pv->certificate);
+	set_certificate_part_label (self->pv->builder, "issued-by-cn", value);
+	g_free (value);
+	
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_issuer_part (self->pv->certificate, "o");
+	set_certificate_part_label (self->pv->builder, "issued-by-o", value);
+	g_free (value);
+
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_issuer_part (self->pv->certificate, "ou");
+	set_certificate_part_label (self->pv->builder, "issued-by-ou", value);
+	g_free (value);
+
+	
+	/* Expiry */
+	
+	date = NULL;
+	if (self->pv->certificate)
+		date = gcr_certificate_get_issued_date (self->pv->certificate);
+	set_certificate_part_date (self->pv->builder, "validity-issued-on", date);
+	if (date)
+		g_date_free (date);
+	
+	date = NULL;
+	if (self->pv->certificate)
+		date = gcr_certificate_get_expiry_date (self->pv->certificate);
+	set_certificate_part_date (self->pv->builder, "validity-expires-on", date);
+	if (date)
+		g_date_free (date);
+
+	
+	/* Fingerprints */
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_fingerprint_hex (self->pv->certificate, G_CHECKSUM_SHA1);
+	set_certificate_part_label (self->pv->builder, "fingerprints-sha1", value);
+	g_free (value);
+	
+	value = NULL;
+	if (self->pv->certificate)
+		value = gcr_certificate_get_fingerprint_hex (self->pv->certificate, G_CHECKSUM_SHA1);
+	set_certificate_part_label (self->pv->builder, "fingerprints-md5", value);
+	g_free (value);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+
+static GObject* 
+gcr_certificate_basics_widget_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+{
+	GObject *obj = G_OBJECT_CLASS (gcr_certificate_basics_widget_parent_class)->constructor (type, n_props, props);
+	GcrCertificateBasicsWidget *self = NULL;
+	GtkWidget *widget;
+	
+	if (obj) {
+		self = GCR_CERTIFICATE_BASICS_WIDGET (obj);
+		
+		if (!gtk_builder_add_from_file (self->pv->builder, UIDIR "gcr-certificate-basics-widget.ui", NULL))
+			g_return_val_if_reached (obj);
+	
+		widget = GTK_WIDGET (gtk_builder_get_object (self->pv->builder, "certificate-basics-widget"));
+		g_return_val_if_fail (GTK_IS_WIDGET (widget), obj);
+		gtk_container_add (GTK_CONTAINER (self), widget);
+		gtk_widget_show (widget);
+	}
+	
+	return obj;
+}
+
+static void
+gcr_certificate_basics_widget_init (GcrCertificateBasicsWidget *self)
+{
+	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_BASICS_WIDGET, GcrCertificateBasicsWidgetPrivate));
+	self->pv->builder = gtk_builder_new ();
+}
+
+static void
+gcr_certificate_basics_widget_dispose (GObject *obj)
+{
+	GcrCertificateBasicsWidget *self = GCR_CERTIFICATE_BASICS_WIDGET (obj);
+	
+	if (self->pv->certificate)
+		g_object_unref (self->pv->certificate);
+	self->pv->certificate = NULL;
+	
+	G_OBJECT_CLASS (gcr_certificate_basics_widget_parent_class)->dispose (obj);
+}
+
+static void
+gcr_certificate_basics_widget_finalize (GObject *obj)
+{
+	GcrCertificateBasicsWidget *self = GCR_CERTIFICATE_BASICS_WIDGET (obj);
+
+	g_assert (!self->pv->certificate);
+	
+	G_OBJECT_CLASS (gcr_certificate_basics_widget_parent_class)->finalize (obj);
+}
+
+static void
+gcr_certificate_basics_widget_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                                    GParamSpec *pspec)
+{
+	GcrCertificateBasicsWidget *self = GCR_CERTIFICATE_BASICS_WIDGET (obj);
+	
+	switch (prop_id) {
+	case PROP_CERTIFICATE:
+		gcr_certificate_basics_widget_set_certificate (self, g_value_get_object (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_basics_widget_get_property (GObject *obj, guint prop_id, GValue *value, 
+                                    GParamSpec *pspec)
+{
+	GcrCertificateBasicsWidget *self = GCR_CERTIFICATE_BASICS_WIDGET (obj);
+	
+	switch (prop_id) {
+	case PROP_CERTIFICATE:
+		g_value_set_object (value, self->pv->certificate);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_basics_widget_class_init (GcrCertificateBasicsWidgetClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+    
+	gcr_certificate_basics_widget_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GcrCertificateBasicsWidgetPrivate));
+
+	gobject_class->constructor = gcr_certificate_basics_widget_constructor;
+	gobject_class->dispose = gcr_certificate_basics_widget_dispose;
+	gobject_class->finalize = gcr_certificate_basics_widget_finalize;
+	gobject_class->set_property = gcr_certificate_basics_widget_set_property;
+	gobject_class->get_property = gcr_certificate_basics_widget_get_property;
+    
+	g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
+	           g_param_spec_object("certificate", "Certificate", "Certificate to display.", 
+	                               GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GcrCertificateBasicsWidget*
+gcr_certificate_basics_widget_new (GcrCertificate *certificate)
+{
+	return g_object_new (GCR_TYPE_CERTIFICATE_BASICS_WIDGET, "certificate", certificate, NULL);
+}
+
+GcrCertificate*
+gcr_certificate_basics_widget_get_certificate (GcrCertificateBasicsWidget *self)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_BASICS_WIDGET (self), NULL);
+	return self->pv->certificate;
+}
+
+void
+gcr_certificate_basics_widget_set_certificate (GcrCertificateBasicsWidget *self, GcrCertificate *cert)
+{
+	g_return_if_fail (GCR_IS_CERTIFICATE_BASICS_WIDGET (self));
+	
+	if (self->pv->certificate)
+		g_object_unref (self->pv->certificate);
+	self->pv->certificate = cert;
+	if (self->pv->certificate)
+		g_object_ref (self->pv->certificate);	
+	
+	refresh_display (self);
+	g_object_notify (G_OBJECT (self), "certificate");
+}

Added: trunk/gcr/gcr-certificate-basics-widget.glade
==============================================================================
--- (empty file)
+++ trunk/gcr/gcr-certificate-basics-widget.glade	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,512 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
+<!--*- mode: xml -*-->
+<glade-interface>
+  <widget class="GtkWindow" id="unused-window">
+    <child>
+      <widget class="GtkVBox" id="certificate-basics-widget">
+        <property name="visible">True</property>
+        <property name="border_width">6</property>
+        <property name="spacing">6</property>
+        <child>
+          <widget class="GtkFrame" id="frame1">
+            <property name="label_xalign">0</property>
+            <property name="shadow_type">GTK_SHADOW_NONE</property>
+            <child>
+              <widget class="GtkVBox" id="vbox2">
+                <property name="visible">True</property>
+                <property name="border_width">6</property>
+                <child>
+                  <widget class="GtkLabel" id="ssl-client-cert-verified-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">SSL Client Certificate</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="ssl-server-cert-verified-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">SSL Server Certificate</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="email-signer-cert-verified-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Email Signer Certificate</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <widget class="GtkLabel" id="email-recipient-cert-verified-label">
+                    <property name="visible">True</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Email Recipient Certificate</property>
+                  </widget>
+                  <packing>
+                    <property name="expand">False</property>
+                    <property name="fill">False</property>
+                    <property name="position">3</property>
+                  </packing>
+                </child>
+              </widget>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label3">
+                <property name="visible">True</property>
+                <property name="label" translatable="yes">&lt;b&gt;This certificate has been verified for the following uses:&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="type">label_item</property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkHSeparator" id="hseparator1">
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <widget class="GtkTable" id="table3">
+            <property name="visible">True</property>
+            <property name="border_width">3</property>
+            <property name="n_rows">15</property>
+            <property name="n_columns">2</property>
+            <property name="column_spacing">6</property>
+            <child>
+              <widget class="GtkLabel" id="label25">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">1</property>
+                <property name="ypad">3</property>
+                <property name="label" translatable="yes">&lt;b&gt;Issued To&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label26">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Common Name (CN)</property>
+              </widget>
+              <packing>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label27">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Organization (O)</property>
+              </widget>
+              <packing>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label28">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Organizational Unit (OU)</property>
+              </widget>
+              <packing>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label29">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Serial Number</property>
+              </widget>
+              <packing>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label31">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Common Name (CN)</property>
+              </widget>
+              <packing>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label32">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Organization (O)</property>
+              </widget>
+              <packing>
+                <property name="top_attach">7</property>
+                <property name="bottom_attach">8</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label33">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Organizational Unit (OU)</property>
+              </widget>
+              <packing>
+                <property name="top_attach">8</property>
+                <property name="bottom_attach">9</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label36">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Issued On</property>
+              </widget>
+              <packing>
+                <property name="top_attach">10</property>
+                <property name="bottom_attach">11</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label37">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">Expires On</property>
+              </widget>
+              <packing>
+                <property name="top_attach">11</property>
+                <property name="bottom_attach">12</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label30">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="yalign">1</property>
+                <property name="ypad">3</property>
+                <property name="label" translatable="yes">&lt;b&gt;Issued By&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">5</property>
+                <property name="bottom_attach">6</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label35">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="ypad">3</property>
+                <property name="label" translatable="yes">&lt;b&gt;Fingerprints&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">12</property>
+                <property name="bottom_attach">13</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label38">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">SHA1 Fingerprint</property>
+              </widget>
+              <packing>
+                <property name="top_attach">13</property>
+                <property name="bottom_attach">14</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label39">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="xpad">6</property>
+                <property name="label" translatable="yes">MD5 Fingerprint</property>
+              </widget>
+              <packing>
+                <property name="top_attach">14</property>
+                <property name="bottom_attach">15</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="issued-to-o">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">2</property>
+                <property name="bottom_attach">3</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="issued-to-ou">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">3</property>
+                <property name="bottom_attach">4</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="issued-to-serial">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">4</property>
+                <property name="bottom_attach">5</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="issued-by-cn">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">6</property>
+                <property name="bottom_attach">7</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="issued-by-o">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">7</property>
+                <property name="bottom_attach">8</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="issued-by-ou">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">8</property>
+                <property name="bottom_attach">9</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="validity-issued-on">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">10</property>
+                <property name="bottom_attach">11</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="validity-expires-on">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">11</property>
+                <property name="bottom_attach">12</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="fingerprints-sha1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">13</property>
+                <property name="bottom_attach">14</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="fingerprints-md5">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">14</property>
+                <property name="bottom_attach">15</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="issued-to-cn">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">&lt;Not Part of Certificate&gt;</property>
+                <property name="selectable">True</property>
+              </widget>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="right_attach">2</property>
+                <property name="top_attach">1</property>
+                <property name="bottom_attach">2</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+            <child>
+              <widget class="GtkLabel" id="label34">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="ypad">3</property>
+                <property name="label" translatable="yes">&lt;b&gt;Validity&lt;/b&gt;</property>
+                <property name="use_markup">True</property>
+              </widget>
+              <packing>
+                <property name="right_attach">2</property>
+                <property name="top_attach">9</property>
+                <property name="bottom_attach">10</property>
+                <property name="x_options">GTK_FILL</property>
+                <property name="y_options"></property>
+              </packing>
+            </child>
+          </widget>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+      </widget>
+    </child>
+  </widget>
+</glade-interface>

Added: trunk/gcr/gcr-certificate-basics-widget.h
==============================================================================
--- (empty file)
+++ trunk/gcr/gcr-certificate-basics-widget.h	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,57 @@
+/* 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCR_CERTIFICATE_BASICS_WIDGET_H__
+#define __GCR_CERTIFICATE_BASICS_WIDGET_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-certificate.h"
+
+#define GCR_TYPE_CERTIFICATE_BASICS_WIDGET               (gcr_certificate_basics_widget_get_type ())
+#define GCR_CERTIFICATE_BASICS_WIDGET(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_BASICS_WIDGET, GcrCertificateBasicsWidget))
+#define GCR_CERTIFICATE_BASICS_WIDGET_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_BASICS_WIDGET, GcrCertificateBasicsWidgetClass))
+#define GCR_IS_CERTIFICATE_BASICS_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_BASICS_WIDGET))
+#define GCR_IS_CERTIFICATE_BASICS_WIDGET_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_BASICS_WIDGET))
+#define GCR_CERTIFICATE_BASICS_WIDGET_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_BASICS_WIDGET, GcrCertificateBasicsWidgetClass))
+
+typedef struct _GcrCertificateBasicsWidget GcrCertificateBasicsWidget;
+typedef struct _GcrCertificateBasicsWidgetClass GcrCertificateBasicsWidgetClass;
+typedef struct _GcrCertificateBasicsWidgetPrivate GcrCertificateBasicsWidgetPrivate;
+    
+struct _GcrCertificateBasicsWidget {
+	GtkAlignment parent;
+	GcrCertificateBasicsWidgetPrivate *pv;
+};
+
+struct _GcrCertificateBasicsWidgetClass {
+	GtkAlignmentClass parent_class;
+};
+
+GType                        gcr_certificate_basics_widget_get_type               (void);
+
+GcrCertificateBasicsWidget*  gcr_certificate_basics_widget_new                    (GcrCertificate *cert);
+
+GcrCertificate*              gcr_certificate_basics_widget_get_certificate        (GcrCertificateBasicsWidget *basics);
+
+void                         gcr_certificate_basics_widget_set_certificate        (GcrCertificateBasicsWidget *basics, 
+                                                                                   GcrCertificate *cert);
+
+#endif /* __GCR_CERTIFICATE_BASICS_WIDGET_H__ */

Added: trunk/gcr/gcr-certificate-details-widget.c
==============================================================================
--- (empty file)
+++ trunk/gcr/gcr-certificate-details-widget.c	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,462 @@
+/* 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gcr-certificate.h"
+#include "gcr-certificate-details-widget.h"
+
+#include "egg/egg-asn1.h"
+#include "egg/egg-hex.h"
+
+#include <glib/gi18n-lib.h>
+
+enum {
+	PROP_0,
+	PROP_CERTIFICATE
+};
+
+struct _GcrCertificateDetailsWidgetPrivate {
+	GcrCertificate *certificate;
+	GtkTextView *view;
+	GtkTextBuffer *buffer;
+	GtkTextTag *field_tag;
+	gint field_width;
+};
+
+G_DEFINE_TYPE (GcrCertificateDetailsWidget, gcr_certificate_details_widget, GTK_TYPE_ALIGNMENT);
+
+#define FIELD_MARGIN 17
+#define COLUMN_MARGIN 6
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static GtkTextTagTable*
+create_tag_table (GcrCertificateDetailsWidget *self)
+{
+	GtkTextTagTable *tags;
+	GtkTextTag *tag;
+
+	g_assert (GCR_IS_CERTIFICATE_DETAILS_WIDGET (self));
+	
+	tags = gtk_text_tag_table_new ();
+	
+	tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                    "name", "heading",
+	                    "left-margin", 5, 
+	                    "right-margin", 5,
+	                    "pixels-above-lines", 9,
+	                    "pixels-below-lines", 3,
+	                    "weight", PANGO_WEIGHT_BOLD,
+	                    NULL);
+	
+	gtk_text_tag_table_add (tags, tag);
+	g_object_unref (tag);
+	
+	tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                    "name", "monospace",
+	                    "family", "monospace",
+	                    NULL);
+	
+	gtk_text_tag_table_add (tags, tag);
+	g_object_unref (tag);	
+
+	g_assert (!self->pv->field_tag);
+	self->pv->field_width = 0;
+	self->pv->field_tag = g_object_new (GTK_TYPE_TEXT_TAG,
+	                                    "name", "field",
+	                                    "left-margin", self->pv->field_width + FIELD_MARGIN,
+	                                    "indent", self->pv->field_width,
+	                                    "right-margin", 5,
+	                                    "pixels-below-lines", 3,
+	                                    "wrap-mode", GTK_WRAP_WORD_CHAR,
+	                                    NULL);
+	gtk_text_tag_table_add (tags, self->pv->field_tag);
+	
+	return tags;
+}
+
+static void
+append_field_and_value (GcrCertificateDetailsWidget *self, const gchar *field, 
+                        const gchar *value, gboolean monospace)
+{
+	PangoRectangle extents;
+	PangoTabArray *tabs;
+	PangoLayout *layout;
+	GtkTextIter iter;
+	gchar *text;
+	
+	text = g_strdup_printf ("%s:", field);
+	
+	/* Measure the width of the field */
+	layout = gtk_widget_create_pango_layout (GTK_WIDGET (self), text);
+	pango_layout_get_extents (layout, NULL, &extents);
+	pango_extents_to_pixels (&extents, NULL);
+	g_object_unref (layout);
+	
+	/* Make the tab wide enough to accomodate */
+	if (extents.width > self->pv->field_width) {
+		self->pv->field_width = extents.width + COLUMN_MARGIN;
+		tabs = pango_tab_array_new (1, TRUE);
+		pango_tab_array_set_tab (tabs, 0, PANGO_TAB_LEFT, self->pv->field_width);
+		g_object_set (self->pv->field_tag, 
+		              "left-margin", FIELD_MARGIN,
+		              "indent", 0 - self->pv->field_width,
+		              "tabs", tabs,
+		              NULL);
+		pango_tab_array_free (tabs);
+	}
+	
+	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, text, -1, "field", NULL);
+	gtk_text_buffer_insert (self->pv->buffer, &iter, "\t", 1);
+	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, value, -1, "field", 
+	                                          monospace ? "monospace" : NULL, NULL);
+	gtk_text_buffer_insert (self->pv->buffer, &iter, "\n", 1);
+	
+	g_free (text);
+}
+
+static void
+append_heading (GcrCertificateDetailsWidget *self, const gchar *heading)
+{
+	GtkTextIter iter;
+	
+	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+	gtk_text_buffer_insert_with_tags_by_name (self->pv->buffer, &iter, heading, -1, "heading", NULL);
+	gtk_text_buffer_insert (self->pv->buffer, &iter, "\n", 1);
+}
+
+static void
+append_fingerprint (GcrCertificateDetailsWidget *self, const guchar *data, 
+                    gsize n_data, const gchar *name, GChecksumType type)
+{
+	GChecksum *checksum;
+	guint8 *buffer;
+	gsize n_buffer;
+	gchar *display;
+	
+	checksum = g_checksum_new (type);
+	g_return_if_fail (checksum);
+	g_checksum_update (checksum, data, n_data);
+	
+	n_buffer = g_checksum_type_get_length (type);
+	g_return_if_fail (n_buffer);
+	buffer = g_malloc0 (n_buffer);
+	
+	g_checksum_get_digest (checksum, buffer, &n_buffer);
+	g_checksum_free (checksum);
+	
+	display = egg_hex_encode_full (buffer, n_buffer, 1);
+	append_field_and_value (self, name, display, TRUE);
+	g_free (display);
+	
+	g_free (buffer);		
+}
+
+static void
+on_parsed_dn_part (guint index, GQuark oid, const guchar *value,
+                   gsize n_value, gpointer user_data)
+{
+	GcrCertificateDetailsWidget *self = user_data;
+	const gchar *attr;
+	const gchar *desc;
+	gchar *field;
+	gchar *display;
+	
+	g_return_if_fail (GCR_IS_CERTIFICATE_DETAILS_WIDGET (self));
+	
+	attr = egg_asn1_dn_oid_attr (oid);
+	desc = egg_asn1_dn_oid_desc (oid);
+	
+	/* Combine them into something sane */
+	if (attr && desc) {
+		if (strcmp (attr, desc) == 0)
+			field = g_strdup (attr);
+		else 
+			field = g_strdup_printf ("%s (%s)", attr, desc);
+	} else if (!attr && !desc) {
+		field = g_strdup ("");
+	} else if (attr) {
+		field = g_strdup (attr);
+	} else if (desc) {
+		field = g_strdup (desc);
+	} else {
+		g_assert_not_reached ();
+	}
+	
+	display = egg_asn1_dn_print_value (oid, value, n_value);
+	if (display == NULL)
+		display = "";
+	
+	append_field_and_value (self, field, display, FALSE);
+	g_free (field);
+	g_free (display);
+}
+
+static void
+refresh_display (GcrCertificateDetailsWidget *self)
+{
+	GtkTextIter start, iter;
+	const guchar *data, *value;
+	gsize n_data, n_value;
+	guint version;
+	gchar *display;
+	ASN1_TYPE asn;
+	GDate date;
+	
+	gtk_text_buffer_get_start_iter (self->pv->buffer, &start);
+	gtk_text_buffer_get_end_iter (self->pv->buffer, &iter);
+	gtk_text_buffer_delete (self->pv->buffer, &start, &iter);
+	
+	if (!self->pv->certificate)
+		return;
+	
+	data = gcr_certificate_get_der_data (self->pv->certificate, &n_data);
+	g_return_if_fail (data);
+	
+	asn = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
+	g_return_if_fail (asn);
+	
+	/* The subject */
+	append_heading (self, _("Subject Name"));
+	egg_asn1_dn_parse (asn, "tbsCertificate.subject.rdnSequence", on_parsed_dn_part, self);
+	
+	/* The Issuer */
+	append_heading (self, _("Issuer Name"));
+	egg_asn1_dn_parse (asn, "tbsCertificate.issuer.rdnSequence", on_parsed_dn_part, self);
+	
+	/* The Issued Parameters */
+	append_heading (self, _("Issued Certificate"));
+	
+	if (!egg_asn1_read_uint (asn, "tbsCertificate.version", &version))
+		g_return_if_reached ();
+	display = g_strdup_printf ("%u", version + 1);
+	append_field_and_value (self, _("Version"), display, FALSE);
+	g_free (display);
+	
+	value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.serialNumber", &n_value);
+	g_return_if_fail (value);
+	display = egg_hex_encode_full (value, n_value, 1);
+	append_field_and_value (self, _("Serial Number"), display, TRUE);
+	g_free (display);
+	
+	display = g_malloc0 (128);
+	if (egg_asn1_read_date (asn, "tbsCertificate.validity.notBefore", &date)) {
+		if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
+			g_return_if_reached ();
+		append_field_and_value (self, _("Not Valid Before"), display, FALSE);
+	}
+	if (egg_asn1_read_date (asn, "tbsCertificate.validity.notAfter", &date)) {
+		if (!g_date_strftime (display, 128, "%Y-%m-%d", &date))
+			g_return_if_reached ();
+		append_field_and_value (self, _("Not Valid After"), display, FALSE);
+	}
+	g_free (display);
+	
+	/* Signature */
+	append_heading (self, _("Signature"));
+	
+	/* TODO: Complete Signature algorithm, and params */
+	append_field_and_value (self, _("Signature Algorithm"), "TODO", FALSE);
+	
+	value = egg_asn1_read_content (asn, data, n_data, "signature", &n_value);
+	g_return_if_fail (value);
+	display = egg_hex_encode_full (value, n_value, 1);
+	append_field_and_value (self, _("Signature"), display, TRUE);
+	g_free (display);
+
+	/* Public Key Info */
+	append_heading (self, _("Public Key Info"));
+	
+	/* TODO: Complete algorithm, params, key size */
+	append_field_and_value (self, _("Key Algorithm"), "TODO", FALSE);
+	append_field_and_value (self, _("Key Size"), "TODO", FALSE);
+	
+	value = egg_asn1_read_content (asn, data, n_data, "tbsCertificate.subjectPublicKeyInfo.subjectPublicKey", &n_value);
+	g_return_if_fail (value);
+	display = egg_hex_encode_full (value, n_value, 1);
+	append_field_and_value (self, _("Public Key"), display, TRUE);
+	g_free (display);
+	
+	/* TODO: Implement extensions */
+
+	/* Fingerprints */
+	append_heading (self, _("Fingerprints"));
+	
+	append_fingerprint (self, data, n_data, "SHA1", G_CHECKSUM_SHA1);
+	append_fingerprint (self, data, n_data, "MD5", G_CHECKSUM_MD5);
+	
+	asn1_delete_structure (&asn);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static GObject* 
+gcr_certificate_details_widget_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+{
+	GObject *obj = G_OBJECT_CLASS (gcr_certificate_details_widget_parent_class)->constructor (type, n_props, props);
+	GcrCertificateDetailsWidget *self = NULL;
+	GtkTextTagTable *tags;
+	GtkWidget *widget; 
+	GtkWidget *scroll;
+	
+	g_return_val_if_fail (obj, NULL);
+	
+	self = GCR_CERTIFICATE_DETAILS_WIDGET (obj);
+	
+	tags = create_tag_table (self);
+	self->pv->buffer = gtk_text_buffer_new (tags);
+	g_object_unref (tags);
+	
+	widget = gtk_text_view_new_with_buffer (self->pv->buffer);
+	self->pv->view = GTK_TEXT_VIEW (widget);
+	gtk_text_view_set_editable (self->pv->view, FALSE);
+	
+	scroll = gtk_scrolled_window_new (NULL, NULL);
+	gtk_container_add (GTK_CONTAINER (scroll), widget);
+	
+	gtk_container_add (GTK_CONTAINER (self), scroll);
+	gtk_widget_show_all (scroll);
+	
+	return obj;
+}
+
+static void
+gcr_certificate_details_widget_init (GcrCertificateDetailsWidget *self)
+{
+	self->pv = (G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE_DETAILS_WIDGET, GcrCertificateDetailsWidgetPrivate));
+}
+
+static void
+gcr_certificate_details_widget_dispose (GObject *obj)
+{
+	GcrCertificateDetailsWidget *self = GCR_CERTIFICATE_DETAILS_WIDGET (obj);
+	
+	if (self->pv->certificate)
+		g_object_unref (self->pv->certificate);
+	self->pv->certificate = NULL;
+	
+	G_OBJECT_CLASS (gcr_certificate_details_widget_parent_class)->dispose (obj);
+}
+
+static void
+gcr_certificate_details_widget_finalize (GObject *obj)
+{
+	GcrCertificateDetailsWidget *self = GCR_CERTIFICATE_DETAILS_WIDGET (obj);
+
+	g_assert (!self->pv->certificate);
+	
+	if (self->pv->buffer)
+		g_object_unref (self->pv->buffer);
+	self->pv->buffer = NULL;
+
+	if (self->pv->field_tag)
+		g_object_unref (self->pv->field_tag);
+	self->pv->field_tag = NULL;
+	
+	G_OBJECT_CLASS (gcr_certificate_details_widget_parent_class)->finalize (obj);
+}
+
+static void
+gcr_certificate_details_widget_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                                             GParamSpec *pspec)
+{
+	GcrCertificateDetailsWidget *self = GCR_CERTIFICATE_DETAILS_WIDGET (obj);
+	
+	switch (prop_id) {
+	case PROP_CERTIFICATE:
+		gcr_certificate_details_widget_set_certificate (self, g_value_get_object (value));
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_details_widget_get_property (GObject *obj, guint prop_id, GValue *value, 
+                                             GParamSpec *pspec)
+{
+	GcrCertificateDetailsWidget *self = GCR_CERTIFICATE_DETAILS_WIDGET (obj);
+	
+	switch (prop_id) {
+	case PROP_CERTIFICATE:
+		g_value_set_object (value, self->pv->certificate);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_details_widget_class_init (GcrCertificateDetailsWidgetClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+    
+	gcr_certificate_details_widget_parent_class = g_type_class_peek_parent (klass);
+	g_type_class_add_private (klass, sizeof (GcrCertificateDetailsWidgetPrivate));
+
+	gobject_class->constructor = gcr_certificate_details_widget_constructor;
+	gobject_class->dispose = gcr_certificate_details_widget_dispose;
+	gobject_class->finalize = gcr_certificate_details_widget_finalize;
+	gobject_class->set_property = gcr_certificate_details_widget_set_property;
+	gobject_class->get_property = gcr_certificate_details_widget_get_property;
+    
+	g_object_class_install_property (gobject_class, PROP_CERTIFICATE,
+	           g_param_spec_object("certificate", "Certificate", "Certificate to display.", 
+	                               GCR_TYPE_CERTIFICATE, G_PARAM_READWRITE));
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GcrCertificateDetailsWidget*
+gcr_certificate_details_widget_new (GcrCertificate *certificate)
+{
+	return g_object_new (GCR_TYPE_CERTIFICATE_DETAILS_WIDGET, "certificate", certificate, NULL);
+}
+
+GcrCertificate*
+gcr_certificate_details_widget_get_certificate (GcrCertificateDetailsWidget *self)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE_DETAILS_WIDGET (self), NULL);
+	return self->pv->certificate;
+}
+
+void
+gcr_certificate_details_widget_set_certificate (GcrCertificateDetailsWidget *self, GcrCertificate *cert)
+{
+	g_return_if_fail (GCR_IS_CERTIFICATE_DETAILS_WIDGET (self));
+	
+	if (self->pv->certificate)
+		g_object_unref (self->pv->certificate);
+	self->pv->certificate = cert;
+	if (self->pv->certificate)
+		g_object_ref (self->pv->certificate);	
+	
+	refresh_display (self);
+	g_object_notify (G_OBJECT (self), "certificate");
+}

Added: trunk/gcr/gcr-certificate-details-widget.h
==============================================================================
--- (empty file)
+++ trunk/gcr/gcr-certificate-details-widget.h	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,57 @@
+/* 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCR_CERTIFICATE_DETAILS_WIDGET_H__
+#define __GCR_CERTIFICATE_DETAILS_WIDGET_H__
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gcr-certificate.h"
+
+#define GCR_TYPE_CERTIFICATE_DETAILS_WIDGET               (gcr_certificate_details_widget_get_type ())
+#define GCR_CERTIFICATE_DETAILS_WIDGET(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET, GcrCertificateDetailsWidget))
+#define GCR_CERTIFICATE_DETAILS_WIDGET_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET, GcrCertificateDetailsWidgetClass))
+#define GCR_IS_CERTIFICATE_DETAILS_WIDGET(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET))
+#define GCR_IS_CERTIFICATE_DETAILS_WIDGET_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET))
+#define GCR_CERTIFICATE_DETAILS_WIDGET_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE_DETAILS_WIDGET, GcrCertificateDetailsWidgetClass))
+
+typedef struct _GcrCertificateDetailsWidget GcrCertificateDetailsWidget;
+typedef struct _GcrCertificateDetailsWidgetClass GcrCertificateDetailsWidgetClass;
+typedef struct _GcrCertificateDetailsWidgetPrivate GcrCertificateDetailsWidgetPrivate;
+    
+struct _GcrCertificateDetailsWidget {
+	GtkAlignment parent;
+	GcrCertificateDetailsWidgetPrivate *pv;
+};
+
+struct _GcrCertificateDetailsWidgetClass {
+	GtkAlignmentClass parent_class;
+};
+
+GType                         gcr_certificate_details_widget_get_type               (void);
+
+GcrCertificateDetailsWidget*  gcr_certificate_details_widget_new                    (GcrCertificate *cert);
+
+GcrCertificate*               gcr_certificate_details_widget_get_certificate        (GcrCertificateDetailsWidget *details);
+
+void                          gcr_certificate_details_widget_set_certificate        (GcrCertificateDetailsWidget *details, 
+                                                                                     GcrCertificate *cert);
+
+#endif /* __GCR_CERTIFICATE_DETAILS_WIDGET_H__ */

Added: trunk/gcr/gcr-certificate.c
==============================================================================
--- (empty file)
+++ trunk/gcr/gcr-certificate.c	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,398 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#include "config.h"
+
+#include "gcr-internal.h"
+#include "gcr-certificate.h"
+
+#include "egg/egg-asn1.h"
+#include "egg/egg-hex.h"
+
+#include <string.h>
+
+struct _GcrCertificatePrivate {
+	/* Cache of data returned  from get_der_data() */ 
+	ASN1_TYPE asn1;
+	gconstpointer data;
+	gsize n_data;
+	
+	/* When initialized with gcr_certificate_new_for_data() */
+	guchar *owned_data;
+	gsize n_owned_data;
+};
+
+G_DEFINE_TYPE (GcrCertificate, gcr_certificate, G_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * INTERNAL 
+ */
+
+static ASN1_TYPE
+parse_certificate_asn1 (GcrCertificate *self)
+{
+	const guchar *data;
+	gsize n_data;
+	
+	g_assert (GCR_IS_CERTIFICATE (self));
+	
+	data = gcr_certificate_get_der_data (self, &n_data);
+	g_return_val_if_fail (data, NULL);
+
+	if (self->pv->asn1 && n_data == self->pv->n_data && 
+	    memcmp (data, self->pv->data, n_data) == 0)
+		return self->pv->asn1;
+	
+	if (self->pv->asn1) {
+		asn1_delete_structure (&self->pv->asn1);
+		self->pv->asn1 = NULL;
+		self->pv->data = NULL;
+		self->pv->n_data = 0;
+	}
+	
+	/* Cache is invalid or non existent */
+	self->pv->asn1 = egg_asn1_decode ("PKIX1.Certificate", data, n_data);
+	if (self->pv->asn1 == NULL) {
+		g_warning ("encountered invalid or unparseable X509 DER certificate data.");
+		return NULL;
+	}
+	
+	self->pv->data = data;
+	self->pv->n_data = n_data;
+
+	return self->pv->asn1;
+}
+
+static GChecksum*
+digest_certificate (GcrCertificate *self, GChecksumType type)
+{
+	GChecksum *digest;
+	const guchar *der;
+	gsize n_der;
+	
+	g_assert (GCR_IS_CERTIFICATE (self));
+
+	der = gcr_certificate_get_der_data (self, &n_der);
+	g_return_val_if_fail (der, NULL);
+	
+	digest = g_checksum_new (type);
+	g_return_val_if_fail (digest, NULL);
+	
+	g_checksum_update (digest, der, n_der);
+	return digest;
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT 
+ */
+
+static const guchar* 
+gcr_certificate_real_get_der_data (GcrCertificate *self, gsize *n_data)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	g_return_val_if_fail (n_data, NULL);
+	g_return_val_if_fail (self->pv->owned_data, NULL);
+	
+	/* This is called when we're not a base class */
+	*n_data = self->pv->n_owned_data;
+	return self->pv->owned_data;
+}
+
+static GObject* 
+gcr_certificate_constructor (GType type, guint n_props, GObjectConstructParam *props) 
+{
+	GcrCertificate *self = GCR_CERTIFICATE (G_OBJECT_CLASS (gcr_certificate_parent_class)->constructor(type, n_props, props));
+	g_return_val_if_fail (self, NULL);	
+	
+	return G_OBJECT (self);
+}
+
+static void
+gcr_certificate_init (GcrCertificate *self)
+{
+	self->pv = G_TYPE_INSTANCE_GET_PRIVATE (self, GCR_TYPE_CERTIFICATE, GcrCertificatePrivate);
+}
+
+static void
+gcr_certificate_dispose (GObject *obj)
+{
+	GcrCertificate *self = GCR_CERTIFICATE (obj);
+
+	if (self->pv->asn1) {
+		asn1_delete_structure (&self->pv->asn1);
+		self->pv->data = NULL;
+		self->pv->n_data = 0;
+	}
+    
+	G_OBJECT_CLASS (gcr_certificate_parent_class)->dispose (obj);
+}
+
+static void
+gcr_certificate_finalize (GObject *obj)
+{
+	GcrCertificate *self = GCR_CERTIFICATE (obj);
+	
+	g_assert (self->pv->asn1 == NULL);
+	g_free (self->pv->owned_data);
+	self->pv->owned_data = NULL;
+	self->pv->n_owned_data = 0;
+
+	G_OBJECT_CLASS (gcr_certificate_parent_class)->finalize (obj);
+}
+
+static void
+gcr_certificate_set_property (GObject *obj, guint prop_id, const GValue *value, 
+                              GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_get_property (GObject *obj, guint prop_id, GValue *value, 
+                              GParamSpec *pspec)
+{
+	switch (prop_id) {
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+gcr_certificate_class_init (GcrCertificateClass *klass)
+{
+	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+    
+	gobject_class->constructor = gcr_certificate_constructor;
+	gobject_class->dispose = gcr_certificate_dispose;
+	gobject_class->finalize = gcr_certificate_finalize;
+	gobject_class->set_property = gcr_certificate_set_property;
+	gobject_class->get_property = gcr_certificate_get_property;
+	
+	klass->get_der_data = gcr_certificate_real_get_der_data;
+    
+	g_type_class_add_private (gobject_class, sizeof (GcrCertificatePrivate));
+
+	_gcr_initialize ();
+}
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC 
+ */
+
+GcrCertificate*
+gcr_certificate_new_for_data (const guchar *data, gsize n_data)
+{
+	GcrCertificate *cert;
+	
+	g_return_val_if_fail (data, NULL);
+	g_return_val_if_fail (n_data, NULL);
+	
+	cert = g_object_new (GCR_TYPE_CERTIFICATE, NULL);
+	
+	cert->pv->owned_data = g_memdup (data, n_data);
+	cert->pv->n_owned_data = n_data;
+	return cert;
+}
+
+const guchar*
+gcr_certificate_get_der_data (GcrCertificate *self, gsize *n_length)
+{
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	g_return_val_if_fail (GCR_CERTIFICATE_GET_CLASS (self)->get_der_data, NULL);
+	return GCR_CERTIFICATE_GET_CLASS (self)->get_der_data (self, n_length);
+}
+
+gchar*
+gcr_certificate_get_issuer_cn (GcrCertificate *self)
+{
+	return gcr_certificate_get_issuer_part (self, "cn");
+}
+
+gchar*
+gcr_certificate_get_issuer_part (GcrCertificate *self, const char *part)
+{
+	ASN1_TYPE asn1;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	asn1 = parse_certificate_asn1 (self);
+	g_return_val_if_fail (asn1, NULL);
+	
+	return egg_asn1_read_dn_part (asn1, "tbsCertificate.issuer.rdnSequence", part);
+}
+
+gchar*
+gcr_certificate_get_issuer_dn (GcrCertificate *self)
+{
+	ASN1_TYPE asn1;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	asn1 = parse_certificate_asn1 (self);
+	g_return_val_if_fail (asn1, NULL);
+	
+	return egg_asn1_read_dn (asn1, "tbsCertificate.issuer.rdnSequence"); 
+}
+
+gchar* 
+gcr_certificate_get_subject_cn (GcrCertificate *self)
+{
+	return gcr_certificate_get_subject_part (self, "cn");
+}
+
+gchar* 
+gcr_certificate_get_subject_part (GcrCertificate *self, const char *part)
+{
+	ASN1_TYPE asn1;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	asn1 = parse_certificate_asn1 (self);
+	g_return_val_if_fail (asn1, NULL);
+	
+	return egg_asn1_read_dn_part (asn1, "tbsCertificate.subject.rdnSequence", part); 
+}
+
+gchar* 
+gcr_certificate_get_subject_dn (GcrCertificate *self)
+{
+	ASN1_TYPE asn1;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	asn1 = parse_certificate_asn1 (self);
+	g_return_val_if_fail (asn1, NULL);
+	
+	return egg_asn1_read_dn (asn1, "tbsCertificate.issuer.rdnSequence"); 	
+}
+
+GDate* 
+gcr_certificate_get_issued_date (GcrCertificate *self)
+{
+	ASN1_TYPE asn1;
+	GDate *date;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	asn1 = parse_certificate_asn1 (self);
+	g_return_val_if_fail (asn1, NULL);
+	
+	date = g_date_new ();
+	if (!egg_asn1_read_date (asn1, "tbsCertificate.validity.notBefore", date)) {
+		g_date_free (date);
+		return NULL;
+	}
+	
+	return date;
+}
+
+GDate* 
+gcr_certificate_get_expiry_date (GcrCertificate *self)
+{
+	ASN1_TYPE asn1;
+	GDate *date;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	asn1 = parse_certificate_asn1 (self);
+	g_return_val_if_fail (asn1, NULL);
+	
+	date = g_date_new ();
+	if (!egg_asn1_read_date (asn1, "tbsCertificate.validity.notAfter", date)) {
+		g_date_free (date);
+		return NULL;
+	}
+	
+	return date;
+}
+
+guchar*
+gcr_certificate_get_fingerprint (GcrCertificate *self, GChecksumType type, gsize *n_digest)
+{
+	GChecksum *sum;
+	guchar *digest;
+	gssize length;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	g_return_val_if_fail (n_digest, NULL);
+	
+	sum = digest_certificate (self, type);
+	g_return_val_if_fail (sum, NULL);
+	length = g_checksum_type_get_length (type);
+	g_return_val_if_fail (length > 0, NULL);
+	digest = g_malloc (length);
+	*n_digest = length;
+	g_checksum_get_digest (sum, digest, n_digest);
+	g_checksum_free (sum);
+	
+	return digest;
+}
+
+gchar*
+gcr_certificate_get_fingerprint_hex (GcrCertificate *self, GChecksumType type)
+{
+	GChecksum *sum;
+	gchar *hex;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	sum = digest_certificate (self, type);
+	g_return_val_if_fail (sum, NULL);
+	hex = g_strdup (g_checksum_get_string (sum));
+	g_checksum_free (sum);
+	return hex;
+}
+
+guchar*
+gcr_certificate_get_serial_number (GcrCertificate *self, gsize *n_length)
+{
+	ASN1_TYPE asn1;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	asn1 = parse_certificate_asn1 (self);
+	g_return_val_if_fail (asn1, NULL);
+	
+	return egg_asn1_read_value (asn1, "tbsCertificate.serialNumber", n_length, g_realloc); 
+}
+
+gchar*
+gcr_certificate_get_serial_number_hex (GcrCertificate *self)
+{
+	guchar *serial;
+	gsize n_serial;
+	gchar *hex;
+	
+	g_return_val_if_fail (GCR_IS_CERTIFICATE (self), NULL);
+	
+	serial = gcr_certificate_get_serial_number (self, &n_serial);
+	if (serial == NULL)
+		return NULL;
+	
+	hex = egg_hex_encode (serial, n_serial);
+	g_free (serial);
+	return hex;
+}

Added: trunk/gcr/gcr-certificate.h
==============================================================================
--- (empty file)
+++ trunk/gcr/gcr-certificate.h	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,91 @@
+/* 
+ * gnome-keyring
+ * 
+ * Copyright (C) 2008 Stefan Walter
+ * 
+ * This program is free software; you can redistribute it and/or modify 
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *  
+ * This program 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
+ * Lesser General Public License for more details.
+ *  
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.  
+ */
+
+#ifndef __GCR_CERTIFICATE_H__
+#define __GCR_CERTIFICATE_H__
+
+#include "gcr.h"
+
+#include <glib-object.h>
+
+#define GCR_TYPE_CERTIFICATE               (gcr_certificate_get_type ())
+#define GCR_CERTIFICATE(obj)               (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCR_TYPE_CERTIFICATE, GcrCertificate))
+#define GCR_CERTIFICATE_CLASS(klass)       (G_TYPE_CHECK_CLASS_CAST ((klass), GCR_TYPE_CERTIFICATE, GcrCertificateClass))
+#define GCR_IS_CERTIFICATE(obj)            (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCR_TYPE_CERTIFICATE))
+#define GCR_IS_CERTIFICATE_CLASS(klass)    (G_TYPE_CHECK_CLASS_TYPE ((klass), GCR_TYPE_CERTIFICATE))
+#define GCR_CERTIFICATE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), GCR_TYPE_CERTIFICATE, GcrCertificateClass))
+
+typedef struct _GcrCertificate GcrCertificate;
+typedef struct _GcrCertificateClass GcrCertificateClass;
+typedef struct _GcrCertificatePrivate GcrCertificatePrivate;
+
+struct _GcrCertificate {
+	GObject parent;
+	GcrCertificatePrivate *pv;
+};
+
+struct _GcrCertificateClass {
+	GObjectClass parent_class;
+    
+	/* virtual  */
+    
+	const guchar* (*get_der_data) (GcrCertificate *self, gsize *n_length);
+};
+
+GType               gcr_certificate_get_type               (void);
+
+GcrCertificate*     gcr_certificate_new_for_data           (const guchar *data,
+                                                            gsize n_data);
+
+const guchar*       gcr_certificate_get_der_data           (GcrCertificate *self, 
+                                                            gsize *n_data);
+
+gchar*              gcr_certificate_get_issuer_cn          (GcrCertificate *self);
+
+gchar*              gcr_certificate_get_issuer_dn          (GcrCertificate *self);
+
+gchar*              gcr_certificate_get_issuer_part        (GcrCertificate *self, 
+                                                            const gchar *part);
+
+gchar*              gcr_certificate_get_subject_cn         (GcrCertificate *self);
+
+gchar*              gcr_certificate_get_subject_dn         (GcrCertificate *self);
+
+gchar*              gcr_certificate_get_subject_part       (GcrCertificate *self, 
+                                                            const gchar *part);
+
+GDate*              gcr_certificate_get_issued_date        (GcrCertificate *self);
+
+GDate*              gcr_certificate_get_expiry_date        (GcrCertificate *self);
+
+guchar*             gcr_certificate_get_serial_number      (GcrCertificate *self, 
+                                                            gsize *n_length);
+
+gchar*              gcr_certificate_get_serial_number_hex  (GcrCertificate *self);
+
+guchar*             gcr_certificate_get_fingerprint        (GcrCertificate *self, 
+                                                            GChecksumType type, 
+                                                            gsize *n_length);
+
+gchar*              gcr_certificate_get_fingerprint_hex    (GcrCertificate *self, 
+                                                            GChecksumType type);
+
+#endif /* __GCR_CERTIFICATE_H__ */

Modified: trunk/gcr/gcr-library.c
==============================================================================
--- trunk/gcr/gcr-library.c	(original)
+++ trunk/gcr/gcr-library.c	Wed Jan 28 01:38:38 2009
@@ -180,7 +180,8 @@
 		
 		/* Only initialize libgcrypt if it hasn't already been initialized */
 		if (!gcry_control (GCRYCTL_INITIALIZATION_FINISHED_P)) {
-			gcry_control (GCRYCTL_SET_THREAD_CBS, &glib_thread_cbs);
+			if (g_thread_supported())
+				gcry_control (GCRYCTL_SET_THREAD_CBS, &glib_thread_cbs);
 			gcry_check_version (LIBGCRYPT_VERSION);
 			gcry_set_log_handler (log_handler, NULL);
 			gcry_set_outofcore_handler (no_mem_handler, NULL);

Modified: trunk/gcr/gcr-parser.c
==============================================================================
--- trunk/gcr/gcr-parser.c	(original)
+++ trunk/gcr/gcr-parser.c	Wed Jan 28 01:38:38 2009
@@ -553,7 +553,7 @@
 		if (!egg_symkey_read_cipher (scheme, password, -1, params, n_params, &cih))
 			break;
 			
-		crypted = egg_asn1_read_value (asn, "encryptedData", &n_crypted, egg_secure_realloc);
+		crypted = egg_asn1_read_value (asn, "encryptedData", &n_crypted, (EggAllocator)egg_secure_realloc);
 		if (!crypted)
 			break;
 	
@@ -892,7 +892,7 @@
 		}
 			
 		crypted = egg_asn1_read_value (asn, "encryptedContentInfo.encryptedContent", 
-		                               &n_crypted, egg_secure_realloc);
+		                               &n_crypted, (EggAllocator)egg_secure_realloc);
 		if (!crypted)
 			goto done;
 	

Modified: trunk/gcr/tests/Makefile.am
==============================================================================
--- trunk/gcr/tests/Makefile.am	(original)
+++ trunk/gcr/tests/Makefile.am	Wed Jan 28 01:38:38 2009
@@ -1,10 +1,9 @@
 
 # Test files should be listed in order they need to run
 UNIT_AUTO = \
+	unit-test-certificate.c \
 	unit-test-parser.c
 
-UNIT_PROMPT = 
-
 UNIT_LIBS =  \
 	$(top_builddir)/gcr/libgcr.la \
 	$(top_builddir)/egg/libegg.la \
@@ -15,3 +14,22 @@
 	-DGCR_API_SUBJECT_TO_CHANGE
 
 include $(top_srcdir)/tests/gtest.make
+
+# ------------------------------------------------------------------
+
+noinst_PROGRAMS += \
+	ui-test-details
+
+ui_test_details_SOURCES = \
+	ui-test-details.c
+
+ui_test_details_CFLAGS = \
+	-DGCR_API_SUBJECT_TO_CHANGE \
+	$(GTK_CFLAGS)
+	
+ui_test_details_LDADD = \
+	$(top_builddir)/gcr/libgcr.la \
+	$(GTK_LIBS) \
+	$(LIBGCRYPT_LIBS) \
+	$(LIBTASN1_LIBS)
+	
\ No newline at end of file

Added: trunk/gcr/tests/ui-test-details.c
==============================================================================
--- (empty file)
+++ trunk/gcr/tests/ui-test-details.c	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,45 @@
+
+#include "config.h"
+
+#include "gcr-certificate-details-widget.h"
+
+#include <gtk/gtk.h>
+
+static void
+test_details (void)
+{
+	GcrCertificateDetailsWidget *details;
+	GcrCertificate *certificate;
+	GtkDialog *dialog;
+	guchar *data;
+	gsize n_data;
+	
+	if (!g_file_get_contents ("test-data/der-certificate.crt", (gchar**)&data, &n_data, NULL))
+		g_assert_not_reached ();
+	
+	certificate = gcr_certificate_new_for_data (data, n_data);
+	g_assert (certificate);
+	g_free (data);
+	
+	dialog = GTK_DIALOG (gtk_dialog_new ());
+	g_object_ref_sink (dialog);
+	
+	details = gcr_certificate_details_widget_new (certificate);
+	gtk_widget_show (GTK_WIDGET (details));
+	gtk_container_add (GTK_CONTAINER (dialog->vbox), GTK_WIDGET (details));
+
+	gtk_window_set_default_size (GTK_WINDOW (dialog), 400, 400);
+	gtk_dialog_run (dialog);
+	
+	g_object_unref (dialog);
+	g_object_unref (certificate);
+	g_object_unref (details);
+}
+
+int
+main(int argc, char *argv[])
+{
+	gtk_init (&argc, &argv);
+	test_details ();
+	return 0;
+}

Added: trunk/gcr/tests/unit-test-certificate.c
==============================================================================
--- (empty file)
+++ trunk/gcr/tests/unit-test-certificate.c	Wed Jan 28 01:38:38 2009
@@ -0,0 +1,139 @@
+
+#include "config.h"
+#include "run-auto-test.h"
+
+#include "gcr-certificate.h"
+
+#include <glib.h>
+
+#include <string.h>
+
+static GcrCertificate *certificate = NULL;
+
+DEFINE_SETUP(certificate)
+{
+	GError *err = NULL;
+	gchar *contents;
+	gsize n_contents;
+	
+	if (!g_file_get_contents ("test-data/der-certificate.crt", &contents, &n_contents, &err)) {
+		g_warning ("couldn't read test-data/test-certificate-1.der: %s", err->message);
+		return;
+	}
+
+	certificate = gcr_certificate_new_for_data ((const guchar*)contents, n_contents);
+	g_assert (certificate);
+	g_free (contents);
+}
+
+DEFINE_TEARDOWN(certificate)
+{
+	if (certificate)
+		g_object_unref (certificate);
+	certificate = NULL;
+}
+
+DEFINE_TEST(issuer_cn)
+{
+	gchar *cn = gcr_certificate_get_issuer_cn (certificate);
+	g_assert (cn);
+	g_assert_cmpstr (cn, ==, "http://www.valicert.com/";);
+	g_free (cn);
+}
+
+DEFINE_TEST(issuer_dn)
+{
+	gchar *dn = gcr_certificate_get_issuer_dn (certificate);
+	g_assert (dn);
+	g_assert_cmpstr (dn, ==, "L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 3 Policy Validation Authority, CN=http://www.valicert.com/, EMAIL=info valicert com");
+	g_free (dn);
+}
+
+DEFINE_TEST(issuer_part)
+{
+	gchar *part = gcr_certificate_get_issuer_part (certificate, "l");
+	g_assert (part);
+	g_assert_cmpstr (part, ==, "ValiCert Validation Network");
+	g_free (part);
+}
+
+DEFINE_TEST(subject_cn)
+{
+	gchar *cn = gcr_certificate_get_subject_cn (certificate);
+	g_assert (cn);
+	g_assert_cmpstr (cn, ==, "http://www.valicert.com/";);
+	g_free (cn);
+}
+
+DEFINE_TEST(subject_dn)
+{
+	gchar *dn = gcr_certificate_get_subject_dn (certificate);
+	g_assert (dn);
+	g_assert_cmpstr (dn, ==, "L=ValiCert Validation Network, O=ValiCert, Inc., OU=ValiCert Class 3 Policy Validation Authority, CN=http://www.valicert.com/, EMAIL=info valicert com");
+	g_free (dn);
+}
+
+DEFINE_TEST(subject_part)
+{
+	gchar *part = gcr_certificate_get_subject_part (certificate, "OU");
+	g_assert (part);
+	g_assert_cmpstr (part, ==, "ValiCert Class 3 Policy Validation Authority");
+	g_free (part);
+}
+
+DEFINE_TEST(issued_date)
+{
+	GDate *date = gcr_certificate_get_issued_date (certificate);
+	g_assert (date);
+	g_assert_cmpuint (g_date_get_year (date), ==, 1999);
+	g_assert_cmpuint (g_date_get_month (date), ==, 6);
+	g_assert_cmpuint (g_date_get_day (date), ==, 26);
+	g_date_free (date);
+}
+
+DEFINE_TEST(expiry_date)
+{
+	GDate *date = gcr_certificate_get_expiry_date (certificate);
+	g_assert (date);
+	g_assert_cmpuint (g_date_get_year (date), ==, 2019);
+	g_assert_cmpuint (g_date_get_month (date), ==, 6);
+	g_assert_cmpuint (g_date_get_day (date), ==, 26);
+	g_date_free (date);
+}
+
+DEFINE_TEST(serial_number)
+{
+	gsize n_serial;
+	guchar *serial;
+	gchar *hex;
+	
+	serial = gcr_certificate_get_serial_number (certificate, &n_serial);
+	g_assert (serial);
+	g_assert_cmpuint (n_serial, ==, 1);
+	g_assert (memcmp (serial, "\1", n_serial) == 0);
+	g_free (serial);
+
+	hex = gcr_certificate_get_serial_number_hex (certificate);
+	g_assert (hex);
+	g_assert_cmpstr (hex, ==, "01");
+	g_free (hex);
+}
+
+DEFINE_TEST(fingerprint)
+{
+	gsize n_print;
+	guchar *print = gcr_certificate_get_fingerprint (certificate, G_CHECKSUM_MD5, &n_print);
+	g_assert (print);
+	g_assert_cmpuint (n_print, ==, g_checksum_type_get_length (G_CHECKSUM_MD5));
+	g_assert (memcmp (print, "\xa2\x6f\x53\xb7\xee\x40\xdb\x4a\x68\xe7\xfa\x18\xd9\x10\x4b\x72", n_print) == 0);
+	g_free (print);
+}
+
+DEFINE_TEST(fingerprint_hex)
+{
+	gchar *print = gcr_certificate_get_fingerprint_hex (certificate, G_CHECKSUM_MD5);
+	g_assert (print);
+	g_assert_cmpstr (print, ==, "a26f53b7ee40db4a68e7fa18d9104b72");
+	g_free (print);
+}
+

Modified: trunk/po/POTFILES.in
==============================================================================
--- trunk/po/POTFILES.in	(original)
+++ trunk/po/POTFILES.in	Wed Jan 28 01:38:38 2009
@@ -15,6 +15,10 @@
 daemon/pkix/gkr-pkix-parser.c
 daemon/pkix/gkr-pkix-serialize.c
 daemon/ui/gkr-ask-tool.c
+egg/egg-asn1.c
+gcr/gcr-certificate-basics-widget.c
+gcr/gcr-certificate-basics-widget.glade
+gcr/gcr-certificate-details-widget.c
 gcr/gcr-import-dialog.glade
 gcr/gcr-importer.c
 gcr/gcr-parser.c
@@ -22,4 +26,3 @@
 library/gnome-keyring-utils.c
 pkcs11/gck/gck-certificate.c
 pkcs11/ssh-store/gck-ssh-private-key.c
-

Modified: trunk/po/POTFILES.skip
==============================================================================
--- trunk/po/POTFILES.skip	(original)
+++ trunk/po/POTFILES.skip	Wed Jan 28 01:38:38 2009
@@ -1,2 +1,3 @@
 daemon/gnome-keyring-daemon.desktop.in
 gcr/gcr-import-dialog.ui
+gcr/gcr-certificate-basics-widget.ui



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]