gnome-keyring r1403 - in trunk: . pkcs11 pkcs11/gck pkcs11/gck/tests pkcs11/gck/tests/test-data tests



Author: nnielsen
Date: Mon Dec 22 20:21:06 2008
New Revision: 1403
URL: http://svn.gnome.org/viewvc/gnome-keyring?rev=1403&view=rev

Log:
	* pkcs11/gck/tests/*: (added)
	* pkcs11/gck/gck-crypto.c:
	* pkcs11/gck/gck-crypto.h:
	* pkcs11/gck/gck-data-asn1.c:
	* pkcs11/gck/gck-data-asn1.h:
	* pkcs11/gck/gck-data-der.c: (added)
	* pkcs11/gck/gck-data-der.h: (added)
	* pkcs11/gck/gck-data-openssl.c: (added)
	* pkcs11/gck/gck-data-openssl.h: (added)
	* pkcs11/gck/gck-data-pem.c: (added)
	* pkcs11/gck/gck-data-pem.h: (added)
	* pkcs11/gck/gck-data-types.h: (added)
	* pkcs11/gck/gck-file-tracker.c: (added)
	* pkcs11/gck/gck-file-tracker.h: (added)
	* pkcs11/gck/gck-module.c:
	* pkcs11/gck/gck-module.h: 
	* pkcs11/gck/gck-module-ep.h:
	* pkcs11/gck/temporary-test.c: 
	* pkcs11/gck/Makefile.am:
	* pkcs11/gck/pk.asn: (added)
	* pkcs11/gck/pkix.asn: (added)
	* pkcs11/Makefile.am:
	* tests/gtest-helpers.c:
	* tests/gtest.make:
	* configure.in: Migrate lots of data processing code over to 
	new GCK component. Vet for thread-safety, add unit-tests,
	and disable code not covered by unit tests.


Added:
   trunk/pkcs11/gck/gck-data-asn1.c
   trunk/pkcs11/gck/gck-data-asn1.h
   trunk/pkcs11/gck/gck-data-der.c
   trunk/pkcs11/gck/gck-data-der.h
   trunk/pkcs11/gck/gck-data-openssl.c
   trunk/pkcs11/gck/gck-data-openssl.h
   trunk/pkcs11/gck/gck-data-pem.c
   trunk/pkcs11/gck/gck-data-pem.h
   trunk/pkcs11/gck/gck-data-types.h
   trunk/pkcs11/gck/gck-file-tracker.c
   trunk/pkcs11/gck/gck-file-tracker.h
   trunk/pkcs11/gck/pk.asn
   trunk/pkcs11/gck/pkix.asn
   trunk/pkcs11/gck/tests/   (props changed)
   trunk/pkcs11/gck/tests/Makefile.am
   trunk/pkcs11/gck/tests/test-data/
   trunk/pkcs11/gck/tests/test-data/pem-rsa-enc.key
   trunk/pkcs11/gck/tests/test.asn
   trunk/pkcs11/gck/tests/unit-test-crypto.c
   trunk/pkcs11/gck/tests/unit-test-data-asn1.c
   trunk/pkcs11/gck/tests/unit-test-data-der.c
   trunk/pkcs11/gck/tests/unit-test-data-openssl.c
   trunk/pkcs11/gck/tests/unit-test-file-tracker.c
Modified:
   trunk/ChangeLog
   trunk/configure.in
   trunk/pkcs11/Makefile.am
   trunk/pkcs11/gck/   (props changed)
   trunk/pkcs11/gck/Makefile.am
   trunk/pkcs11/gck/gck-crypto.c
   trunk/pkcs11/gck/gck-crypto.h
   trunk/pkcs11/gck/gck-module-ep.h
   trunk/pkcs11/gck/gck-module.c
   trunk/pkcs11/gck/gck-module.h
   trunk/pkcs11/gck/temporary-test.c
   trunk/tests/gtest-helpers.c
   trunk/tests/gtest.make

Modified: trunk/configure.in
==============================================================================
--- trunk/configure.in	(original)
+++ trunk/configure.in	Mon Dec 22 20:21:06 2008
@@ -513,7 +513,9 @@
 pam/Makefile
 pam/tests/Makefile
 pkcs11/Makefile
+pkcs11/dot-ssh/Makefile
 pkcs11/gck/Makefile
+pkcs11/gck/tests/Makefile
 pkcs11/rpc/Makefile
 pkcs11/tests/Makefile
 po/Makefile.in

Modified: trunk/pkcs11/Makefile.am
==============================================================================
--- trunk/pkcs11/Makefile.am	(original)
+++ trunk/pkcs11/Makefile.am	Mon Dec 22 20:21:06 2008
@@ -41,5 +41,5 @@
 TESTS_DIR = 
 endif
 
-SUBDIRS = . rpc gck $(TESTS_DIR)
+SUBDIRS = . rpc gck dot-ssh $(TESTS_DIR)
 

Modified: trunk/pkcs11/gck/Makefile.am
==============================================================================
--- trunk/pkcs11/gck/Makefile.am	(original)
+++ trunk/pkcs11/gck/Makefile.am	Mon Dec 22 20:21:06 2008
@@ -7,13 +7,22 @@
 	$(GLIB_CFLAGS)
 	
 # ------------------------------------------------------------------------------
-# The dispatch code
+# The GCK library
 
 noinst_LTLIBRARIES = \
 	libgck.la	
 
+BUILT_SOURCES = \
+	asn1-def-pk.h asn1-def-pkix.h
+
 libgck_la_SOURCES = \
 	gck-crypto.c gck-crypto.h \
+	gck-data-asn1.c gck-data-asn1.h \
+	gck-data-der.c gck-data-der.h \
+	gck-data-openssl.c gck-data-openssl.h \
+	gck-data-pem.c gck-data-pem.h \
+	gck-data-types.h \
+	gck-file-tracker.c gck-file-tracker.h \
 	gck-key.c gck-key.h \
 	gck-manager.c gck-manager.h \
 	gck-module.c gck-module.h gck-module-ep.h \
@@ -24,6 +33,16 @@
 	gck-sexp.c gck-sexp.h \
 	gck-util.c gck-util.h 
 	
+asn1-def-pk.h: pk.asn
+	asn1Parser -o asn1-def-pk.h pk.asn 
+	
+asn1-def-pkix.h: pkix.asn
+	asn1Parser -o asn1-def-pkix.h pkix.asn 
+
+EXTRA_DIST = \
+	pkix.asn \
+	pk.asn
+
 # ------------------------------------------------------------------------------
 # TEMPORARY TEST BINARY
 
@@ -32,10 +51,23 @@
 	
 temporary_test_SOURCES = \
 	temporary-test.c
+
+temporary_test_LDFLAGS = \
+	-lpthread
 	
 temporary_test_LDADD = \
 	libgck.la \
+	$(top_builddir)/common/libgkr-module-common.la \
     	$(GOBJECT_LIBS) \
     	$(LIBGCRYPT_LIBS) \
-	$(GLIB_LIBS)
-	
\ No newline at end of file
+	$(GLIB_LIBS) 
+
+# -------------------------------------------------------------------------------
+
+if WITH_TESTS
+TESTS_DIR = tests
+else
+TESTS_DIR = 
+endif
+
+SUBDIRS = . $(TESTS_DIR)

Modified: trunk/pkcs11/gck/gck-crypto.c
==============================================================================
--- trunk/pkcs11/gck/gck-crypto.c	(original)
+++ trunk/pkcs11/gck/gck-crypto.c	Mon Dec 22 20:21:06 2008
@@ -23,6 +23,8 @@
 
 #include "gck-crypto.h"
 
+#include "common/gkr-secure-memory.h"
+
 /* ----------------------------------------------------------------------------
  * INTERNAL
  */
@@ -886,3 +888,574 @@
 {
 	return unpad_rsa_pkcs1 (0x02, bits, padded, n_padded, n_raw);
 }
+
+/* -----------------------------------------------------------------------------
+ * PASSWORD TO KEY/IV
+ */
+
+gboolean
+gck_crypto_symkey_generate_simple (int cipher_algo, int hash_algo, 
+                                   const gchar *password, const guchar *salt, 
+                                   gsize n_salt, int iterations, guchar **key, 
+                                   guchar **iv)
+{
+	gcry_md_hd_t mdh;
+	gcry_error_t gcry;
+	guchar *digest;
+	guchar *digested;
+	guint n_digest;
+	gint pass, i;
+	gint needed_iv, needed_key;
+	guchar *at_iv, *at_key;
+
+	g_assert (cipher_algo);
+	g_assert (hash_algo);
+
+	g_return_val_if_fail (iterations >= 1, FALSE);
+	
+	/* 
+	 * If cipher algo needs more bytes than hash algo has available
+	 * then the entire hashing process is done again (with the previous
+	 * hash bytes as extra input), and so on until satisfied.
+	 */ 
+	
+	needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
+	needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
+	
+	gcry = gcry_md_open (&mdh, hash_algo, 0);
+	if (gcry) {
+		g_warning ("couldn't create '%s' hash context: %s", 
+			   gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
+		return FALSE;
+	}
+
+	n_digest = gcry_md_get_algo_dlen (hash_algo);
+	g_return_val_if_fail (n_digest > 0, FALSE);
+	
+	digest = gkr_secure_alloc (n_digest);
+	g_return_val_if_fail (digest, FALSE);
+	if (key) {
+		*key = gkr_secure_alloc (needed_key);
+		g_return_val_if_fail (*key, FALSE);
+	}
+	if (iv) 
+		*iv = g_new0 (guchar, needed_iv);
+
+	at_key = key ? *key : NULL;
+	at_iv = iv ? *iv : NULL;
+
+	for (pass = 0; TRUE; ++pass) {
+		gcry_md_reset (mdh);
+		
+		/* Hash in the previous buffer on later passes */
+		if (pass > 0)
+			gcry_md_write (mdh, digest, n_digest);
+
+		if (password)
+			gcry_md_write (mdh, password, strlen (password));
+		if (salt && n_salt)
+			gcry_md_write (mdh, salt, n_salt);
+		gcry_md_final (mdh);
+		digested = gcry_md_read (mdh, 0);
+		g_return_val_if_fail (digested, FALSE);
+		memcpy (digest, digested, n_digest);
+		
+		for (i = 1; i < iterations; ++i) {
+			gcry_md_reset (mdh);
+			gcry_md_write (mdh, digest, n_digest);
+			gcry_md_final (mdh);
+			digested = gcry_md_read (mdh, 0);
+			g_return_val_if_fail (digested, FALSE);
+			memcpy (digest, digested, n_digest);
+		}
+		
+		/* Copy as much as possible into the destinations */
+		i = 0; 
+		while (needed_key && i < n_digest) {
+			if (at_key)
+				*(at_key++) = digest[i];
+			needed_key--;
+			i++;
+		}
+		while (needed_iv && i < n_digest) {
+			if (at_iv) 
+				*(at_iv++) = digest[i];
+			needed_iv--;
+			i++;
+		}
+		
+		if (needed_key == 0 && needed_iv == 0)
+			break;
+	}
+
+	gkr_secure_free (digest);
+	gcry_md_close (mdh);
+	
+	return TRUE;
+}
+
+gboolean
+gck_crypto_symkey_generate_pbe (int cipher_algo, int hash_algo, const gchar *password, 
+                                const guchar *salt, gsize n_salt, int iterations, 
+                                guchar **key, guchar **iv)
+{
+	gcry_md_hd_t mdh;
+	gcry_error_t gcry;
+	guchar *digest;
+	guchar *digested;
+	guint i, n_digest;
+	gint needed_iv, needed_key;
+
+	g_assert (cipher_algo);
+	g_assert (hash_algo);
+
+	g_return_val_if_fail (iterations >= 1, FALSE);
+	
+	/* 
+	 * We only do one pass here.
+	 * 
+	 * The key ends up as the first needed_key bytes of the hash buffer.
+	 * The iv ends up as the last needed_iv bytes of the hash buffer. 
+	 * 
+	 * The IV may overlap the key (which is stupid) if the wrong pair of 
+	 * hash/cipher algorithms are chosen.
+	 */ 
+
+	n_digest = gcry_md_get_algo_dlen (hash_algo);
+	g_return_val_if_fail (n_digest > 0, FALSE);
+	
+	needed_key = gcry_cipher_get_algo_keylen (cipher_algo);
+	needed_iv = gcry_cipher_get_algo_blklen (cipher_algo);
+	if (needed_iv + needed_key > 16 || needed_iv + needed_key > n_digest) {
+		g_warning ("using PBE symkey generation with %s using an algorithm that needs " 
+		           "too many bytes of key and/or IV: %s",
+		           gcry_cipher_algo_name (hash_algo), 
+		           gcry_cipher_algo_name (cipher_algo));
+		return FALSE;
+	}
+	
+	gcry = gcry_md_open (&mdh, hash_algo, 0);
+	if (gcry) {
+		g_warning ("couldn't create '%s' hash context: %s", 
+			   gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
+		return FALSE;
+	}
+
+	digest = gkr_secure_alloc (n_digest);
+	g_return_val_if_fail (digest, FALSE);
+	if (key) {
+		*key = gkr_secure_alloc (needed_key);
+		g_return_val_if_fail (*key, FALSE);
+	}
+	if (iv) 
+		*iv = g_new0 (guchar, needed_iv);
+
+	if (password)
+		gcry_md_write (mdh, password, strlen (password));
+	if (salt && n_salt)
+		gcry_md_write (mdh, salt, n_salt);
+	gcry_md_final (mdh);
+	digested = gcry_md_read (mdh, 0);
+	g_return_val_if_fail (digested, FALSE);
+	memcpy (digest, digested, n_digest);
+		
+	for (i = 1; i < iterations; ++i)
+		gcry_md_hash_buffer (hash_algo, digest, digest, n_digest);
+	
+	/* The first x bytes are the key */
+	if (key) {
+		g_assert (needed_key <= n_digest);
+		memcpy (*key, digest, needed_key);
+	}
+	
+	/* The last 16 - x bytes are the iv */
+	if (iv) {
+		g_assert (needed_iv <= n_digest && n_digest >= 16);
+		memcpy (*iv, digest + (16 - needed_iv), needed_iv);
+	}
+		
+	gkr_secure_free (digest);
+	gcry_md_close (mdh);
+	
+	return TRUE;	
+}
+
+static gboolean
+generate_pkcs12 (int hash_algo, int type, const gchar *utf8_password, 
+                 const guchar *salt, gsize n_salt, int iterations,
+                 guchar *output, gsize n_output)
+{
+	gcry_mpi_t num_b1, num_ij;
+	guchar *hash, *buf_i, *buf_b;
+	gcry_md_hd_t mdh;
+	const gchar *p2;
+	guchar *p;
+	gsize n_hash, i;
+	gunichar unich;
+	gcry_error_t gcry;
+	
+	num_b1 = num_ij = NULL;
+	
+	n_hash = gcry_md_get_algo_dlen (hash_algo);
+	g_return_val_if_fail (n_hash > 0, FALSE);
+	
+	gcry = gcry_md_open (&mdh, hash_algo, 0);
+	if (gcry) {
+		g_warning ("couldn't create '%s' hash context: %s", 
+		           gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
+		return FALSE;
+	}
+
+	/* Reqisition me a buffer */
+	hash = gkr_secure_alloc (n_hash);
+	buf_i = gkr_secure_alloc (128);
+	buf_b = gkr_secure_alloc (64);
+	g_return_val_if_fail (hash && buf_i && buf_b, FALSE);
+		
+	/* Bring in the salt */
+	p = buf_i;
+	if (salt) {
+		for (i = 0; i < 64; ++i)
+			*(p++) = salt[i % n_salt];
+	} else {
+		memset (p, 0, 64);
+		p += 64;
+	}
+	
+	/* Bring in the password, as 16bits per character BMP string, ie: UCS2 */
+	if (utf8_password) {
+		p2 = utf8_password;
+		for (i = 0; i < 64; i += 2) {
+			unich = *p2 ? g_utf8_get_char (p2) : 0;
+			*(p++) = (unich & 0xFF00) >> 8;
+			*(p++) = (unich & 0xFF);
+			if (*p2) /* Loop back to beginning if more bytes are needed */
+				p2 = g_utf8_next_char (p2);
+			else
+				p2 = utf8_password;
+		}
+	} else {
+		memset (p, 0, 64);
+		p += 64;
+	}
+	
+	/* Hash and bash */
+	for (;;) {
+		gcry_md_reset (mdh);
+
+		/* Put in the PKCS#12 type of key */
+		for (i = 0; i < 64; ++i)
+			gcry_md_putc (mdh, type);
+			
+		/* Bring in the password */
+		gcry_md_write (mdh, buf_i, utf8_password ? 128 : 64);
+		
+		/* First iteration done */
+		memcpy (hash, gcry_md_read (mdh, hash_algo), n_hash);
+		
+		/* All the other iterations */
+		for (i = 1; i < iterations; i++)
+			gcry_md_hash_buffer (hash_algo, hash, hash, n_hash);
+		
+		/* Take out as much as we need */
+		for (i = 0; i < n_hash && n_output; ++i) {
+			*(output++) = hash[i];
+			--n_output;
+		}
+		
+		/* Is that enough generated keying material? */
+		if (!n_output)
+			break;
+			
+		/* Need more bytes, do some voodoo */
+		for (i = 0; i < 64; ++i)
+			buf_b[i] = hash[i % n_hash];
+		gcry = gcry_mpi_scan (&num_b1, GCRYMPI_FMT_USG, buf_b, 64, NULL);
+		g_return_val_if_fail (gcry == 0, FALSE);
+		gcry_mpi_add_ui (num_b1, num_b1, 1);
+		for (i = 0; i < 128; i += 64) {
+			gcry = gcry_mpi_scan (&num_ij, GCRYMPI_FMT_USG, buf_i + i, 64, NULL);
+			g_return_val_if_fail (gcry == 0, FALSE);
+			gcry_mpi_add (num_ij, num_ij, num_b1);
+			gcry_mpi_clear_highbit (num_ij, 64 * 8);
+			gcry = gcry_mpi_print (GCRYMPI_FMT_USG, buf_i + i, 64, NULL, num_ij);
+			g_return_val_if_fail (gcry == 0, FALSE);
+			gcry_mpi_release (num_ij);
+		}
+	}  
+	
+	gkr_secure_free (buf_i);
+	gkr_secure_free (buf_b);
+	gkr_secure_free (hash);
+	gcry_mpi_release (num_b1);
+	gcry_md_close (mdh);
+	
+	return TRUE;
+}
+
+gboolean
+gck_crypto_symkey_generate_pkcs12 (int cipher_algo, int hash_algo, const gchar *password, 
+                                   const guchar *salt, gsize n_salt,
+                                   int iterations, guchar **key, guchar **iv)
+{
+	gsize n_block, n_key;
+	gboolean ret = TRUE;
+	
+	g_return_val_if_fail (cipher_algo, FALSE);
+	g_return_val_if_fail (hash_algo, FALSE);
+	g_return_val_if_fail (iterations > 0, FALSE);
+	
+	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
+	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
+	
+	if (password && !g_utf8_validate (password, -1, NULL)) {
+		g_warning ("invalid non-UTF8 password");
+		g_return_val_if_reached (FALSE);
+	}
+	
+	if (key)
+		*key = NULL;
+	if (iv)
+		*iv = NULL;
+	
+	/* Generate us an key */
+	if (key) {
+		*key = gkr_secure_alloc (n_key);
+		g_return_val_if_fail (*key != NULL, FALSE);
+		ret = generate_pkcs12 (hash_algo, 1, password, salt, n_salt, 
+		                       iterations, *key, n_key);
+	} 
+	
+	/* Generate us an iv */
+	if (ret && iv) {
+		if (n_block > 1) {
+			*iv = g_malloc (n_block);
+			ret = generate_pkcs12 (hash_algo, 2, password, salt, n_salt, 
+			                       iterations, *iv, n_block);
+		} else {
+			*iv = NULL;
+		}
+	}
+	
+	/* Cleanup in case of failure */
+	if (!ret) {
+		g_free (iv ? *iv : NULL);
+		g_free (key ? *key : NULL);
+	}
+	
+	return ret;
+}
+
+static gboolean
+generate_pbkdf2 (int hash_algo, const gchar *password, gsize n_password,
+		 const guchar *salt, gsize n_salt, guint iterations,
+		 guchar *output, gsize n_output)
+{
+	gcry_md_hd_t mdh;
+	guint u, l, r, i, k;
+	gcry_error_t gcry;
+	guchar *U, *T, *buf;
+	gsize n_buf, n_hash;
+	
+	g_return_val_if_fail (hash_algo > 0, FALSE);
+	g_return_val_if_fail (iterations > 0, FALSE);
+	g_return_val_if_fail (n_output > 0, FALSE);
+	g_return_val_if_fail (n_output < G_MAXUINT32, FALSE);
+
+	n_hash = gcry_md_get_algo_dlen (hash_algo);
+	g_return_val_if_fail (n_hash > 0, FALSE);
+	
+	gcry = gcry_md_open (&mdh, hash_algo, GCRY_MD_FLAG_HMAC);
+	if (gcry != 0) {
+		g_warning ("couldn't create '%s' hash context: %s", 
+		           gcry_md_algo_name (hash_algo), gcry_strerror (gcry));
+		return FALSE;
+	}
+
+	/* Get us a temporary buffers */
+	T = gkr_secure_alloc (n_hash);
+	U = gkr_secure_alloc (n_hash);
+	n_buf = n_salt + 4;
+	buf = gkr_secure_alloc (n_buf);
+	g_return_val_if_fail (buf && T && U, FALSE);
+
+	/* n_hash blocks in output, rounding up */
+	l = ((n_output - 1) / n_hash) + 1;
+	
+	/* number of bytes in last, rounded up, n_hash block */
+	r = n_output - (l - 1) * n_hash;
+	
+	memcpy (buf, salt, n_salt);
+	for (i = 1; i <= l; i++) {
+		memset (T, 0, n_hash);
+		for (u = 1; u <= iterations; u++) {
+			gcry_md_reset (mdh);
+
+			gcry = gcry_md_setkey (mdh, password, n_password);
+			g_return_val_if_fail (gcry == 0, FALSE);
+			
+			/* For first iteration on each block add 4 extra bytes */
+			if (u == 1) {
+				buf[n_salt + 0] = (i & 0xff000000) >> 24;
+				buf[n_salt + 1] = (i & 0x00ff0000) >> 16;
+				buf[n_salt + 2] = (i & 0x0000ff00) >> 8;
+				buf[n_salt + 3] = (i & 0x000000ff) >> 0;
+				
+				gcry_md_write (mdh, buf, n_buf);
+		
+			/* Other iterations, any block */
+			} else {
+				gcry_md_write (mdh, U, n_hash);
+			}
+			
+			memcpy (U, gcry_md_read (mdh, hash_algo), n_hash);
+
+			for (k = 0; k < n_hash; k++)
+				T[k] ^= U[k];
+		}
+
+		memcpy (output + (i - 1) * n_hash, T, i == l ? r : n_hash);
+	}
+	
+	gkr_secure_free (T);
+	gkr_secure_free (U);
+	gkr_secure_free (buf);
+	gcry_md_close (mdh);
+	return TRUE;
+}
+
+gboolean
+gck_crypto_symkey_generate_pbkdf2 (int cipher_algo, int hash_algo, 
+                                   const gchar *password, const guchar *salt, 
+                                   gsize n_salt, int iterations, 
+                                   guchar **key, guchar **iv)
+{
+	gsize n_key, n_block, n_password;
+	gboolean ret = TRUE;
+	
+	g_return_val_if_fail (hash_algo, FALSE);
+	g_return_val_if_fail (cipher_algo, FALSE);
+	g_return_val_if_fail (iterations > 0, FALSE);
+	
+	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
+	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
+	
+	if (key)
+		*key = NULL;
+	if (iv)
+		*iv = NULL;
+		
+	n_password = password ? strlen (password) : 0;
+	
+	/* Generate us an key */
+	if (key) {
+		*key = gkr_secure_alloc (n_key);
+		g_return_val_if_fail (*key != NULL, FALSE);
+		ret = generate_pbkdf2 (hash_algo, password, n_password, salt, n_salt, 
+		                       iterations, *key, n_key);
+	} 
+	
+	/* Generate us an iv */
+	if (ret && iv) {
+		if (n_block > 1) {
+			*iv = g_malloc (n_block);
+			gcry_create_nonce (*iv, n_block);
+		} else {
+			*iv = NULL;
+		}
+	}
+	
+	/* Cleanup in case of failure */
+	if (!ret) {
+		g_free (iv ? *iv : NULL);
+		g_free (key ? *key : NULL);
+	}
+	
+	return ret;
+}
+
+/* --------------------------------------------------------------------------
+ * INITIALIZATION
+ */
+
+static void
+log_handler (gpointer unused, int unknown, const gchar *msg, va_list va)
+{
+	/* TODO: Figure out additional arguments */
+	g_logv ("gcrypt", G_LOG_LEVEL_MESSAGE, msg, va);
+}
+
+static int 
+no_mem_handler (gpointer unused, size_t sz, unsigned int unknown)
+{
+	/* TODO: Figure out additional arguments */
+	g_error ("couldn't allocate %lu bytes of memory", 
+	         (unsigned long int)sz);
+	return 0;
+}
+
+static void
+fatal_handler (gpointer unused, int unknown, const gchar *msg)
+{
+	/* TODO: Figure out additional arguments */
+	g_log ("gcrypt", G_LOG_LEVEL_ERROR, "%s", msg);
+}
+
+static int
+glib_thread_mutex_init (void **lock)
+{
+	*lock = g_mutex_new ();
+	return 0;
+}
+
+static int 
+glib_thread_mutex_destroy (void **lock)
+{
+	g_mutex_free (*lock);
+	return 0;
+}
+
+static int 
+glib_thread_mutex_lock (void **lock)
+{
+	g_mutex_lock (*lock);
+	return 0;
+}
+
+static int 
+glib_thread_mutex_unlock (void **lock)
+{
+	g_mutex_unlock (*lock);
+	return 0;
+}
+
+static struct gcry_thread_cbs glib_thread_cbs = {
+	GCRY_THREAD_OPTION_USER, NULL,
+	glib_thread_mutex_init, glib_thread_mutex_destroy,
+	glib_thread_mutex_lock, glib_thread_mutex_unlock,
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL 
+};
+
+void
+gck_crypto_initialize (void)
+{
+	static gsize gcrypt_initialized = FALSE;
+	unsigned seed;
+
+	if (g_once_init_enter (&gcrypt_initialized)) {
+		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);
+		gcry_set_fatalerror_handler (fatal_handler, NULL);
+		gcry_set_allocation_handler ((gcry_handler_alloc_t)g_malloc, 
+		                             (gcry_handler_alloc_t)gkr_secure_alloc, 
+		                             gkr_secure_check, 
+		                             (gcry_handler_realloc_t)gkr_secure_realloc, 
+		                             gkr_secure_free);
+		gcry_create_nonce (&seed, sizeof (seed));
+		srand (seed);
+		
+		g_once_init_leave (&gcrypt_initialized, 1);
+	}
+}

Modified: trunk/pkcs11/gck/gck-crypto.h
==============================================================================
--- trunk/pkcs11/gck/gck-crypto.h	(original)
+++ trunk/pkcs11/gck/gck-crypto.h	Mon Dec 22 20:21:06 2008
@@ -40,6 +40,8 @@
 	CKM_DSA
 };
 
+void                     gck_crypto_initialize                         (void);
+
 CK_RV                    gck_crypto_perform                            (gcry_sexp_t sexp, 
                                                                         CK_MECHANISM_TYPE mech, 
                                                                         CK_ATTRIBUTE_TYPE method, 
@@ -157,4 +159,40 @@
                                                                         gsize n_padded, 
                                                                         gsize *n_raw);
 
+gboolean                 gck_crypto_symkey_generate_simple             (int cipher_algo, 
+                                                                        int hash_algo, 
+                                                                        const gchar *password, 
+                                                                        const guchar *salt, 
+                                                                        gsize n_salt, 
+                                                                        int iterations, 
+                                                                        guchar **key, 
+                                                                        guchar **iv);
+
+gboolean                 gck_crypto_symkey_generate_pbe                (int cipher_algo, 
+                                                                        int hash_algo, 
+                                                                        const gchar *password, 
+                                                                        const guchar *salt, 
+                                                                        gsize n_salt, 
+                                                                        int iterations, 
+                                                                        guchar **key, 
+                                                                        guchar **iv);
+
+gboolean                 gck_crypto_symkey_generate_pkcs12             (int cipher_algo, 
+                                                                        int hash_algo, 
+                                                                        const gchar *password, 
+                                                                        const guchar *salt, 
+                                                                        gsize n_salt,
+                                                                        int iterations, 
+									guchar **key, 
+									guchar **iv);
+
+gboolean                 gck_crypto_symkey_generate_pbkdf2             (int cipher_algo, 
+                                                                        int hash_algo, 
+                                                                        const gchar *password, 
+                                                                        const guchar *salt, 
+                                                                        gsize n_salt, 
+                                                                        int iterations, 
+                                                                        guchar **key, 
+                                                                        guchar **iv);
+
 #endif /* GCKCRYPTO_H_ */

Added: trunk/pkcs11/gck/gck-data-asn1.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-asn1.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,798 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pkix-asn1.c - ASN.1 helper routines
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-data-asn1.h"
+
+#include "common/gkr-buffer.h"
+#include "common/gkr-secure-memory.h"
+
+#include <libtasn1.h>
+
+/* 
+ * HACK: asn1Parser defines these arrays as extern const, which gives 
+ * gcc a fit. So we def it out. 
+ */
+ 
+#define extern 
+#include "asn1-def-pk.h"
+#include "asn1-def-pkix.h"
+#undef extern 
+
+static ASN1_TYPE asn1_pk = NULL; 
+static ASN1_TYPE asn1_pkix = NULL;
+
+static void
+init_asn1_trees (void)
+{
+	static gsize asn1_initialized = 0;
+	int res;
+	
+	if (g_once_init_enter (&asn1_initialized)) {
+		res = asn1_array2tree (pk_asn1_tab, &asn1_pk, NULL);
+		g_return_if_fail (res == ASN1_SUCCESS);
+		res = asn1_array2tree (pkix_asn1_tab, &asn1_pkix, NULL);
+		g_return_if_fail (res == ASN1_SUCCESS);
+		g_once_init_leave (&asn1_initialized, 1);
+	}
+}
+
+ASN1_TYPE 
+gck_data_asn1_get_pk_asn1type (void)
+{
+	init_asn1_trees ();
+	return asn1_pk;
+}
+
+ASN1_TYPE 
+gck_data_asn1_get_pkix_asn1type (void)
+{
+	init_asn1_trees ();
+	return asn1_pkix;
+}
+	
+ASN1_TYPE
+gck_data_asn1_decode (const gchar *type, const guchar *data, gsize n_data)
+{
+	ASN1_TYPE base = ASN1_TYPE_EMPTY;
+	ASN1_TYPE asn;
+	int res;
+	
+	if (strncmp (type, "PKIX1.", 6) == 0)
+		base = gck_data_asn1_get_pkix_asn1type ();
+	else if (strncmp (type, "PK.", 3) == 0)
+		base = gck_data_asn1_get_pk_asn1type ();
+	else
+		g_return_val_if_reached (NULL);
+		
+	res = asn1_create_element (base, type, &asn); 
+	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+	
+	res = asn1_der_decoding (&asn, data, n_data, NULL);
+	if (res != ASN1_SUCCESS) {
+		asn1_delete_structure (&asn);
+		return NULL;
+	}
+	
+	return asn;
+}
+
+guchar*
+gck_data_asn1_encode (ASN1_TYPE asn, const gchar* part, gsize *n_data, 
+                      GkrBufferAllocator alloc)
+{
+	guchar *data;
+	int res, len;
+	
+	g_assert (asn);
+	g_assert (n_data);
+	
+	len = 0;
+	res = asn1_der_coding (asn, part, NULL, &len, NULL); 
+	g_return_val_if_fail (res == ASN1_MEM_ERROR, NULL);
+	
+	if (!alloc)
+		alloc = (GkrBufferAllocator)g_realloc;
+
+	data = (alloc) (NULL, len);
+	g_return_val_if_fail (data != NULL, NULL);
+	
+	res = asn1_der_coding (asn, part, data, &len, NULL);
+	if (res != ASN1_SUCCESS) {
+		(alloc) (data, 0);
+		return NULL;
+	}
+	
+	*n_data = len;
+	return data;
+}
+
+gint
+gck_data_asn1_element_length (const guchar *data, gsize n_data)
+{
+	guchar cls;
+	int counter = 0;
+	int cb, len;
+	gulong tag;
+	
+	if (asn1_get_tag_der (data, n_data, &cls, &cb, &tag) == ASN1_SUCCESS) {
+		counter += cb;
+		len = asn1_get_length_der (data + cb, n_data - cb, &cb);
+		counter += cb;
+		if (len >= 0) {
+			len += counter;
+			if (n_data >= len)
+				return len;
+		}
+	}
+	
+	return -1;
+}
+
+#ifdef UNTESTED_CODE
+
+const guchar*
+gck_data_asn1_read_element (ASN1_TYPE asn, const guchar *data, gsize n_data, 
+                            const gchar *part, gsize *n_element)
+{
+	int beg, end, res;
+	
+	g_return_val_if_fail (asn != NULL, NULL);
+	g_return_val_if_fail (part != NULL, NULL);
+	g_return_val_if_fail (data != NULL, NULL);
+	g_return_val_if_fail (n_element != NULL, NULL);
+	
+	res = asn1_der_decoding_startEnd (asn, data, n_data, part, &beg, &end);
+	if (res != ASN1_SUCCESS) 
+		return NULL;
+		
+	*n_element = end - beg + 1;
+	return data + beg;
+}                                                               
+
+const guchar*
+gck_data_asn1_read_content (ASN1_TYPE asn, const guchar *data, gsize n_data, 
+                            const gchar *part, gsize *n_content)
+{
+	const guchar *raw;
+	gsize n_raw;
+	
+	g_return_val_if_fail (asn != NULL, NULL);
+	g_return_val_if_fail (part != NULL, NULL);
+	g_return_val_if_fail (data != NULL, NULL);
+	g_return_val_if_fail (n_content != NULL, NULL);
+	
+	raw = gck_data_asn1_read_element (asn, data, n_data, part, &n_raw);
+	if (!raw)
+		return NULL;
+
+	return gck_data_asn1_element_content (raw, n_raw, n_content);		
+}
+
+#endif /* UNTESTED_CODE */
+
+const guchar*
+gck_data_asn1_element_content (const guchar *data, gsize n_data, gsize *n_content)
+{
+	int counter = 0;
+	guchar cls;
+	gulong tag;
+	int cb, len;
+	
+	g_return_val_if_fail (data != NULL, NULL);
+	g_return_val_if_fail (n_content != NULL, NULL);
+	
+	/* Now get the data out of this element */	
+	if (asn1_get_tag_der (data, n_data, &cls, &cb, &tag) != ASN1_SUCCESS)
+		return NULL;
+			
+	counter += cb;
+	len = asn1_get_length_der (data + cb, n_data - cb, &cb);
+	if (len < 0)
+		return NULL;
+	counter += cb;
+	
+	*n_content = len;
+	return data + counter;	
+}
+
+guchar*
+gck_data_asn1_read_value (ASN1_TYPE asn, const gchar *part, gsize *len, 
+                          GkrBufferAllocator allocator)
+{
+	int l, res;
+	guchar *buf;
+	
+	g_return_val_if_fail (asn != NULL, NULL);
+	g_return_val_if_fail (part != NULL, NULL);
+	g_return_val_if_fail (len != NULL, NULL);
+	
+	if (allocator == NULL)
+		allocator = (GkrBufferAllocator)g_realloc;
+	
+	*len = 0;
+
+	l = 0;
+	res = asn1_read_value (asn, part, NULL, &l);
+	g_return_val_if_fail (res != ASN1_SUCCESS, NULL);
+	if (res != ASN1_MEM_ERROR)
+		return NULL;
+		
+	/* Always null terminate it, just for convenience */
+	buf = (allocator) (NULL, l + 1);
+	g_return_val_if_fail (buf, NULL);
+	memset (buf, 0, *len + 1);
+	
+	res = asn1_read_value (asn, part, buf, &l);
+	if (res != ASN1_SUCCESS) {
+		(allocator) (buf, 0);
+		buf = NULL;
+	} else {
+		*len = l;
+	}
+	
+	return buf;
+}
+
+gboolean
+gck_data_asn1_write_value (ASN1_TYPE asn, const gchar *part, 
+		                   const guchar* value, gsize len)
+{
+	int res;
+
+	g_return_val_if_fail (asn, FALSE);
+	g_return_val_if_fail (part, FALSE);
+	g_return_val_if_fail (!len || value, FALSE);
+	
+	res = asn1_write_value (asn, part, (const void*)value, (int)len);
+	return res == ASN1_SUCCESS;
+}
+
+#ifdef UNTESTED_CODE
+
+gboolean
+gck_data_asn1_read_boolean (ASN1_TYPE asn, const gchar *part, gboolean *val)
+{
+	gchar buffer[32];
+	int n_buffer = sizeof (buffer) - 1;
+	int res;
+	
+	memset (buffer, 0, sizeof (buffer));
+	
+	res = asn1_read_value (asn, part, buffer, &n_buffer);
+	if (res != ASN1_SUCCESS)
+		return FALSE;
+		
+	if (g_ascii_strcasecmp (buffer, "TRUE") == 0)
+		*val = TRUE;
+	else
+		*val = FALSE;
+		
+	return TRUE;
+}
+
+#endif /* UNTESTED_CODE */
+
+gboolean
+gck_data_asn1_read_uint (ASN1_TYPE asn, const gchar *part, guint *val)
+{
+	guchar buf[4];
+	int n_buf = sizeof (buf);
+	gsize i;
+	int res;
+	
+	res = asn1_read_value (asn, part, buf, &n_buf);
+	if(res != ASN1_SUCCESS)
+		return FALSE;
+
+	if (n_buf > 4 || n_buf < 1)
+		return FALSE;
+
+	*val = 0;
+	for (i = 0; i < n_buf; ++i)
+		*val |= buf[i] << (8 * ((n_buf - 1) - i));
+
+	return TRUE;
+}
+
+gboolean
+gck_data_asn1_write_uint (ASN1_TYPE asn, const gchar *part, guint32 val)
+{
+	guchar buf[4];
+	int res, bytes;
+		
+	buf[0] = (val >> 24) & 0xff;
+	buf[1] = (val >> 16) & 0xff;
+	buf[2] = (val >> 8) & 0xff;
+	buf[3] = (val >> 0) & 0xff;
+	
+	for (bytes = 3; bytes >= 0; --bytes)
+		if (!buf[bytes])
+			break;
+			
+	bytes = 4 - (bytes + 1);
+	if (bytes == 0)
+		bytes = 1;
+	res = asn1_write_value (asn, part, buf + (4 - bytes), bytes);
+	return res == ASN1_SUCCESS;	
+}
+
+#ifdef UNTESTED_CODE
+
+GQuark
+gck_data_asn1_read_oid (ASN1_TYPE asn, const gchar *part)
+{
+	GQuark quark;
+	guchar *buf;
+	gsize n_buf;
+	
+	buf = gck_data_asn1_read_value (asn, part, &n_buf, NULL);
+	if (!buf)
+		return 0;
+		
+	/* TODO: This should probably just 'try' */
+	quark = g_quark_from_string ((gchar*)buf);
+	g_free (buf);
+	
+	return quark;
+}
+
+gboolean
+gck_data_asn1_write_oid (ASN1_TYPE asn, const gchar *part, GQuark val)
+{
+	const gchar* oid;
+	
+	g_return_val_if_fail (val, FALSE);
+	
+	oid = g_quark_to_string (val);
+	g_return_val_if_fail (oid, FALSE);
+	
+	return gck_data_asn1_write_value (asn, part, (const guchar*)oid, 
+			                          1 /* any non-null value for OID */);
+}
+
+#endif /* UNTESTED_CODE */
+
+gboolean
+gck_data_asn1_read_mpi (ASN1_TYPE asn, const gchar *part, gcry_mpi_t *mpi)
+{
+  	gcry_error_t gcry;
+  	gsize sz;
+  	guchar *buf;
+
+	buf = gck_data_asn1_read_value (asn, part, &sz, (GkrBufferAllocator)g_realloc);
+	if (!buf)
+		return FALSE;
+	
+	gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_STD, buf, sz, &sz);
+	g_free (buf);
+
+	if (gcry != 0)
+		return FALSE;
+	
+	return TRUE;
+}
+
+gboolean
+gck_data_asn1_read_secure_mpi (ASN1_TYPE asn, const gchar *part, gcry_mpi_t *mpi)
+{
+  	gcry_error_t gcry;
+  	gsize sz;
+  	guchar *buf;
+
+	buf = gck_data_asn1_read_value (asn, part, &sz, gkr_secure_realloc);
+	if (!buf)
+		return FALSE;
+	
+	gcry = gcry_mpi_scan (mpi, GCRYMPI_FMT_STD, buf, sz, &sz);
+	gkr_secure_free (buf);
+
+	if (gcry != 0)
+		return FALSE;
+	
+	return TRUE;
+}
+
+gboolean
+gck_data_asn1_write_mpi (ASN1_TYPE asn, const gchar *part, gcry_mpi_t mpi)
+{
+	gcry_error_t gcry;
+	gsize len;
+	guchar *buf;
+	int res;
+
+	g_assert (asn);
+	g_assert (part);
+	g_assert (mpi);
+	
+	/* Get the size */
+	gcry = gcry_mpi_print (GCRYMPI_FMT_STD, NULL, 0, &len, mpi);
+	g_return_val_if_fail (gcry == 0, FALSE);
+	g_return_val_if_fail (len > 0, FALSE); 
+
+	buf = gkr_secure_alloc (len);
+	
+	gcry = gcry_mpi_print (GCRYMPI_FMT_STD, buf, len, &len, mpi);	
+	g_return_val_if_fail (gcry == 0, FALSE);
+	
+	res = asn1_write_value (asn, part, buf, len);
+	gkr_secure_free (buf);
+	
+	if (res != ASN1_SUCCESS)
+		return FALSE;
+		
+	return TRUE;
+}
+
+static int
+atoin (const char *p, int digits)
+{
+	int ret = 0, base = 1;
+	while(--digits >= 0) {
+		if (p[digits] < '0' || p[digits] > '9')
+			return -1;
+		ret += (p[digits] - '0') * base;
+		base *= 10;
+	}
+	return ret;
+}
+
+static int
+two_to_four_digit_year (int year)
+{
+	time_t now;
+	struct tm tm;
+	int century, current;
+	
+	g_return_val_if_fail (year >= 0 && year <= 99, -1);
+	
+	/* Get the current year */
+	now = time (NULL);
+	g_return_val_if_fail (now >= 0, -1);
+	if (!gmtime_r (&now, &tm))
+		g_return_val_if_reached (-1);
+
+	current = (tm.tm_year % 100);
+	century = (tm.tm_year + 1900) - current;
+
+	/* 
+	 * Check if it's within 40 years before the 
+	 * current date. 
+	 */
+	if (current < 40) {
+		if (year < current)
+			return century + year;
+		if (year > 100 - (40 - current))
+			return (century - 100) + year;
+	} else {
+		if (year < current && year > (current - 40))
+			return century + year;
+	}
+	
+	/* 
+	 * If it's after then adjust for overflows to
+	 * the next century.
+	 */
+	if (year < current)
+		return century + 100 + year;
+	else
+		return century + year;
+}
+
+#ifndef HAVE_TIMEGM
+time_t timegm(struct tm *t)
+{
+	time_t tl, tb;
+	struct tm *tg;
+
+	tl = mktime (t);
+	if (tl == -1)
+	{
+		t->tm_hour--;
+		tl = mktime (t);
+		if (tl == -1)
+			return -1; /* can't deal with output from strptime */
+		tl += 3600;
+	}
+	tg = gmtime (&tl);
+	tg->tm_isdst = 0;
+	tb = mktime (tg);
+	if (tb == -1)
+	{
+		tg->tm_hour--;
+		tb = mktime (tg);
+		if (tb == -1)
+			return -1; /* can't deal with output from gmtime */
+		tb += 3600;
+	}
+	return (tl - (tb - tl));
+}
+#endif //NOT_HAVE_TIMEGM
+
+time_t
+gck_data_asn1_parse_utc_time (const gchar *time)
+{
+	struct tm when;
+	guint n_time;
+	time_t result;
+	const char *p, *e;
+	int year;
+
+	g_assert (time);	
+	n_time = strlen (time);
+	
+	/* YYMMDDhhmmss.ffff Z | +0000 */
+	if (n_time < 6 || n_time >= 28) 
+		return -1;
+	
+	/* Reset everything to default legal values */
+	memset (&when, 0, sizeof (when));
+	when.tm_mday = 1;
+	
+	/* Select the digits part of it */
+	p = time;
+	for (e = p; *e >= '0' && *e <= '9'; ++e);
+	
+	if (p + 2 <= e) {
+		year = atoin (p, 2);
+		p += 2;
+		
+		/* 
+		 * 40 years in the past is our century. 60 years
+		 * in the future is the next century. 
+		 */
+		when.tm_year = two_to_four_digit_year (year) - 1900;
+	}
+	if (p + 2 <= e) {
+		when.tm_mon = atoin (p, 2) - 1;
+		p += 2;
+	}
+	if (p + 2 <= e) {
+		when.tm_mday = atoin (p, 2);
+		p += 2;
+	}
+	if (p + 2 <= e) {
+		when.tm_hour = atoin (p, 2);
+		p += 2;
+	}
+	if (p + 2 <= e) {
+		when.tm_min = atoin (p, 2);
+		p += 2;
+	}
+	if (p + 2 <= e) {
+		when.tm_sec = atoin (p, 2);
+		p += 2;
+	}
+
+	if (when.tm_year < 0 || when.tm_year > 9999 ||
+	    when.tm_mon < 0 || when.tm_mon > 11 ||
+	    when.tm_mday < 1 || when.tm_mday > 31 ||
+	    when.tm_hour < 0 || when.tm_hour > 23 ||
+	    when.tm_min < 0 || when.tm_min > 59 ||
+	    when.tm_sec < 0 || when.tm_sec > 59)
+	    	return -1;
+	    	
+	/* Make sure all that got parsed */
+	if (p != e)
+		return -1;
+
+	/* In order to work with 32 bit time_t. */
+  	if (sizeof (time_t) <= 4 && when.tm_year >= 2038)
+		return (time_t) 2145914603;  /* 2037-12-31 23:23:23 */
+		
+	/* Covnvert to seconds since epoch */
+	result = timegm (&when);
+	
+	/* Now the remaining optional stuff */
+	e = time + n_time;
+		
+	/* See if there's a fraction, and discard it if so */
+	if (p < e && *p == '.' && p + 5 <= e)
+		p += 5;
+		
+	/* See if it's UTC */
+	if (p < e && *p == 'Z') {
+		p += 1;
+
+	/* See if it has a timezone */	
+	} else if ((*p == '-' || *p == '+') && p + 3 <= e) { 
+		int off, neg;
+		
+		neg = *p == '-';
+		++p;
+		
+		off = atoin (p, 2) * 3600;
+		if (off < 0 || off > 86400)
+			return -1;
+		p += 2;
+		
+		if (p + 2 <= e) {
+			off += atoin (p, 2) * 60;
+			p += 2;
+		}
+
+		/* Use TZ offset */		
+		if (neg)
+			result -= off;
+		else
+			result += off;
+	}
+
+	/* Make sure everything got parsed */	
+	if (p != e)
+		return -1;
+
+	return result;
+}
+
+time_t
+gck_data_asn1_parse_general_time (const gchar *time)
+{
+	struct tm when;
+	guint n_time;
+	time_t result;
+	const char *p, *e;
+
+	g_assert (time);	
+	n_time = strlen (time);
+	
+	/* YYYYMMDDhhmmss.ffff Z | +0000 */
+	if (n_time < 8 || n_time >= 30) 
+		return -1;
+	
+	/* Reset everything to default legal values */
+	memset (&when, 0, sizeof (when));
+	when.tm_mday = 1;
+	
+	/* Select the digits part of it */
+	p = time;
+	for (e = p; *e >= '0' && *e <= '9'; ++e);
+	
+	if (p + 4 <= e) {
+		when.tm_year = atoin (p, 4) - 1900;
+		p += 4;
+	}
+	if (p + 2 <= e) {
+		when.tm_mon = atoin (p, 2) - 1;
+		p += 2;
+	}
+	if (p + 2 <= e) {
+		when.tm_mday = atoin (p, 2);
+		p += 2;
+	}
+	if (p + 2 <= e) {
+		when.tm_hour = atoin (p, 2);
+		p += 2;
+	}
+	if (p + 2 <= e) {
+		when.tm_min = atoin (p, 2);
+		p += 2;
+	}
+	if (p + 2 <= e) {
+		when.tm_sec = atoin (p, 2);
+		p += 2;
+	}
+
+	if (when.tm_year < 0 || when.tm_year > 9999 ||
+	    when.tm_mon < 0 || when.tm_mon > 11 ||
+	    when.tm_mday < 1 || when.tm_mday > 31 ||
+	    when.tm_hour < 0 || when.tm_hour > 23 ||
+	    when.tm_min < 0 || when.tm_min > 59 ||
+	    when.tm_sec < 0 || when.tm_sec > 59)
+	    	return -1;
+	
+	/* Make sure all that got parsed */
+	if (p != e)
+		return -1;
+		
+	/* Covnvert to seconds since epoch */
+	result = timegm (&when);
+	
+	/* Now the remaining optional stuff */
+	e = time + n_time;
+		
+	/* See if there's a fraction, and discard it if so */
+	if (p < e && *p == '.' && p + 5 <= e)
+		p += 5;
+		
+	/* See if it's UTC */
+	if (p < e && *p == 'Z') {
+		p += 1;
+
+	/* See if it has a timezone */	
+	} else if ((*p == '-' || *p == '+') && p + 3 <= e) { 
+		int off, neg;
+		
+		neg = *p == '-';
+		++p;
+		
+		off = atoin (p, 2) * 3600;
+		if (off < 0 || off > 86400)
+			return -1;
+		p += 2;
+		
+		if (p + 2 <= e) {
+			off += atoin (p, 2) * 60;
+			p += 2;
+		}
+
+		/* Use TZ offset */		
+		if (neg)
+			result -= off;
+		else
+			result += off;
+	}
+
+	/* Make sure everything got parsed */	
+	if (p != e)
+		return -1;
+
+	return result;
+}
+
+#ifdef UNTESTED_CODE
+
+gboolean
+gck_data_asn1_read_time (ASN1_TYPE asn, const gchar *part, time_t *val)
+{
+	#define MAX_TIME 1024
+	gchar ttime[MAX_TIME];
+	gchar *name;
+	int len, res;
+
+	len = sizeof (ttime) - 1;
+	res = asn1_read_value (asn, part, ttime, &len);
+	if (res != ASN1_SUCCESS)
+		return FALSE;
+		
+	/* CHOICE */
+	if (strcmp (ttime, "generalTime") == 0) {
+		name = g_strconcat (part, ".generalTime", NULL);
+		len = sizeof (ttime) - 1;
+		res = asn1_read_value (asn, name, ttime, &len);
+		g_free (name);
+		if (res != ASN1_SUCCESS)
+			return FALSE;
+		
+		*val = gck_data_asn1_parse_general_time (ttime);
+		
+	/* UTCTIME */
+	} else {
+		name = g_strconcat (part, ".utcTime", NULL);
+		len = sizeof (ttime) - 1;
+		res = asn1_read_value (asn, name, ttime, &len);
+		g_free (name);
+		if (res != ASN1_SUCCESS)
+			return FALSE;
+	
+		*val = gck_data_asn1_parse_utc_time (ttime);
+    	}
+
+	if (*val < (time_t)0)
+		return FALSE;
+		
+	return TRUE;	
+}
+
+#endif /* UNTESTED_CODE */

Added: trunk/pkcs11/gck/gck-data-asn1.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-asn1.h	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,84 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-data-asn1.h - ASN.1 helper routines
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#ifndef GCK_DATA_ASN_H_
+#define GCK_DATA_ASN_H_
+
+#include <libtasn1.h>
+#include <gcrypt.h>
+#include <glib.h>
+
+#include "gck-data-types.h"
+
+ASN1_TYPE          gck_data_asn1_get_pk_asn1type               (void);
+
+ASN1_TYPE          gck_data_asn1_get_pkix_asn1type             (void);
+
+ASN1_TYPE          gck_data_asn1_decode                        (const gchar *type, const guchar *data,
+                                                                gsize n_data);
+
+guchar*            gck_data_asn1_encode                        (ASN1_TYPE asn, const gchar* part, 
+                                                                gsize *len, GckDataAllocator alloc); 
+
+guchar*            gck_data_asn1_read_value                    (ASN1_TYPE asn, const gchar *part, 
+                                                                gsize *len, GckDataAllocator alloc);
+
+gboolean           gck_data_asn1_write_value                   (ASN1_TYPE asn, const gchar *part, 
+                                                                const guchar* value, gsize len); 
+
+GQuark             gck_data_asn1_read_oid                      (ASN1_TYPE asn, const gchar *part);
+
+gboolean           gck_data_asn1_write_oid                     (ASN1_TYPE asn, const gchar *part, GQuark val);
+
+gboolean           gck_data_asn1_read_boolean                  (ASN1_TYPE asn, const gchar *part, gboolean *val);
+
+gboolean           gck_data_asn1_read_uint                     (ASN1_TYPE asn, const gchar *part, guint *val);
+
+gboolean           gck_data_asn1_read_time                     (ASN1_TYPE asn, const gchar *part, time_t *val);
+
+const guchar*      gck_data_asn1_read_content                  (ASN1_TYPE asn, const guchar *data, gsize n_data, 
+                                                                const gchar *part, gsize *n_content);
+
+const guchar*      gck_data_asn1_read_element                  (ASN1_TYPE asn, const guchar *data, gsize n_data, 
+                                                                const gchar *part, gsize *n_element);
+                                                                 
+gboolean           gck_data_asn1_write_uint                    (ASN1_TYPE asn, const gchar *part, guint val);
+
+gboolean           gck_data_asn1_read_mpi                      (ASN1_TYPE asn, const gchar *part, 
+                                                                gcry_mpi_t *mpi);
+
+gboolean           gck_data_asn1_read_secure_mpi               (ASN1_TYPE asn, const gchar *part, 
+                                                                gcry_mpi_t *mpi);
+
+gboolean           gck_data_asn1_write_mpi                     (ASN1_TYPE asn, const gchar *part, 
+                                                                gcry_mpi_t mpi);
+                                                                
+gint               gck_data_asn1_element_length                (const guchar *data, gsize n_data);
+
+const guchar*      gck_data_asn1_element_content               (const guchar *data, gsize n_data, gsize *n_content);
+
+time_t             gck_data_asn1_parse_utc_time                (const gchar* value);
+
+time_t             gck_data_asn1_parse_general_time            (const gchar* value);
+
+#endif /*GCK_DATA_ASN_H_*/

Added: trunk/pkcs11/gck/gck-data-der.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-der.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,1399 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-data-der.c - parsing and serializing of common crypto DER structures 
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-crypto.h"
+#include "gck-data-asn1.h"
+#include "gck-data-der.h"
+#include "gck-data-types.h"
+
+#include "common/gkr-secure-memory.h"
+
+#include <glib.h>
+#include <gcrypt.h>
+#include <libtasn1.h>
+
+/* -----------------------------------------------------------------------------
+ * QUARKS
+ */
+
+#ifdef UNTESTED_CODE
+
+static GQuark OID_PKIX1_RSA;
+static GQuark OID_PKIX1_DSA;
+
+static GQuark OID_PBE_MD2_DES_CBC;
+static GQuark OID_PBE_MD5_DES_CBC;
+static GQuark OID_PBE_MD2_RC2_CBC;
+static GQuark OID_PBE_MD5_RC2_CBC;
+static GQuark OID_PBE_SHA1_DES_CBC;
+static GQuark OID_PBE_SHA1_RC2_CBC;
+static GQuark OID_PBES2;
+static GQuark OID_PBKDF2;
+
+static GQuark OID_DES_CBC;
+static GQuark OID_DES_RC2_CBC;
+static GQuark OID_DES_EDE3_CBC;
+static GQuark OID_DES_RC5_CBC;
+
+static GQuark OID_PKCS12_PBE_ARCFOUR_SHA1;
+static GQuark OID_PKCS12_PBE_RC4_40_SHA1;
+static GQuark OID_PKCS12_PBE_3DES_SHA1;
+static GQuark OID_PKCS12_PBE_2DES_SHA1;
+static GQuark OID_PKCS12_PBE_RC2_128_SHA1;
+static GQuark OID_PKCS12_PBE_RC2_40_SHA1;
+
+static void
+init_quarks (void)
+{
+	static gsize quarks_inited = 0;
+
+	if (g_once_init_enter (&quarks_inited)) {
+
+		#define QUARK(name, value) \
+			name = g_quark_from_static_string(value)
+
+		QUARK (OID_PKIX1_RSA, "1.2.840.113549.1.1.1");
+		QUARK (OID_PKIX1_DSA, "1.2.840.10040.4.1");
+
+		QUARK (OID_PBE_MD2_DES_CBC, "1.2.840.113549.1.5.1");
+		QUARK (OID_PBE_MD5_DES_CBC, "1.2.840.113549.1.5.3");
+		QUARK (OID_PBE_MD2_RC2_CBC, "1.2.840.113549.1.5.4");
+		QUARK (OID_PBE_MD5_RC2_CBC, "1.2.840.113549.1.5.6");
+		QUARK (OID_PBE_SHA1_DES_CBC, "1.2.840.113549.1.5.10");
+		QUARK (OID_PBE_SHA1_RC2_CBC, "1.2.840.113549.1.5.11");
+		
+		QUARK (OID_PBES2, "1.2.840.113549.1.5.13");
+		
+		QUARK (OID_PBKDF2, "1.2.840.113549.1.5.12");
+		
+		QUARK (OID_DES_CBC, "1.3.14.3.2.7");
+		QUARK (OID_DES_RC2_CBC, "1.2.840.113549.3.2");
+		QUARK (OID_DES_EDE3_CBC, "1.2.840.113549.3.7");
+		QUARK (OID_DES_RC5_CBC, "1.2.840.113549.3.9");
+		
+		QUARK (OID_PKCS12_PBE_ARCFOUR_SHA1, "1.2.840.113549.1.12.1.1");
+		QUARK (OID_PKCS12_PBE_RC4_40_SHA1, "1.2.840.113549.1.12.1.2");
+		QUARK (OID_PKCS12_PBE_3DES_SHA1, "1.2.840.113549.1.12.1.3");
+		QUARK (OID_PKCS12_PBE_2DES_SHA1, "1.2.840.113549.1.12.1.4");
+		QUARK (OID_PKCS12_PBE_RC2_128_SHA1, "1.2.840.113549.1.12.1.5");
+		QUARK (OID_PKCS12_PBE_RC2_40_SHA1, "1.2.840.113549.1.12.1.6");
+		
+		#undef QUARK
+		
+		g_once_init_leave (&quarks_inited, 1);
+	}
+}
+
+#endif UNTESTED_CODE
+
+/* -----------------------------------------------------------------------------
+ * KEY PARSING
+ */
+
+#define SEXP_PUBLIC_RSA  \
+	"(public-key"    \
+	"  (rsa"         \
+	"    (n %m)"     \
+	"    (e %m)))"
+
+GckDataResult
+gck_data_der_read_public_key_rsa (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
+{
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_mpi_t n, e;
+	int res;
+
+	n = e = NULL;
+	
+	asn = gck_data_asn1_decode ("PK.RSAPublicKey", data, n_data);
+	if (!asn)
+		goto done;
+		
+	ret = GCK_DATA_FAILURE;
+    
+	if (!gck_data_asn1_read_mpi (asn, "modulus", &n) || 
+	    !gck_data_asn1_read_mpi (asn, "publicExponent", &e))
+		goto done;
+		
+	res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_RSA, n, e);
+	if (res)
+		goto done;
+
+	g_assert (*s_key);
+	ret = GCK_DATA_SUCCESS;
+
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (n);
+	gcry_mpi_release (e);
+	
+	if (ret == GCK_DATA_FAILURE)
+		g_message ("invalid RSA public key");
+		
+	return ret;
+}
+
+#define SEXP_PRIVATE_RSA  \
+	"(private-key"   \
+	"  (rsa"         \
+	"    (n %m)"     \
+	"    (e %m)"     \
+	"    (d %m)"     \
+	"    (p %m)"     \
+	"    (q %m)"     \
+	"    (u %m)))"
+
+GckDataResult
+gck_data_der_read_private_key_rsa (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
+{
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	gcry_mpi_t n, e, d, p, q, u;
+	gcry_mpi_t tmp;
+	guint version;
+	int res;
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+
+	n = e = d = p = q = u = NULL;
+	
+	asn = gck_data_asn1_decode ("PK.RSAPrivateKey", data, n_data);
+	if (!asn)
+		goto done;
+		
+	ret = GCK_DATA_FAILURE;
+	
+	if (!gck_data_asn1_read_uint (asn, "version", &version))
+		goto done;
+	
+	/* We only support simple version */
+	if (version != 0) {
+		ret = GCK_DATA_UNRECOGNIZED;
+		g_message ("unsupported version of RSA key: %u", version);
+		goto done;
+	}
+    
+	if (!gck_data_asn1_read_secure_mpi (asn, "modulus", &n) || 
+	    !gck_data_asn1_read_secure_mpi (asn, "publicExponent", &e) ||
+	    !gck_data_asn1_read_secure_mpi (asn, "privateExponent", &d) ||
+	    !gck_data_asn1_read_secure_mpi (asn, "prime1", &p) ||
+	    !gck_data_asn1_read_secure_mpi (asn, "prime2", &q) || 
+	    !gck_data_asn1_read_secure_mpi (asn, "coefficient", &u))
+		goto done;
+		
+	/* Fix up the incoming key so gcrypt likes it */    	
+	if (gcry_mpi_cmp (p, q) > 0) {
+		/* P shall be smaller then Q!  Swap primes.  iqmp becomes u.  */
+		tmp = p;
+		p = q;
+		q = tmp;
+	} else {
+		/* U needs to be recomputed.  */
+		gcry_mpi_invm (u, p, q);
+	}
+
+	res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_RSA, n, e, d, p, q, u);
+	if (res)
+		goto done;
+
+	g_assert (*s_key);
+	ret = GCK_DATA_SUCCESS;
+
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (n);
+	gcry_mpi_release (e);
+	gcry_mpi_release (d);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (u);
+	
+	if (ret == GCK_DATA_FAILURE)
+		g_message ("invalid RSA key");
+		
+	return ret;
+}
+
+#define SEXP_PUBLIC_DSA  \
+	"(public-key"   \
+	"  (dsa"         \
+	"    (p %m)"     \
+	"    (q %m)"     \
+	"    (g %m)"     \
+	"    (y %m)))"
+
+GckDataResult
+gck_data_der_read_public_key_dsa (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
+{
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_mpi_t p, q, g, y;
+	int res;
+
+	p = q = g = y = NULL;
+	
+	asn = gck_data_asn1_decode ("PK.DSAPublicKey", data, n_data);
+	if (!asn)
+		goto done;
+	
+	ret = GCK_DATA_FAILURE;
+    
+	if (!gck_data_asn1_read_mpi (asn, "p", &p) || 
+	    !gck_data_asn1_read_mpi (asn, "q", &q) ||
+	    !gck_data_asn1_read_mpi (asn, "g", &g) ||
+	    !gck_data_asn1_read_mpi (asn, "Y", &y))
+	    	goto done;
+
+	res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_DSA, p, q, g, y);
+	if (res)
+		goto done;
+		
+	g_assert (*s_key);
+	ret = GCK_DATA_SUCCESS;
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+	
+	if (ret == GCK_DATA_FAILURE) 
+		g_message ("invalid public DSA key");
+		
+	return ret;	
+}
+
+#ifdef UNTESTED_CODE
+
+GckDataResult
+gck_data_der_read_public_key_dsa_parts (const guchar *keydata, gsize n_keydata,
+                                        const guchar *params, gsize n_params,
+                                        gcry_sexp_t *s_key)
+{
+	gcry_mpi_t p, q, g, y;
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	ASN1_TYPE asn_params = ASN1_TYPE_EMPTY;
+	ASN1_TYPE asn_key = ASN1_TYPE_EMPTY;
+	int res;
+
+	p = q = g = y = NULL;
+	
+	asn_params = gck_data_asn1_decode ("PK.DSAParameters", params, n_params);
+	asn_key = gck_data_asn1_decode ("PK.DSAPublicPart", keydata, n_keydata);
+	if (!asn_params || !asn_key)
+		goto done;
+	
+	ret = GCK_DATA_FAILURE;
+    
+	if (!gck_data_asn1_read_mpi (asn_params, "p", &p) || 
+	    !gck_data_asn1_read_mpi (asn_params, "q", &q) ||
+	    !gck_data_asn1_read_mpi (asn_params, "g", &g))
+	    	goto done;
+	    	
+	if (!gck_data_asn1_read_mpi (asn_key, "", &y))
+		goto done;
+
+	res = gcry_sexp_build (s_key, NULL, SEXP_PUBLIC_DSA, p, q, g, y);
+	if (res)
+		goto done;
+		
+	g_assert (*s_key);
+	ret = GCK_DATA_SUCCESS;
+	
+done:
+	if (asn_key)
+		asn1_delete_structure (&asn_key);
+	if (asn_params)
+		asn1_delete_structure (&asn_params);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+	
+	if (ret == GCK_DATA_FAILURE) 
+		g_message ("invalid DSA key");
+		
+	return ret;	
+}
+
+#endif /* UNTESTED_CODE */
+
+#define SEXP_PRIVATE_DSA  \
+	"(private-key"   \
+	"  (dsa"         \
+	"    (p %m)"     \
+	"    (q %m)"     \
+	"    (g %m)"     \
+	"    (y %m)"     \
+	"    (x %m)))"
+
+GckDataResult
+gck_data_der_read_private_key_dsa (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
+{
+	gcry_mpi_t p, q, g, y, x;
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	int res;
+	ASN1_TYPE asn;
+
+	p = q = g = y = x = NULL;
+	
+	asn = gck_data_asn1_decode ("PK.DSAPrivateKey", data, n_data);
+	if (!asn)
+		goto done;
+	
+	ret = GCK_DATA_FAILURE;
+    
+	if (!gck_data_asn1_read_secure_mpi (asn, "p", &p) || 
+	    !gck_data_asn1_read_secure_mpi (asn, "q", &q) ||
+	    !gck_data_asn1_read_secure_mpi (asn, "g", &g) ||
+	    !gck_data_asn1_read_secure_mpi (asn, "Y", &y) ||
+	    !gck_data_asn1_read_secure_mpi (asn, "priv", &x))
+		goto done;
+		
+	res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_DSA, p, q, g, y, x);
+	if (res)
+		goto done;
+		
+	g_assert (*s_key);
+	ret = GCK_DATA_SUCCESS;
+
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+	gcry_mpi_release (x);
+	
+	if (ret == GCK_DATA_FAILURE) 
+		g_message ("invalid DSA key");
+		
+	return ret;
+}
+
+GckDataResult
+gck_data_der_read_private_key_dsa_parts (const guchar *keydata, gsize n_keydata,
+                                         const guchar *params, gsize n_params, 
+                                         gcry_sexp_t *s_key)
+{
+	gcry_mpi_t p, q, g, y, x;
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	int res;
+	ASN1_TYPE asn_params = ASN1_TYPE_EMPTY;
+	ASN1_TYPE asn_key = ASN1_TYPE_EMPTY;
+
+	p = q = g = y = x = NULL;
+	
+	asn_params = gck_data_asn1_decode ("PK.DSAParameters", params, n_params);
+	asn_key = gck_data_asn1_decode ("PK.DSAPrivatePart", keydata, n_keydata);
+	if (!asn_params || !asn_key)
+		goto done;
+	
+	ret = GCK_DATA_FAILURE;
+    
+	if (!gck_data_asn1_read_secure_mpi (asn_params, "p", &p) || 
+	    !gck_data_asn1_read_secure_mpi (asn_params, "q", &q) ||
+	    !gck_data_asn1_read_secure_mpi (asn_params, "g", &g))
+	    	goto done;
+	    	
+	if (!gck_data_asn1_read_secure_mpi (asn_key, "", &x))
+		goto done;
+
+	/* Now we calculate y */
+	y = gcry_mpi_snew (1024);
+  	gcry_mpi_powm (y, g, x, p);
+
+	res = gcry_sexp_build (s_key, NULL, SEXP_PRIVATE_DSA, p, q, g, y, x);
+	if (res)
+		goto done;
+		
+	g_assert (*s_key);
+	ret = GCK_DATA_SUCCESS;
+	
+done:
+	if (asn_key)
+		asn1_delete_structure (&asn_key);
+	if (asn_params)
+		asn1_delete_structure (&asn_params);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+	gcry_mpi_release (x);
+	
+	if (ret == GCK_DATA_FAILURE) 
+		g_message ("invalid DSA key");
+		
+	return ret;	
+}
+
+GckDataResult  
+gck_data_der_read_public_key (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
+{
+	GckDataResult res;
+	
+	res = gck_data_der_read_public_key_rsa (data, n_data, s_key);
+	if (res == GCK_DATA_UNRECOGNIZED)
+		res = gck_data_der_read_public_key_dsa (data, n_data, s_key);
+		
+	return res;
+}
+
+#ifdef UNTESTED_CODE
+
+GckDataResult
+gck_data_der_read_public_key_info (const guchar* data, gsize n_data, gcry_sexp_t* s_key)
+{
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	GQuark oid;
+	ASN1_TYPE asn;
+	gsize n_key, n_params;
+	const guchar *params;
+	guchar *key = NULL;
+	
+	init_quarks ();
+
+	asn = gck_data_asn1_decode ("PKIX1.SubjectPublicKeyInfo", data, n_data);
+	if (!asn)
+		goto done;
+	
+	ret = GCK_DATA_FAILURE;
+    
+	/* Figure out the algorithm */
+	oid = gck_data_asn1_read_oid (asn, "algorithm.algorithm");
+	if (!oid)
+		goto done;
+		
+	/* A bit string so we cannot process in place */
+	key = gck_data_asn1_read_value (asn, "subjectPublicKey", &n_key, NULL);
+	if (!key)
+		goto done;
+	n_key /= 8;
+		
+	/* An RSA key is simple */
+	if (oid == OID_PKIX1_RSA) {
+		ret = gck_data_der_read_public_key_rsa (key, n_key, s_key);
+		
+	/* A DSA key paramaters are stored separately */
+	} else if (oid == OID_PKIX1_DSA) {
+		params = gck_data_asn1_read_element (asn, data, n_data, "algorithm.parameters", &n_params);
+		if (!params)
+			goto done;
+		ret = gck_data_der_read_public_key_dsa_parts (key, n_key, params, n_params, s_key);
+		
+	} else {
+		g_message ("unsupported key algorithm in certificate: %s", g_quark_to_string (oid));
+		goto done;
+	}
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	
+	g_free (key);
+		
+	if (ret == GCK_DATA_FAILURE)
+		g_message ("invalid subject public-key info");
+		
+	return ret;
+}
+
+#endif /* UNTESTED_CODE */
+
+GckDataResult
+gck_data_der_read_private_key (const guchar *data, gsize n_data, gcry_sexp_t *s_key)
+{
+	GckDataResult res;
+	
+	res = gck_data_der_read_private_key_rsa (data, n_data, s_key);
+	if (res == GCK_DATA_UNRECOGNIZED)
+		res = gck_data_der_read_private_key_dsa (data, n_data, s_key);
+		
+	return res;
+}
+
+guchar*
+gck_data_der_write_public_key_rsa (gcry_sexp_t s_key, gsize *len)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_mpi_t n, e;
+	guchar *result = NULL;
+	int res;
+
+	n = e = NULL;
+
+	res = asn1_create_element (gck_data_asn1_get_pk_asn1type (), 
+	                           "PK.RSAPublicKey", &asn);
+	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+
+	if (!gck_crypto_sexp_extract_mpi (s_key, &n, "rsa", "n", NULL) || 
+	    !gck_crypto_sexp_extract_mpi (s_key, &e, "rsa", "e", NULL))
+	    	goto done;
+	
+	if (!gck_data_asn1_write_mpi (asn, "modulus", n) ||
+	    !gck_data_asn1_write_mpi (asn, "publicExponent", e))
+	    	goto done;
+
+	result = gck_data_asn1_encode (asn, "", len, NULL);
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (n);
+	gcry_mpi_release (e);
+	
+	return result;
+}
+
+guchar*
+gck_data_der_write_private_key_rsa (gcry_sexp_t s_key, gsize *n_key)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_mpi_t n, e, d, p, q, u, e1, e2, tmp;
+	guchar *result = NULL;
+	int res;
+
+	n = e = d = p = q = u = e1 = e2 = tmp = NULL;
+
+	res = asn1_create_element (gck_data_asn1_get_pk_asn1type (), 
+	                           "PK.RSAPrivateKey", &asn);
+	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+
+	if (!gck_crypto_sexp_extract_mpi (s_key, &n, "rsa", "n", NULL) || 
+	    !gck_crypto_sexp_extract_mpi (s_key, &e, "rsa", "e", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &d, "rsa", "d", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &p, "rsa", "p", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &q, "rsa", "q", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &u, "rsa", "u", NULL))
+		goto done;
+	
+	if (!gck_data_asn1_write_mpi (asn, "modulus", n) ||
+	    !gck_data_asn1_write_mpi (asn, "publicExponent", e) || 
+	    !gck_data_asn1_write_mpi (asn, "privateExponent", d) ||
+	    !gck_data_asn1_write_mpi (asn, "prime1", p) ||
+	    !gck_data_asn1_write_mpi (asn, "prime2", q) ||
+	    !gck_data_asn1_write_mpi (asn, "coefficient", u))
+		goto done;
+
+	/* Calculate e1 and e2 */
+	tmp = gcry_mpi_snew (1024);
+	gcry_mpi_sub_ui (tmp, p, 1);
+	e1 = gcry_mpi_snew (1024);
+	gcry_mpi_mod (e1, d, tmp);
+	gcry_mpi_sub_ui (tmp, q, 1);
+	e2 = gcry_mpi_snew (1024);
+	gcry_mpi_mod (e2, d, tmp);
+	
+	/* Write out calculated */
+	if (!gck_data_asn1_write_mpi (asn, "exponent1", e1) ||
+	    !gck_data_asn1_write_mpi (asn, "exponent2", e2))
+		goto done;
+
+	/* Write out the version */
+	if (!gck_data_asn1_write_uint (asn, "version", 0))
+		goto done;
+
+	result = gck_data_asn1_encode (asn, "", n_key, NULL);
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (n);
+	gcry_mpi_release (e);
+	gcry_mpi_release (d);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (u);
+	
+	gcry_mpi_release (tmp);
+	gcry_mpi_release (e1);
+	gcry_mpi_release (e2);
+	
+	return result;
+}
+
+guchar*
+gck_data_der_write_public_key_dsa (gcry_sexp_t s_key, gsize *len)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_mpi_t p, q, g, y;
+	guchar *result = NULL;
+	int res;
+
+	p = q = g = y = NULL;
+
+	res = asn1_create_element (gck_data_asn1_get_pk_asn1type (), 
+	                           "PK.DSAPublicKey", &asn);
+	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+
+	if (!gck_crypto_sexp_extract_mpi (s_key, &p, "dsa", "p", NULL) || 
+	    !gck_crypto_sexp_extract_mpi (s_key, &q, "dsa", "q", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &g, "dsa", "g", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &y, "dsa", "y", NULL))
+	    	goto done;
+	
+	if (!gck_data_asn1_write_mpi (asn, "p", p) ||
+	    !gck_data_asn1_write_mpi (asn, "q", q) ||
+	    !gck_data_asn1_write_mpi (asn, "g", g) ||
+	    !gck_data_asn1_write_mpi (asn, "Y", y))
+	    	goto done;
+
+	if (!gck_data_asn1_write_uint (asn, "version", 0))
+		goto done; 
+		
+	result = gck_data_asn1_encode (asn, "", len, NULL);
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+	
+	return result;
+}
+
+guchar*
+gck_data_der_write_private_key_dsa_part (gcry_sexp_t skey, gsize *n_key)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_mpi_t x;
+	guchar *result = NULL;
+	int res;
+
+	x = NULL;
+
+	res = asn1_create_element (gck_data_asn1_get_pk_asn1type (), 
+	                           "PK.DSAPrivatePart", &asn);
+	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+
+	if (!gck_crypto_sexp_extract_mpi (skey, &x, "dsa", "x", NULL))
+	    	goto done;
+	
+	if (!gck_data_asn1_write_mpi (asn, "", x))
+	    	goto done;
+
+	result = gck_data_asn1_encode (asn, "", n_key, NULL);
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (x);
+	
+	return result;		
+}
+
+guchar*
+gck_data_der_write_private_key_dsa_params (gcry_sexp_t skey, gsize *n_params)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_mpi_t p, q, g;
+	guchar *result = NULL;
+	int res;
+
+	p = q = g = NULL;
+
+	res = asn1_create_element (gck_data_asn1_get_pk_asn1type (), 
+	                           "PK.DSAParameters", &asn);
+	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+
+	if (!gck_crypto_sexp_extract_mpi (skey, &p, "dsa", "p", NULL) || 
+	    !gck_crypto_sexp_extract_mpi (skey, &q, "dsa", "q", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (skey, &g, "dsa", "g", NULL))
+	    	goto done;
+	
+	if (!gck_data_asn1_write_mpi (asn, "p", p) ||
+	    !gck_data_asn1_write_mpi (asn, "q", q) ||
+	    !gck_data_asn1_write_mpi (asn, "g", g))
+	    	goto done;
+
+	result = gck_data_asn1_encode (asn, "", n_params, NULL);
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	
+	return result;
+}
+
+guchar*
+gck_data_der_write_private_key_dsa (gcry_sexp_t s_key, gsize *len)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_mpi_t p, q, g, y, x;
+	guchar *result = NULL;
+	int res;
+
+	p = q = g = y = x = NULL;
+
+	res = asn1_create_element (gck_data_asn1_get_pk_asn1type (), 
+	                           "PK.DSAPrivateKey", &asn);
+	g_return_val_if_fail (res == ASN1_SUCCESS, NULL);
+
+	if (!gck_crypto_sexp_extract_mpi (s_key, &p, "dsa", "p", NULL) || 
+	    !gck_crypto_sexp_extract_mpi (s_key, &q, "dsa", "q", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &g, "dsa", "g", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &y, "dsa", "y", NULL) ||
+	    !gck_crypto_sexp_extract_mpi (s_key, &x, "dsa", "x", NULL))
+	    	goto done;
+	
+	if (!gck_data_asn1_write_mpi (asn, "p", p) ||
+	    !gck_data_asn1_write_mpi (asn, "q", q) ||
+	    !gck_data_asn1_write_mpi (asn, "g", g) ||
+	    !gck_data_asn1_write_mpi (asn, "Y", y) ||
+	    !gck_data_asn1_write_mpi (asn, "priv", x))
+	    	goto done;
+
+	if (!gck_data_asn1_write_uint (asn, "version", 0))
+		goto done; 
+		
+	result = gck_data_asn1_encode (asn, "", len, NULL);
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	gcry_mpi_release (p);
+	gcry_mpi_release (q);
+	gcry_mpi_release (g);
+	gcry_mpi_release (y);
+	gcry_mpi_release (x);
+	
+	return result;
+}
+
+guchar*
+gck_data_der_write_public_key (gcry_sexp_t s_key, gsize *len)
+{
+	gboolean is_priv;
+	int algorithm;
+	
+	g_return_val_if_fail (s_key != NULL, NULL);
+	
+	if (!gck_crypto_sexp_parse_key (s_key, &algorithm, &is_priv, NULL))
+		g_return_val_if_reached (NULL);
+	
+	g_return_val_if_fail (!is_priv, NULL);
+		
+	switch (algorithm) {
+	case GCRY_PK_RSA:
+		return gck_data_der_write_public_key_rsa (s_key, len);
+	case GCRY_PK_DSA:
+		return gck_data_der_write_public_key_dsa (s_key, len);
+	default:
+		g_return_val_if_reached (NULL);
+	}
+}
+
+guchar*
+gck_data_der_write_private_key (gcry_sexp_t s_key, gsize *len)
+{
+	gboolean is_priv;
+	int algorithm;
+	
+	g_return_val_if_fail (s_key != NULL, NULL);
+	
+	if (!gck_crypto_sexp_parse_key (s_key, &algorithm, &is_priv, NULL))
+		g_return_val_if_reached (NULL);
+	
+	g_return_val_if_fail (is_priv, NULL);
+		
+	switch (algorithm) {
+	case GCRY_PK_RSA:
+		return gck_data_der_write_private_key_rsa (s_key, len);
+	case GCRY_PK_DSA:
+		return gck_data_der_write_private_key_dsa (s_key, len);
+	default:
+		g_return_val_if_reached (NULL);
+	}
+}
+
+#ifdef UNTESTED_CODE
+
+/* -----------------------------------------------------------------------------
+ * CERTIFICATES
+ */
+ 
+GckDataResult
+gck_data_der_read_certificate (const guchar *data, gsize n_data, ASN1_TYPE *asn1)
+{
+	*asn1 = gck_data_asn1_decode ("PKIX1.Certificate", data, n_data);
+	if (!*asn1)
+		return GCK_DATA_UNRECOGNIZED;
+	
+	return GCK_DATA_SUCCESS;
+}
+
+GckDataResult
+gck_data_der_read_basic_constraints (const guchar *data, gsize n_data, 
+                                     gboolean *is_ca, guint *path_len)
+{
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	ASN1_TYPE asn;
+
+	asn = gck_data_asn1_decode ("PKIX1.BasicConstraints", data, n_data);
+	if (!asn)
+		goto done;
+	
+	ret = GCK_DATA_FAILURE;
+    
+    	if (path_len) {
+    		if (!gck_data_asn1_read_uint (asn, "pathLenConstraint", path_len))
+    			goto done;
+    	}
+    	
+    	if (is_ca) {
+    		if (!gck_data_asn1_read_boolean (asn, "cA", is_ca))
+    			*is_ca = FALSE;
+    	}
+    	
+	ret = GCK_DATA_SUCCESS;
+
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	
+	if (ret == GCK_DATA_FAILURE) 
+		g_message ("invalid basic constraints");
+		
+	return ret;
+}
+
+GckDataResult
+gck_data_der_read_key_usage (const guchar *data, gsize n_data, guint *key_usage)
+{
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	ASN1_TYPE asn;
+	guchar buf[4];
+	int res, len;
+	
+	asn = gck_data_asn1_decode ("PKIX1.KeyUsage", data, n_data);
+	if (!asn)
+		goto done;
+		
+	ret = GCK_DATA_FAILURE;
+
+	memset (buf, 0, sizeof (buf));
+	len = sizeof (buf);
+  	res = asn1_read_value (asn, "", buf, &len);
+  	if (res != ASN1_SUCCESS)
+  		goto done;
+
+	*key_usage = buf[0] | (buf[1] << 8);
+	ret = GCK_DATA_SUCCESS;
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);		
+	return ret;
+}
+
+GckDataResult
+gck_data_der_read_enhanced_usage (const guchar *data, gsize n_data, GQuark **usage_oids)
+{
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	ASN1_TYPE asn;
+	gchar *part;
+	GArray *array;
+	GQuark oid;
+	int i;
+	
+	asn = gck_data_asn1_decode ("PKIX1.ExtKeyUsageSyntax", data, n_data);
+	if (!asn)
+		goto done;
+		
+	ret = GCK_DATA_FAILURE;
+	
+	array = g_array_new (TRUE, TRUE, sizeof (GQuark));
+	for (i = 0; TRUE; ++i) {
+		part = g_strdup_printf ("?%d", i + 1);
+		oid = gck_data_asn1_read_oid (asn, part);
+		g_free (part);
+		
+		if (!oid) 
+			break;
+		
+		g_array_append_val (array, oid);
+	}
+	
+	*usage_oids = (GQuark*)g_array_free (array, FALSE);
+	ret = GCK_DATA_SUCCESS;
+	
+done:
+	if (asn)
+		asn1_delete_structure (&asn);
+	return ret;
+}
+
+guchar*
+gck_data_der_write_certificate (ASN1_TYPE asn1, gsize *n_data)
+{
+	g_return_val_if_fail (asn1, NULL);
+	g_return_val_if_fail (n_data, NULL);
+	
+	return gck_data_asn1_encode (asn1, "", n_data, NULL);
+}
+
+/* -----------------------------------------------------------------------------
+ * CIPHER/KEY DESCRIPTIONS 
+ */
+ 
+GckDataResult
+gck_data_der_read_cipher (GQuark oid_scheme, const gchar *password, 
+                          const guchar *data, gsize n_data, gcry_cipher_hd_t *cih)
+{
+	GckDataResult ret = GCK_DATA_UNRECOGNIZED;
+	
+	g_return_val_if_fail (oid_scheme != 0, GCK_DATA_FAILURE);
+	g_return_val_if_fail (cih != NULL, GCK_DATA_FAILURE);
+	g_return_val_if_fail (data != NULL && n_data != 0, GCK_DATA_FAILURE);
+	
+	init_quarks ();
+	
+	/* PKCS#5 PBE */
+	if (oid_scheme == OID_PBE_MD2_DES_CBC)
+		ret = gck_data_der_read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
+		                                          GCRY_MD_MD2, password, data, n_data, cih);
+
+	else if (oid_scheme == OID_PBE_MD2_RC2_CBC)
+		/* RC2-64 has no implementation in libgcrypt */
+		ret = GCK_DATA_UNRECOGNIZED;
+	else if (oid_scheme == OID_PBE_MD5_DES_CBC)
+		ret = gck_data_der_read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
+		                                          GCRY_MD_MD5, password, data, n_data, cih);
+	else if (oid_scheme == OID_PBE_MD5_RC2_CBC)
+		/* RC2-64 has no implementation in libgcrypt */
+		ret = GCK_DATA_UNRECOGNIZED;
+	else if (oid_scheme == OID_PBE_SHA1_DES_CBC)
+		ret = gck_data_der_read_cipher_pkcs5_pbe (GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC,
+		                                          GCRY_MD_SHA1, password, data, n_data, cih);
+	else if (oid_scheme == OID_PBE_SHA1_RC2_CBC)
+		/* RC2-64 has no implementation in libgcrypt */
+		ret = GCK_DATA_UNRECOGNIZED;
+
+	
+	/* PKCS#5 PBES2 */
+	else if (oid_scheme == OID_PBES2)
+		ret = gck_data_der_read_cipher_pkcs5_pbes2 (password, data, n_data, cih);
+
+		
+	/* PKCS#12 PBE */
+	else if (oid_scheme == OID_PKCS12_PBE_ARCFOUR_SHA1)
+		ret = gck_data_der_read_cipher_pkcs12_pbe (GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM, 
+                                                   password, data, n_data, cih);
+	else if (oid_scheme == OID_PKCS12_PBE_RC4_40_SHA1)
+		/* RC4-40 has no implementation in libgcrypt */;
+
+	else if (oid_scheme == OID_PKCS12_PBE_3DES_SHA1)
+		ret = gck_data_der_read_cipher_pkcs12_pbe (GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC, 
+                                                   password, data, n_data, cih);
+	else if (oid_scheme == OID_PKCS12_PBE_2DES_SHA1) 
+		/* 2DES has no implementation in libgcrypt */;
+		
+	else if (oid_scheme == OID_PKCS12_PBE_RC2_128_SHA1)
+		ret = gck_data_der_read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_128, GCRY_CIPHER_MODE_CBC, 
+                                                   password, data, n_data, cih);
+
+	else if (oid_scheme == OID_PKCS12_PBE_RC2_40_SHA1)
+		ret = gck_data_der_read_cipher_pkcs12_pbe (GCRY_CIPHER_RFC2268_40, GCRY_CIPHER_MODE_CBC, 
+                                                   password, data, n_data, cih);
+
+	if (ret == GCK_DATA_UNRECOGNIZED)
+    		g_message ("unsupported or unrecognized cipher oid: %s", g_quark_to_string (oid_scheme));
+    	return ret;
+}
+
+GckDataResult
+gck_data_der_read_cipher_pkcs5_pbe (int cipher_algo, int cipher_mode, 
+                                    int hash_algo, const gchar *password, const guchar *data, 
+                                    gsize n_data, gcry_cipher_hd_t *cih)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_error_t gcry;
+	GckDataResult ret;
+	const guchar *salt;
+	gsize n_salt;
+	gsize n_block, n_key;
+	guint iterations;
+	guchar *key = NULL;
+	guchar *iv = NULL;
+
+	g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, GCK_DATA_FAILURE);
+	g_return_val_if_fail (cih != NULL, GCK_DATA_FAILURE);
+	g_return_val_if_fail (data != NULL && n_data != 0, GCK_DATA_FAILURE);
+
+	*cih = NULL;	
+	ret = GCK_DATA_UNRECOGNIZED;
+	
+	/* Check if we can use this algorithm */
+	if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0 ||
+	    gcry_md_test_algo (hash_algo) != 0)
+		goto done;
+	
+	asn = gck_data_asn1_decode ("PKIX1.pkcs-5-PBE-params", data, n_data);
+	if (!asn) 
+		goto done;
+		
+	ret = GCK_DATA_FAILURE;
+		
+	salt = gck_data_asn1_read_content (asn, data, n_data, "salt", &n_salt);
+	if (!salt)
+		goto done;
+	if (!gck_data_asn1_read_uint (asn, "iterationCount", &iterations))
+		iterations = 1;
+		
+	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
+	g_return_val_if_fail (n_key > 0, GCK_DATA_FAILURE);
+	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
+		
+	if (!gck_crypto_symkey_generate_pbe (cipher_algo, hash_algo, password, salt,
+	                                     n_salt, iterations, &key, n_block > 1 ? &iv : NULL))
+		goto done;
+		
+	gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0);
+	if (gcry != 0) {
+		g_warning ("couldn't create cipher: %s", gcry_strerror (gcry));
+		goto done;
+	}
+	
+	if (iv) 
+		gcry_cipher_setiv (*cih, iv, n_block);
+	gcry_cipher_setkey (*cih, key, n_key);
+	
+	ret = GCK_DATA_SUCCESS;
+
+done:
+	gkr_secure_free (iv);
+	gkr_secure_free (key);
+	
+	if (asn)
+		asn1_delete_structure (&asn);
+		
+	return ret;
+}
+
+static gboolean
+setup_pkcs5_rc2_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_error_t gcry;
+	const guchar *iv;
+	gsize n_iv;
+	guint version;
+	
+	g_assert (data);
+
+	asn = gck_data_asn1_decode ("PKIX1.pkcs-5-rc2-CBC-params", data, n_data);
+	if (!asn) 
+		return GCK_DATA_UNRECOGNIZED;
+		
+	if (!gck_data_asn1_read_uint (asn, "rc2ParameterVersion", &version))
+		return GCK_DATA_FAILURE;
+	
+	iv = gck_data_asn1_read_content (asn, data, n_data, "iv", &n_iv);
+	asn1_delete_structure (&asn);
+
+	if (!iv)
+		return GCK_DATA_FAILURE;
+		
+	gcry = gcry_cipher_setiv (cih, iv, n_iv);
+			
+	if (gcry != 0) {
+		g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv);
+		return GCK_DATA_FAILURE;
+	}
+	
+	return GCK_DATA_SUCCESS;
+}
+
+static gboolean
+setup_pkcs5_des_params (const guchar *data, guchar n_data, gcry_cipher_hd_t cih)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_error_t gcry;
+	const guchar *iv;
+	gsize n_iv;
+	
+	g_assert (data);
+
+	asn = gck_data_asn1_decode ("PKIX1.pkcs-5-des-EDE3-CBC-params", data, n_data);
+	if (!asn)
+		asn = gck_data_asn1_decode ("PKIX1.pkcs-5-des-CBC-params", data, n_data);
+	if (!asn) 
+		return GCK_DATA_UNRECOGNIZED;
+	
+	iv = gck_data_asn1_read_content (asn, data, n_data, "", &n_iv);
+	asn1_delete_structure (&asn);
+
+	if (!iv)
+		return GCK_DATA_FAILURE;
+		
+	gcry = gcry_cipher_setiv (cih, iv, n_iv);
+			
+	if (gcry != 0) {
+		g_message ("couldn't set %lu byte iv on cipher", (gulong)n_iv);
+		return GCK_DATA_FAILURE;
+	}
+	
+	return GCK_DATA_SUCCESS;
+}
+
+static GckDataResult
+setup_pkcs5_pbkdf2_params (const gchar *password, const guchar *data, 
+                           gsize n_data, int cipher_algo, gcry_cipher_hd_t cih)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GckDataResult ret;
+	gcry_error_t gcry;
+	guchar *key = NULL; 
+	const guchar *salt;
+	gsize n_salt, n_key;
+	guint iterations;
+	
+	g_assert (cipher_algo);
+	g_assert (data);
+	
+	ret = GCK_DATA_UNRECOGNIZED;
+
+	asn = gck_data_asn1_decode ("PKIX1.pkcs-5-PBKDF2-params", data, n_data);
+	if (!asn)
+		goto done;
+		
+	ret = GCK_DATA_FAILURE;
+		
+	if (!gck_data_asn1_read_uint (asn, "iterationCount", &iterations))
+		iterations = 1;
+	salt = gck_data_asn1_read_content (asn, data, n_data, "salt.specified", &n_salt);
+	if (!salt)
+		goto done;
+				
+	if (!gck_crypto_symkey_generate_pbkdf2 (cipher_algo, GCRY_MD_SHA1, password, 
+	                                        salt, n_salt, iterations, &key, NULL))
+		goto done;
+
+	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
+	g_return_val_if_fail (n_key > 0, GCK_DATA_FAILURE);
+	
+	gcry = gcry_cipher_setkey (cih, key, n_key);
+	if (gcry != 0) {
+		g_message ("couldn't set %lu byte key on cipher", (gulong)n_key);
+		goto done;
+	}
+	
+	ret = GCK_DATA_SUCCESS;
+	                                         
+done:
+	gkr_secure_free (key);
+	if (asn)
+		asn1_delete_structure (&asn);
+	return ret;
+}
+
+GckDataResult
+gck_data_der_read_cipher_pkcs5_pbes2 (const gchar *password, const guchar *data, 
+                                      gsize n_data, gcry_cipher_hd_t *cih)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	GckDataResult r, ret;
+	GQuark key_deriv_algo, enc_oid;
+	gcry_error_t gcry;
+	int algo, mode;
+	int beg, end, res;
+
+	g_return_val_if_fail (cih != NULL, GCK_DATA_FAILURE);
+	g_return_val_if_fail (data != NULL && n_data != 0, GCK_DATA_FAILURE);
+	
+	init_quarks ();
+	
+	*cih = NULL;
+	ret = GCK_DATA_UNRECOGNIZED;
+	
+	asn = gck_data_asn1_decode ("PKIX1.pkcs-5-PBES2-params", data, n_data);
+	if (!asn)
+		goto done;
+		
+	res = GCK_DATA_FAILURE;
+	algo = mode = 0;
+	
+	/* Read in all the encryption type */
+	enc_oid = gck_data_asn1_read_oid (asn, "encryptionScheme.algorithm");
+	if (!enc_oid)
+		goto done;	
+	if (enc_oid == OID_DES_EDE3_CBC)
+		algo = GCRY_CIPHER_3DES;
+	else if (enc_oid == OID_DES_CBC)
+		algo = GCRY_CIPHER_DES;
+	else if (enc_oid == OID_DES_RC2_CBC)
+		algo = GCRY_CIPHER_RFC2268_128;
+	else if (enc_oid == OID_DES_RC5_CBC)
+		/* RC5 doesn't exist in libgcrypt */;
+	
+	/* Unsupported? */
+	if (algo == 0 || gcry_cipher_algo_info (algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0) {
+		ret = GCK_DATA_UNRECOGNIZED;
+		goto done;
+	}
+
+	/* Instantiate our cipher */
+	gcry = gcry_cipher_open (cih, algo, GCRY_CIPHER_MODE_CBC, 0);
+	if (gcry != 0) {
+		g_warning ("couldn't create cipher: %s", gcry_cipher_algo_name (algo));
+		goto done;
+	}
+		
+	/* Read out the parameters */
+	if (asn1_der_decoding_startEnd (asn, data, n_data, "encryptionScheme.parameters",
+	                                &beg, &end) != ASN1_SUCCESS)
+		goto done;
+		
+	switch (algo) {
+	case GCRY_CIPHER_3DES:
+	case GCRY_CIPHER_DES:
+		r = setup_pkcs5_des_params (data + beg, end - beg + 1, *cih);
+		break;
+	case GCRY_CIPHER_RFC2268_128:
+		r = setup_pkcs5_rc2_params (data + beg, end - beg + 1, *cih);
+		break;
+	default:
+		/* Should have been caught on the oid check above */
+		g_assert_not_reached ();
+		r = GCK_DATA_UNRECOGNIZED;
+		break;
+	};
+
+	if (r != GCK_DATA_SUCCESS) {
+		ret = r;
+		goto done;
+	}
+
+	/* Read out the key creation paramaters */
+	key_deriv_algo = gck_data_asn1_read_oid (asn, "keyDerivationFunc.algorithm");
+	if (!key_deriv_algo)
+		goto done;
+	if (key_deriv_algo != OID_PBKDF2) {
+		g_message ("unsupported key derivation algorithm: %s", g_quark_to_string (key_deriv_algo));
+		ret = GCK_DATA_UNRECOGNIZED;
+		goto done;
+	}
+
+	if (asn1_der_decoding_startEnd (asn, data, n_data, "keyDerivationFunc.parameters",
+	                                &beg, &end) != ASN1_SUCCESS)
+		goto done;
+	
+	ret = setup_pkcs5_pbkdf2_params (password, data + beg, end - beg + 1, algo, *cih);
+
+done:
+	if (ret != GCK_DATA_SUCCESS && *cih) {
+		gcry_cipher_close (*cih);
+		*cih = NULL;
+	}
+	
+	if (asn)
+		asn1_delete_structure (&asn);
+	
+	return ret;
+}
+
+GckDataResult
+gck_data_der_read_cipher_pkcs12_pbe (int cipher_algo, int cipher_mode, const gchar *password, 
+                                     const guchar *data, gsize n_data, gcry_cipher_hd_t *cih)
+{
+	ASN1_TYPE asn = ASN1_TYPE_EMPTY;
+	gcry_error_t gcry;
+	GckDataResult ret;
+	const guchar *salt;
+	gsize n_salt;
+	gsize n_block, n_key;
+	guint iterations;
+	guchar *key = NULL;
+	guchar *iv = NULL;
+	
+	g_return_val_if_fail (cipher_algo != 0 && cipher_mode != 0, GCK_DATA_FAILURE);
+	g_return_val_if_fail (cih != NULL, GCK_DATA_FAILURE);
+	g_return_val_if_fail (data != NULL && n_data != 0, GCK_DATA_FAILURE);
+	
+	*cih = NULL;
+	ret = GCK_DATA_UNRECOGNIZED;
+	
+	/* Check if we can use this algorithm */
+	if (gcry_cipher_algo_info (cipher_algo, GCRYCTL_TEST_ALGO, NULL, 0) != 0)
+		goto done;
+	
+	asn = gck_data_asn1_decode ("PKIX1.pkcs-12-PbeParams", data, n_data);
+	if (!asn)
+		goto done;
+
+	ret = GCK_DATA_FAILURE;
+
+	salt = gck_data_asn1_read_content (asn, data, n_data, "salt", &n_salt);
+	if (!salt)
+		goto done;
+	if (!gck_data_asn1_read_uint (asn, "iterations", &iterations))
+		goto done;
+	
+	n_block = gcry_cipher_get_algo_blklen (cipher_algo);
+	n_key = gcry_cipher_get_algo_keylen (cipher_algo);
+	
+	/* Generate IV and key using salt read above */
+	if (!gck_crypto_symkey_generate_pkcs12 (cipher_algo, GCRY_MD_SHA1, password,
+	                                        salt, n_salt, iterations, &key, 
+	                                        n_block > 1 ? &iv : NULL))
+		goto done;
+		
+	gcry = gcry_cipher_open (cih, cipher_algo, cipher_mode, 0);
+	if (gcry != 0) {
+		g_warning ("couldn't create encryption cipher: %s", gcry_strerror (gcry));
+		goto done;
+	}
+	
+	if (iv) 
+		gcry_cipher_setiv (*cih, iv, n_block);
+	gcry_cipher_setkey (*cih, key, n_key);
+	
+	ret = GCK_DATA_SUCCESS;
+	
+done:
+	if (ret != GCK_DATA_SUCCESS && *cih) {
+		gcry_cipher_close (*cih);
+		*cih = NULL;
+	}
+	
+	gkr_secure_free (iv);
+	gkr_secure_free (key);
+	
+	if (asn)
+		asn1_delete_structure (&asn);
+	
+	return ret;
+}
+
+#endif /* UNTESTED_CODE */

Added: trunk/pkcs11/gck/gck-data-der.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-der.h	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,126 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-data-der.h - parsing and serializing of common crypto DER structures 
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#ifndef GKRPKIXDER_H_
+#define GKRPKIXDER_H_
+
+#include <glib.h>
+#include <gcrypt.h>
+#include <libtasn1.h>
+
+#include "gck-data-types.h"
+
+/* -----------------------------------------------------------------------------
+ * PRIVATE KEYS 
+ */
+ 
+GckDataResult      gck_data_der_read_private_key_rsa         (const guchar *data, gsize n_data, 
+                                                              gcry_sexp_t *s_key);
+
+GckDataResult      gck_data_der_read_private_key_dsa         (const guchar *data, gsize n_data, 
+                                                              gcry_sexp_t *s_key);
+
+GckDataResult      gck_data_der_read_private_key_dsa_parts   (const guchar *keydata, gsize n_keydata,
+                                                              const guchar *params, gsize n_params, 
+                                                              gcry_sexp_t *s_key);
+
+GckDataResult      gck_data_der_read_private_key             (const guchar *data, gsize n_data, 
+                                                              gcry_sexp_t *s_key);
+
+guchar*            gck_data_der_write_private_key_rsa        (gcry_sexp_t s_key, gsize *n_data);
+
+guchar*            gck_data_der_write_private_key_dsa        (gcry_sexp_t s_key, gsize *len);
+
+guchar*            gck_data_der_write_private_key_dsa_part   (gcry_sexp_t skey, gsize *n_key);
+
+guchar*            gck_data_der_write_private_key_dsa_params (gcry_sexp_t skey, gsize *n_params);
+
+guchar*            gck_data_der_write_private_key            (gcry_sexp_t s_key, gsize *n_data);
+
+
+/* -----------------------------------------------------------------------------
+ * PUBLIC KEYS
+ */
+
+GckDataResult      gck_data_der_read_public_key_rsa        (const guchar *data, gsize n_data, 
+                                                            gcry_sexp_t *s_key);
+
+GckDataResult      gck_data_der_read_public_key_dsa        (const guchar *data, gsize n_data, 
+                                                            gcry_sexp_t *s_key);
+
+GckDataResult      gck_data_der_read_public_key_dsa_parts  (const guchar *keydata, gsize n_keydata,
+                                                            const guchar *params, gsize n_params,
+                                                            gcry_sexp_t *s_key);
+                                                         
+GckDataResult      gck_data_der_read_public_key            (const guchar *data, gsize n_data, 
+                                                            gcry_sexp_t *s_key);
+
+GckDataResult      gck_data_der_read_public_key_info       (const guchar *data, gsize n_data, 
+                                                            gcry_sexp_t *s_key);
+
+guchar*            gck_data_der_write_public_key_rsa       (gcry_sexp_t s_key, gsize *len);
+
+guchar*            gck_data_der_write_public_key_dsa       (gcry_sexp_t s_key, gsize *len);
+
+guchar*            gck_data_der_write_public_key           (gcry_sexp_t s_key, gsize *len);
+
+
+/* -----------------------------------------------------------------------------
+ * CERTIFICATES
+ */
+
+GckDataResult      gck_data_der_read_certificate           (const guchar *data, gsize n_data, 
+                                                            ASN1_TYPE *asn1);
+                                                         
+GckDataResult      gck_data_der_read_basic_constraints     (const guchar *data, gsize n_data, 
+                                                            gboolean *is_ca, guint *path_len);
+
+GckDataResult      gck_data_der_read_key_usage             (const guchar *data, gsize n_data, 
+                                                            guint *key_usage);
+
+GckDataResult      gck_data_der_read_enhanced_usage        (const guchar *data, gsize n_data, 
+                                                            GQuark **oids);
+
+guchar*            gck_data_der_write_certificate          (ASN1_TYPE asn1, gsize *n_data);
+
+/* -----------------------------------------------------------------------------
+ * CIPHERS
+ */
+ 
+GckDataResult      gck_data_der_read_cipher                 (GQuark oid_scheme, const gchar *password, 
+                                                             const guchar *data, gsize n_data, 
+                                                             gcry_cipher_hd_t *cih);
+
+GckDataResult      gck_data_der_read_cipher_pkcs5_pbe       (int cipher_algo, int cipher_mode, 
+                                                             int hash_algo, const gchar *password, 
+                                                             const guchar *data, gsize n_data, 
+                                                             gcry_cipher_hd_t *cih);
+
+GckDataResult      gck_data_der_read_cipher_pkcs5_pbes2     (const gchar *password, const guchar *data, 
+                                                             gsize n_data, gcry_cipher_hd_t *cih);
+
+GckDataResult      gck_data_der_read_cipher_pkcs12_pbe      (int cipher_algo, int cipher_mode, 
+                                                             const gchar *password, const guchar *data, 
+                                                             gsize n_data, gcry_cipher_hd_t *cih);
+
+#endif /*GKRPKIXDER_H_*/

Added: trunk/pkcs11/gck/gck-data-openssl.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-openssl.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,451 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-data-openssl.c - OpenSSL compatibility functionality
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-crypto.h"
+#include "gck-data-openssl.h"
+
+#include "common/gkr-secure-memory.h"
+
+#include <gcrypt.h>
+#include <libtasn1.h>
+
+#include <glib.h>
+
+/* ----------------------------------------------------------------------------
+ * DEFINITIONS
+ */
+
+const static struct {
+	const gchar *desc;
+	int algo;
+	int mode;
+} openssl_algos[] = {
+	{ "DES-ECB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB },
+	{ "DES-CFB64", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB },
+	{ "DES-CFB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CFB },
+	/* DES-CFB1 */
+	/* DES-CFB8 */
+	/* DESX-CBC */
+	/* DES-EDE */
+	/* DES-EDE-CBC */
+	/* DES-EDE-ECB */
+	/* DES-EDE-CFB64 DES-EDE-CFB */
+	/* DES-EDE-CFB1 */
+	/* DES-EDE-CFB8 */
+	/* DES-EDE-OFB */
+	/* DES-EDE3 */ 
+	{ "DES-EDE3-ECB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_ECB }, 
+	{ "DES-EDE3-CFB64", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
+	{ "DES-EDE3-CFB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CFB },
+	/* DES-EDE3-CFB1 */
+	/* DES-EDE3-CFB8 */
+	{ "DES-OFB", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_OFB },
+	{ "DES-EDE3-OFB", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_OFB },
+	{ "DES-CBC", GCRY_CIPHER_DES, GCRY_CIPHER_MODE_CBC },
+	{ "DES-EDE3-CBC", GCRY_CIPHER_3DES, GCRY_CIPHER_MODE_CBC },
+	/* RC2-ECB */
+	/* RC2-CBC */
+	/* RC2-40-CBC */
+	/* RC2-64-CBC */
+	/* RC2-CFB64    RC2-CFB */
+	/* RC2-OFB */
+	{ "RC4", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM },
+	{ "RC4-40", GCRY_CIPHER_ARCFOUR, GCRY_CIPHER_MODE_STREAM },
+	{ "IDEA-ECB", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_ECB },
+	{ "IDEA-CFB64", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_CFB },
+	{ "IDEA-OFB", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_OFB },
+	{ "IDEA-CBC", GCRY_CIPHER_IDEA, GCRY_CIPHER_MODE_CBC },
+	{ "BF-ECB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_ECB },
+	{ "BF-CBC", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CBC },
+	{ "BF-CFB64", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB },
+	{ "BF-CFB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_CFB },
+	{ "BF-OFB", GCRY_CIPHER_BLOWFISH, GCRY_CIPHER_MODE_OFB },
+	{ "CAST5-ECB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_ECB },
+	{ "CAST5-CBC", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CBC },
+	{ "CAST5-CFB64", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
+	{ "CAST5-CFB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_CFB },
+	{ "CAST5-OFB", GCRY_CIPHER_CAST5, GCRY_CIPHER_MODE_OFB },
+	/* RC5-32-12-16-CBC */ 
+	/* RC5-32-12-16-ECB */
+	/* RC5-32-12-16-CFB64  RC5-32-12-16-CFB */
+	/* RC5-32-12-16-OFB */
+	{ "AES-128-ECB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_ECB },
+	{ "AES-128-CBC", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CBC },
+	/* AES-128-CFB1 */
+	/* AES-128-CFB8	*/
+	{ "AES-128-CFB128", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB },
+	{ "AES-128-CFB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CFB },
+	{ "AES-128-OFB", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_OFB },
+	{ "AES-128-CTR", GCRY_CIPHER_AES128, GCRY_CIPHER_MODE_CTR },
+	{ "AES-192-ECB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_ECB },
+	{ "AES-192-CBC", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CBC },
+	/* AES-192-CFB1 */
+	/* AES-192-CFB8 */
+	{ "AES-192-CFB128", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB },
+	{ "AES-192-CFB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CFB },
+	{ "AES-192-OFB", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_OFB },
+	{ "AES-192-CTR", GCRY_CIPHER_AES192, GCRY_CIPHER_MODE_CTR },
+	{ "AES-256-ECB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_ECB },
+	{ "AES-256-CBC", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC },
+	/* AES-256-CFB1 */
+	/* AES-256-CFB8 */
+	{ "AES-256-CFB128", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB },
+	{ "AES-256-CFB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CFB },
+	{ "AES-256-OFB", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_OFB },
+	{ "AES-256-CTR", GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CTR },
+	/* CAMELLIA-128-ECB */
+	/* CAMELLIA-128-CBC */
+	/* CAMELLIA-128-CFB1 */
+	/* CAMELLIA-128-CFB8 */
+	/* CAMELLIA-128-CFB128   CAMELLIA-128-CFB */
+	/* CAMELLIA-128-OFB */
+	/* CAMELLIA-192-ECB */
+	/* CAMELLIA-192-CBC */
+	/* CAMELLIA-192-CFB1 */
+	/* CAMELLIA-192-CFB8 */
+	/* CAMELLIA-192-CFB128   CAMELLIA-192-CFB */
+	/* CAMELLIA-192_OFB */
+	/* CAMELLIA-256-ECB */
+	/* CAMELLIA-256-CBC */
+	/* CAMELLIA-256-CFB1 */
+	/* CAMELLIA-256-CFB8 */
+	/* CAMELLIA-256-CFB128   CAMELLIA-256-CFB */
+	/* CAMELLIA-256-OFB */
+};
+
+static const char HEXC[] = "0123456789ABCDEF";
+
+/* ------------------------------------------------------------------------- */
+
+static gboolean
+hex_decode (const gchar *data, gsize n_data, 
+            guchar *decoded, gsize *n_decoded)
+{
+	gushort j;
+	gint state = 0;
+	const gchar* pos;
+    
+	g_assert (data);
+	g_assert (decoded);
+	g_assert (n_decoded);
+    
+	g_return_val_if_fail (*n_decoded >= n_data / 2, FALSE);
+	*n_decoded = 0;
+
+	while (n_data > 0) 
+    	{
+    		if (!g_ascii_isspace (*data)) {
+    			
+	        	/* Find the position */
+			pos = strchr (HEXC, g_ascii_toupper (*data));
+			if (pos == 0)
+				break;
+
+			j = pos - HEXC;
+			if(!state) {
+				*decoded = (j & 0xf) << 4;
+				state = 1;
+			} else {      
+				*decoded |= (j & 0xf);
+				(*n_decoded)++;
+				decoded++;
+				state = 0;
+			}
+    		}
+      
+      		++data;
+      		--n_data;
+	}
+  
+  	g_return_val_if_fail (state == 0, FALSE);
+  	
+  	return TRUE;
+}
+
+static gboolean
+hex_encode (const guchar *data, gsize n_data, 
+            gchar *encoded, gsize *n_encoded)
+{
+	guchar j;
+	
+	g_return_val_if_fail (*n_encoded >= n_data * 2 + 1, FALSE);
+	
+	while(n_data > 0) {
+		j = *(data) >> 4 & 0xf;
+		*(encoded++) = HEXC[j];
+    
+		j = *(data++) & 0xf;
+		*(encoded++) = HEXC[j];
+    
+		n_data--;
+	}
+
+	/* Null terminate */
+	*encoded = 0;
+	return TRUE;
+}
+
+int
+gck_data_openssl_parse_algo (const char *name, int *mode)
+{
+	static GQuark openssl_quarks[G_N_ELEMENTS(openssl_algos)] = { 0, };
+	static gsize openssl_quarks_inited = 0;
+	GQuark q;
+	int i;
+
+	if (g_once_init_enter (&openssl_quarks_inited)) {
+		for (i = 0; i < G_N_ELEMENTS(openssl_algos); ++i)
+			openssl_quarks[i] = g_quark_from_static_string (openssl_algos[i].desc);
+		g_once_init_leave (&openssl_quarks_inited, 1);
+	}
+	
+	q = g_quark_try_string (name);
+	if (q) {
+		for (i = 0; i < G_N_ELEMENTS(openssl_algos); ++i) {
+			if (q == openssl_quarks[i]) {
+				*mode = openssl_algos[i].mode;
+				return openssl_algos[i].algo;
+			}
+		}
+	}
+	
+	return 0;
+}
+
+static gboolean
+parse_dekinfo (const gchar *dek, int *algo, int *mode, guchar **iv)
+{
+	gboolean success = FALSE;
+	gchar **parts = NULL;
+	gcry_error_t gcry;
+	gsize ivlen, len;
+	
+	parts = g_strsplit (dek, ",", 2);
+	if (!parts || !parts[0] || !parts[1]) 
+		goto done;
+		
+	/* Parse the algorithm name */
+	*algo = gck_data_openssl_parse_algo (parts[0], mode);
+	if (!*algo)
+		goto done;
+	
+	/* Make sure this is usable */
+	gcry = gcry_cipher_test_algo (*algo);
+	if (gcry)
+		goto done;
+
+	/* Parse the IV */
+	ivlen = len = gcry_cipher_get_algo_blklen (*algo);
+	*iv = g_malloc (ivlen);
+	
+	if (!hex_decode (parts[1], strlen (parts[1]), *iv, &len)) {
+		g_free (*iv);
+		goto done;
+	}
+	
+	if (ivlen != len) {
+		g_free (*iv);
+		goto done;
+	}
+		
+	success = TRUE;
+
+done:
+	g_strfreev (parts);
+	return success;
+}
+
+GckDataResult
+gck_data_openssl_decrypt_block (const gchar *dekinfo, const gchar *password, 
+                                const guchar *data, gsize n_data, 
+                                guchar **decrypted, gsize *n_decrypted)
+{
+	gcry_cipher_hd_t ch;
+	guchar *key = NULL;
+	guchar *iv = NULL;
+	int gcry, ivlen;
+	int algo = 0;
+	int mode = 0;
+	
+	if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
+		return GCK_DATA_UNRECOGNIZED;
+		
+	ivlen = gcry_cipher_get_algo_blklen (algo);
+
+	/* We assume the iv is at least as long as at 8 byte salt */
+	g_return_val_if_fail (ivlen >= 8, FALSE);
+	
+	/* IV is already set from the DEK info */
+	if (!gck_crypto_symkey_generate_simple (algo, GCRY_MD_MD5, password, 
+	                                        iv, 8, 1, &key, NULL)) {
+		g_free (iv);
+		return GCK_DATA_FAILURE;
+	}
+	
+	/* TODO: Use secure memory */
+	gcry = gcry_cipher_open (&ch, algo, mode, 0);
+	g_return_val_if_fail (!gcry, GCK_DATA_FAILURE);
+		
+	gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
+	g_return_val_if_fail (!gcry, GCK_DATA_UNRECOGNIZED);
+	gkr_secure_free (key);
+
+	/* 16 = 128 bits */
+	gcry = gcry_cipher_setiv (ch, iv, ivlen);
+	g_return_val_if_fail (!gcry, GCK_DATA_UNRECOGNIZED);
+	g_free (iv);
+	
+	/* Allocate output area */
+	*n_decrypted = n_data;
+	*decrypted = gkr_secure_alloc (n_data);
+
+	gcry = gcry_cipher_decrypt (ch, *decrypted, *n_decrypted, (void*)data, n_data);
+	if (gcry) {
+		gkr_secure_free (*decrypted);
+		g_return_val_if_reached (GCK_DATA_FAILURE);
+	}
+	
+	gcry_cipher_close (ch);
+	
+	return GCK_DATA_SUCCESS;
+}
+
+gboolean
+gck_data_openssl_encrypt_block (const gchar *dekinfo, const gchar *password, 
+                                const guchar *data, gsize n_data,
+                                guchar **encrypted, gsize *n_encrypted)
+{
+	gsize n_overflow, n_batch, n_padding;
+	gcry_cipher_hd_t ch;
+	guchar *key = NULL;
+	guchar *iv = NULL;
+	guchar *padded = NULL;
+	int gcry, ivlen;
+	int algo = 0;
+	int mode = 0;
+	
+	if (!parse_dekinfo (dekinfo, &algo, &mode, &iv))
+		g_return_val_if_reached (FALSE);
+		
+	ivlen = gcry_cipher_get_algo_blklen (algo);
+
+	/* We assume the iv is at least as long as at 8 byte salt */
+	g_return_val_if_fail (ivlen >= 8, FALSE);
+	
+	/* IV is already set from the DEK info */
+	if (!gck_crypto_symkey_generate_simple (algo, GCRY_MD_MD5, password, 
+	                                        iv, 8, 1, &key, NULL))
+		g_return_val_if_reached (FALSE);
+	
+	gcry = gcry_cipher_open (&ch, algo, mode, 0);
+	g_return_val_if_fail (!gcry, FALSE);
+		
+	gcry = gcry_cipher_setkey (ch, key, gcry_cipher_get_algo_keylen (algo));
+	g_return_val_if_fail (!gcry, FALSE);
+	gkr_secure_free (key);
+
+	/* 16 = 128 bits */
+	gcry = gcry_cipher_setiv (ch, iv, ivlen);
+	g_return_val_if_fail (!gcry, FALSE);
+	g_free (iv);
+	
+	/* Allocate output area */
+	n_overflow = (n_data % ivlen);
+	n_padding = n_overflow ? (ivlen - n_overflow) : 0;
+	n_batch = n_data - n_overflow;
+	*n_encrypted = n_data + n_padding;
+	*encrypted = g_malloc0 (*n_encrypted);
+	
+	g_assert (*n_encrypted % ivlen == 0);
+	g_assert (*n_encrypted >= n_data);
+	g_assert (*n_encrypted == n_batch + n_overflow + n_padding);
+
+	/* Encrypt everything but the last bit */
+	gcry = gcry_cipher_encrypt (ch, *encrypted, n_batch, (void*)data, n_batch);
+	if (gcry) {
+		g_free (*encrypted);
+		g_return_val_if_reached (FALSE);
+	}
+	
+	/* Encrypt the padded block */
+	if (n_overflow) {
+		padded = gkr_secure_alloc (ivlen);
+		memset (padded, 0, ivlen);
+		memcpy (padded, data + n_batch, n_overflow);
+		gcry = gcry_cipher_encrypt (ch, *encrypted + n_batch, ivlen, padded, ivlen);
+		gkr_secure_free (padded);
+		if (gcry) {
+			g_free (*encrypted);
+			g_return_val_if_reached (FALSE);
+		}
+	}
+
+	gcry_cipher_close (ch);
+	return TRUE;
+}
+
+const gchar*
+gck_data_openssl_get_dekinfo (GHashTable *headers)
+{
+	const gchar *val;
+	if (!headers)
+		return NULL;
+	val = g_hash_table_lookup (headers, "Proc-Type");
+	if (!val || strcmp (val, "4,ENCRYPTED") != 0)
+		return NULL;
+	val = g_hash_table_lookup (headers, "DEK-Info");
+	g_return_val_if_fail (val, NULL);
+	return val;
+}
+
+const gchar*
+gck_data_openssl_prep_dekinfo (GHashTable *headers)
+{
+	gsize ivlen, len, n_encoded;
+	gchar buf[256];
+	guchar *iv;
+	const gchar *dekinfo;
+	
+	strcpy (buf, "DES-EDE3-CBC,");
+
+	/* Create the iv */
+	ivlen = gcry_cipher_get_algo_blklen (GCRY_CIPHER_3DES);
+	g_return_val_if_fail (ivlen, NULL);
+	iv = g_malloc (ivlen);
+	gcry_create_nonce (iv, ivlen);
+	
+	/* And encode it into the string */
+	len = strlen (buf);
+	g_return_val_if_fail (sizeof (buf) - len > ivlen * 2, NULL);
+	n_encoded = (ivlen * 2) + 1;
+	if (!hex_encode (iv, ivlen, buf + len, &n_encoded))
+		g_return_val_if_reached (NULL);
+
+	dekinfo = g_strdup (buf);
+	g_hash_table_insert (headers, g_strdup ("DEK-Info"), (void*)dekinfo);
+	g_hash_table_insert (headers, g_strdup ("Proc-Type"), g_strdup ("4,ENCRYPTED"));
+	
+	return dekinfo;
+}

Added: trunk/pkcs11/gck/gck-data-openssl.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-openssl.h	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,43 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-data-openssl.h - OpenSSL compatibility functionality
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#ifndef GCKDATAOPENSSL_H_
+#define GCKDATAOPENSSL_H_
+
+#include "gck-data-types.h"
+
+int              gck_data_openssl_parse_algo        (const gchar *name, int *mode);
+
+gboolean         gck_data_openssl_encrypt_block     (const gchar *dekinfo, const gchar *password, 
+                                                     const guchar *data, gsize n_data,
+                                                     guchar **encrypted, gsize *n_encrypted);
+
+GckDataResult    gck_data_openssl_decrypt_block     (const gchar *dekinfo, const gchar *password, 
+                                                     const guchar *data, gsize n_data, 
+                                                     guchar **decrypted, gsize *n_decrypted);
+
+const gchar*     gck_data_openssl_get_dekinfo       (GHashTable *headers);
+
+const gchar*     gck_data_openssl_prep_dekinfo      (GHashTable *headers);
+
+#endif /* GCKDATAOPENSSL_H_ */

Added: trunk/pkcs11/gck/gck-data-pem.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-pem.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,345 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pkix-pem.c - PEM base64 encoding helper routines
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-data-pem.h"
+
+#include "common/gkr-secure-memory.h"
+
+#include <glib.h>
+
+#include <ctype.h>
+#include <string.h>
+
+/* 
+ * PEM looks like:
+ * 
+ * 	-----BEGIN RSA PRIVATE KEY-----
+ * 	Proc-Type: 4,ENCRYPTED
+ * 	DEK-Info: DES-EDE3-CBC,704CFFD62FBA03E9
+ * 
+ * 	4AV/g0BiTeb07hzo4/Ct47HGhHEshMhBPGJ843QzuAinpZBbg3OxwPsQsLgoPhJL
+ * 	Bg6Oxyz9M4UN1Xlx6Lyo2lRT908mBP6dl/OItLsVArqAzM+e29KHQVNjV1h7xN9F
+ *	u84tOgZftKun+ZkQUOoRvMLLu4yV4CUraks9tgyXquugGba/tbeyj2MYsC8wwSJX
+ * 	....
+ * 	-----END RSA PRIVATE KEY-----
+ */
+ 
+#define PEM_SUFF          "-----"
+#define PEM_SUFF_L        5
+#define PEM_PREF_BEGIN    "-----BEGIN "
+#define PEM_PREF_BEGIN_L  11
+#define PEM_PREF_END      "-----END "
+#define PEM_PREF_END_L    9
+
+static void
+parse_header_lines (const gchar *hbeg, const gchar *hend, GHashTable **result)
+{
+	gchar **lines, **l;
+	gchar *line, *name, *value;
+	gchar *copy;
+	
+	copy = g_strndup (hbeg, hend - hbeg);
+	lines = g_strsplit (copy, "\n", 0);
+	g_free (copy);
+	
+	for (l = lines; l && *l; ++l) {
+		line = *l;
+		g_strstrip (line);
+		
+        	/* Look for the break between name: value */
+        	value = strchr (line, ':');
+        	if (value == NULL)
+        		continue;
+        		
+        	*value = 0;
+        	value = g_strdup (value + 1);
+        	g_strstrip (value);
+        	
+        	name = g_strdup (line);
+        	g_strstrip (name);
+        	
+        	if (!*result)
+        		*result = gck_data_pem_headers_new ();
+        	g_hash_table_replace (*result, name, value);
+	}
+
+	g_strfreev (lines);
+} 
+
+static const gchar*
+pem_find_begin (const gchar *data, gsize n_data, GQuark *type)
+{
+	const gchar *pref, *suff;
+	gchar *stype;
+	
+	/* Look for a prefix */
+	pref = g_strstr_len ((gchar*)data, n_data, PEM_PREF_BEGIN);
+	if (!pref)
+		return NULL;
+		
+	n_data -= (pref - data) + PEM_PREF_BEGIN_L;
+	data = pref + PEM_PREF_BEGIN_L;
+		
+	/* Look for the end of that begin */
+	suff = g_strstr_len ((gchar*)data, n_data, PEM_SUFF);
+	if (!suff)
+		return NULL;
+		
+	/* Make sure on the same line */
+	if (memchr (pref, '\n', suff - pref))
+		return NULL;
+		
+	if (type) {
+		*type = 0;
+		pref += PEM_PREF_BEGIN_L;
+		g_assert (suff > pref);
+		stype = g_alloca (suff - pref + 1);
+		memcpy (stype, pref, suff - pref);
+		stype[suff - pref] = 0;
+		*type = g_quark_from_string (stype);
+	} 
+	
+	/* The byte after this ---BEGIN--- */
+	return suff + PEM_SUFF_L;
+}
+
+static const gchar*
+pem_find_end (const gchar *data, gsize n_data, GQuark type)
+{
+	const gchar *stype;
+	const gchar *pref;
+	gsize n_type;
+	
+	/* Look for a prefix */
+	pref = g_strstr_len (data, n_data, PEM_PREF_END);
+	if (!pref)
+		return NULL;
+		
+	n_data -= (pref - data) + PEM_PREF_END_L;
+	data = pref + PEM_PREF_END_L;
+	
+	/* Next comes the type string */
+	stype = g_quark_to_string (type);
+	n_type = strlen (stype);
+	if (strncmp ((gchar*)data, stype, n_type) != 0)
+		return NULL; 
+		
+	n_data -= n_type;
+	data += n_type;
+	
+	/* Next comes the suffix */
+	if (strncmp ((gchar*)data, PEM_SUFF, PEM_SUFF_L) != 0)
+		return NULL;
+		
+	/* The beginning of this ---END--- */
+	return pref;
+}
+
+static gboolean
+pem_parse_block (const gchar *data, gsize n_data, guchar **decoded, gsize *n_decoded,
+                 GHashTable **headers)
+{
+	const gchar *x, *hbeg, *hend;
+	const gchar *p, *end;
+	gint state = 0;
+	guint save = 0;
+	
+	g_assert (data);
+	g_assert (n_data);
+	
+	g_assert (decoded);
+	g_assert (n_decoded);
+	
+	p = data;
+	end = p + n_data;
+	
+	hbeg = hend = NULL;
+	
+	/* Try and find a pair of blank lines with only white space between */
+	while (hend == NULL) {
+		x = memchr (p, '\n', end - p);
+		if (!x)
+			break;
+		++x;
+		while (isspace (*x)) {
+			/* Found a second line, with only spaces between */
+			if (*x == '\n') {
+				hbeg = data;
+				hend = x;
+				break;
+			/* Found a space between two lines */
+			} else {
+				++x;
+			}
+		}
+		
+		/* Try next line */
+		p = x;
+	}
+
+	/* Headers found? */	
+	if (hbeg && hend) {
+		data = hend;
+		n_data = end - data;
+	}
+	
+	*n_decoded = (n_data * 3) / 4 + 1;
+	if (gkr_secure_check (data))
+		*decoded = gkr_secure_alloc (*n_decoded);
+	else
+		*decoded = g_malloc (*n_decoded);
+	g_return_val_if_fail (*decoded, FALSE);
+	
+	*n_decoded = g_base64_decode_step (data, n_data, *decoded, &state, &save);
+	if (!*n_decoded) {
+		gkr_secure_free (*decoded);
+		return FALSE;
+	}
+	
+	if (headers && hbeg && hend) 
+		parse_header_lines (hbeg, hend, headers);
+	
+	return TRUE;
+}
+
+GHashTable*
+gck_data_pem_headers_new (void)
+{
+	return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+}
+
+guint
+gck_data_pem_parse  (const guchar *data, gsize n_data, 
+                     GckDataPemCallback callback, gpointer user_data)
+{
+	const gchar *beg, *end;
+	guint nfound = 0;
+	guchar *decoded = NULL;
+	gsize n_decoded = 0;
+	GHashTable *headers = NULL;
+	GQuark type;
+	
+	g_return_val_if_fail (data, 0);
+	g_return_val_if_fail (n_data, 0);
+	g_return_val_if_fail (callback, 0);
+
+	while (n_data > 0) {
+		
+		/* This returns the first character after the PEM BEGIN header */
+		beg = pem_find_begin ((const gchar*)data, n_data, &type);
+		if (!beg)
+			break;
+			
+		g_assert (type);
+		
+		/* This returns the character position before the PEM END header */
+		end = pem_find_end ((const gchar*)beg, n_data - ((const guchar*)beg - data), type);
+		if (!end)
+			break;
+
+		if (beg != end) {
+			if (pem_parse_block (beg, end - beg, &decoded, &n_decoded, &headers)) {
+				(callback) (type, decoded, n_decoded, headers, user_data);
+				++nfound;
+				gkr_secure_free (decoded);
+				if (headers)
+					g_hash_table_remove_all (headers);
+			}
+		}
+                     
+		/* Try for another block */
+		end += PEM_SUFF_L;
+		n_data -= (const guchar*)end - data; 
+		data = (const guchar*)end;
+	}
+	
+	if (headers)
+		g_hash_table_destroy (headers);
+
+	return nfound;
+}
+
+#ifdef UNTESTED_CODE
+
+static void 
+append_each_header (gpointer key, gpointer value, gpointer user_data)
+{
+	GString *string = (GString*)user_data;
+	
+	g_string_append (string, (gchar*)key);
+	g_string_append (string, ": ");
+	g_string_append (string, (gchar*)value);
+	g_string_append_c (string, '\n');
+}
+
+guchar*
+gck_data_pem_write (const guchar *data, gsize n_data, GQuark type, 
+                    GHashTable *headers, gsize *n_result)
+{
+	GString *string;
+	gint state, save;
+	gsize length, n_prefix;
+	
+	g_return_val_if_fail (data || !n_data, NULL);
+	g_return_val_if_fail (type, NULL);
+	g_return_val_if_fail (n_result, NULL);
+
+	string = g_string_sized_new (4096);
+	
+	/* The prefix */
+	g_string_append_len (string, PEM_PREF_BEGIN, PEM_PREF_BEGIN_L);
+	g_string_append (string, g_quark_to_string (type));
+	g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
+	g_string_append_c (string, '\n');
+	
+	/* The headers */
+	if (headers && g_hash_table_size (headers) > 0) {
+		g_hash_table_foreach (headers, append_each_header, string);
+		g_string_append_c (string, '\n');
+	}
+
+	/* Resize string to fit the base64 data. Algorithm from Glib reference */
+	length = n_data * 4 / 3 + n_data * 4 / (3 * 72) + 7;
+	n_prefix = string->len;
+	g_string_set_size (string, n_prefix + length);
+	
+	/* The actual base64 data */
+	state = save = 0;
+	length = g_base64_encode_step (data, n_data, TRUE, 
+	                               string->str + string->len, &state, &save);
+	g_string_set_size (string, n_prefix + length);
+	
+	/* The suffix */
+	g_string_append_c (string, '\n');
+	g_string_append_len (string, PEM_PREF_END, PEM_PREF_END_L);
+	g_string_append (string, g_quark_to_string (type));
+	g_string_append_len (string, PEM_SUFF, PEM_SUFF_L);
+	g_string_append_c (string, '\n');
+	
+	*n_result = string->len;
+	return (guchar*)g_string_free (string, FALSE);
+}
+
+#endif /* UNTESTED_CODE */

Added: trunk/pkcs11/gck/gck-data-pem.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-pem.h	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,42 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gkr-pkix-pem.h - PEM base64 helper routines
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#ifndef GCK_DATA_PEM_H_
+#define GCK_DATA_PEM_H_
+
+#include <glib.h>
+
+typedef void (*GckDataPemCallback) (GQuark type, const guchar *data, gsize n_data,
+                                    GHashTable *headers, gpointer user_data);
+
+GHashTable*    gck_data_pem_headers_new       (void);
+
+guint          gck_data_pem_parse             (const guchar *data, gsize n_data, 
+                                               GckDataPemCallback callback, 
+                                               gpointer user_data);
+
+guchar*        gck_data_pem_write             (const guchar *data, gsize n_data, 
+                                               GQuark type, GHashTable *headers,
+                                               gsize *n_result);
+
+#endif /* GCK_DATA_PEM_H_ */

Added: trunk/pkcs11/gck/gck-data-types.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-data-types.h	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,14 @@
+#ifndef GCKDATA_H_
+#define GCKDATA_H_
+
+#include <glib.h>
+
+typedef enum _GckDataResult {
+	GCK_DATA_FAILURE = -2,
+	GCK_DATA_UNRECOGNIZED = 0,
+	GCK_DATA_SUCCESS = 1
+} GckDataResult;
+
+typedef void* (*GckDataAllocator) (void* p, unsigned long len);
+
+#endif /* GCKDATA_H_ */

Added: trunk/pkcs11/gck/gck-file-tracker.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-file-tracker.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,302 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-file-tracker.c - Watch for changes in a directory
+
+   Copyright (C) 2008 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "gck-file-tracker.h"
+
+#include <glib.h>
+#include <glib/gstdio.h>
+
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+
+typedef struct _UpdateDescendants {
+	GckFileTracker *tracker;
+	GHashTable *checks;
+} UpdateDescendants;
+
+struct _GckFileTracker {
+	GObject parent;
+	
+	/* Specification */
+	GPatternSpec *include;
+	GPatternSpec *exclude;
+	gchar *directory_path;
+	time_t directory_mtime;
+	
+	/* Matched files */
+	GHashTable *files;
+};
+
+enum {
+	FILE_ADDED,
+	FILE_REMOVED,
+	FILE_CHANGED,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GckFileTracker, gck_file_tracker, G_TYPE_OBJECT);
+
+/* -----------------------------------------------------------------------------
+ * HELPERS
+ */
+
+static void
+copy_key_string (gpointer key, gpointer value, gpointer data)
+{
+	GHashTable *dest = (GHashTable*)data;
+	g_hash_table_replace (dest, g_strdup (key), value);
+}
+
+static void
+remove_files (gpointer key, gpointer value, gpointer data)
+{
+	GckFileTracker *self = GCK_FILE_TRACKER (data);
+
+	g_hash_table_remove (self->files, key);
+	g_signal_emit (self, signals[FILE_REMOVED], 0, key);
+} 
+
+static gboolean
+update_file (GckFileTracker *self, gboolean force_all, const gchar *path)
+{
+	time_t old_mtime;
+	struct stat sb;
+
+	if (stat (path, &sb) < 0) {
+		if (errno != ENOENT && errno != ENOTDIR && errno != EPERM)
+			g_warning ("couldn't stat file: %s: %s", path, g_strerror (errno));
+		return FALSE;
+	}
+
+	old_mtime = GPOINTER_TO_UINT (g_hash_table_lookup (self->files, path));
+	g_assert (old_mtime);
+
+	/* See if it has actually changed */
+	if (force_all || old_mtime != sb.st_mtime) {
+		g_assert (g_hash_table_lookup (self->files, path));
+		g_hash_table_insert (self->files, g_strdup (path), GUINT_TO_POINTER (sb.st_mtime));
+		g_signal_emit (self, signals[FILE_CHANGED], 0, path);
+	}
+	
+	return TRUE;
+}
+		
+static void
+update_each_file (gpointer key, gpointer unused, gpointer data)
+{
+	UpdateDescendants *ctx = (UpdateDescendants*)data;
+	if (update_file (ctx->tracker, FALSE, key))
+		g_hash_table_remove (ctx->checks, key);
+}
+
+static void
+update_directory (GckFileTracker *self, gboolean force_all, GHashTable *checks)
+{
+	UpdateDescendants uctx;
+	struct stat sb;
+	GError *err = NULL;
+	const char *filename;
+	gchar *path;
+	gchar *file;
+	GDir *dir;
+	int ret, lasterr;
+
+	g_assert (checks);
+	g_assert (GCK_IS_FILE_TRACKER (self));
+	
+	if (!self->directory_path)
+		return;
+
+	if (stat (self->directory_path, &sb) < 0) {
+		if (errno != ENOENT && errno != ENOTDIR && errno != EPERM)
+			g_message ("couldn't stat directory: %s: %s", path, g_strerror (errno));
+		return;
+	}
+
+	/* See if it was updated since last seen or not */
+	if (!force_all && self->directory_mtime == sb.st_mtime) {
+		
+		uctx.checks = checks;
+		uctx.tracker = self;
+
+		/* Still need to check for individual file updates */
+		g_hash_table_foreach (self->files, update_each_file, &uctx);
+		return;
+	}
+
+	self->directory_mtime = sb.st_mtime;
+
+	/* Actually list the directory */
+	dir = g_dir_open (self->directory_path, 0, &err);
+	if (dir == NULL) {
+		if (errno != ENOENT && errno != ENOTDIR && errno != EPERM)
+			g_message ("couldn't list keyrings at: %s: %s", path, 
+		        	   err && err->message ? err->message : "");
+		g_error_free (err);  
+		return;
+	}
+	
+	while ((filename = g_dir_read_name (dir)) != NULL) {
+		if (filename[0] == '.')
+			continue;
+		if (self->include && !g_pattern_match_string (self->include, filename))
+			continue;
+		if (self->exclude && g_pattern_match_string (self->exclude, filename))
+			continue;
+
+		file = g_build_filename (self->directory_path, filename, NULL);
+
+		/* If we hadn't yet seen this, then add it */
+		if (!g_hash_table_remove (checks, file)) {
+			
+			/* Get the last modified time for this one */
+			ret = g_stat (file, &sb);
+			lasterr = errno;
+			
+			/* Couldn't access the file */
+			if (ret < 0) {
+				g_message ("couldn't stat file: %s: %s", file, g_strerror (lasterr));
+				
+			} else {
+			
+				/* We don't do directories */
+				if (!(sb.st_mode & S_IFDIR)) {
+					g_hash_table_replace (self->files, g_strdup (file), GINT_TO_POINTER (sb.st_mtime));
+					g_signal_emit (self, signals[FILE_ADDED], 0, file);
+				}
+			}
+
+		/* Otherwise we already had it, see if it needs updating */
+		} else {
+			update_file (self, force_all, file);
+		}
+		
+		g_free (file);
+	}
+
+	g_dir_close (dir);
+}
+
+/* -----------------------------------------------------------------------------
+ * OBJECT
+ */
+
+static void
+gck_file_tracker_init (GckFileTracker *self)
+{
+	self->files = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+}
+
+static void
+gck_file_tracker_finalize (GObject *obj)
+{
+	GckFileTracker *self = GCK_FILE_TRACKER (obj);
+	 
+	if (self->include)
+		g_pattern_spec_free (self->include);
+	if (self->exclude)
+		g_pattern_spec_free (self->exclude);
+	g_free (self->directory_path);
+	
+	g_hash_table_destroy (self->files);
+	
+	G_OBJECT_CLASS (gck_file_tracker_parent_class)->finalize (obj);
+}
+
+static void
+gck_file_tracker_class_init (GckFileTrackerClass *klass)
+{
+	GObjectClass *gobject_class;
+	gobject_class = (GObjectClass*) klass;
+
+	gck_file_tracker_parent_class = g_type_class_peek_parent (klass);
+	gobject_class->finalize = gck_file_tracker_finalize;
+
+	signals[FILE_ADDED] = g_signal_new ("file-added", GCK_TYPE_FILE_TRACKER, 
+			G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckFileTrackerClass, file_added),
+			NULL, NULL, g_cclosure_marshal_VOID__STRING, 
+			G_TYPE_NONE, 1, G_TYPE_STRING);
+			
+	signals[FILE_CHANGED] = g_signal_new ("file-changed", GCK_TYPE_FILE_TRACKER, 
+			G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckFileTrackerClass, file_changed),
+			NULL, NULL, g_cclosure_marshal_VOID__STRING, 
+			G_TYPE_NONE, 1, G_TYPE_STRING);
+
+	signals[FILE_REMOVED] = g_signal_new ("file-removed", GCK_TYPE_FILE_TRACKER, 
+			G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (GckFileTrackerClass, file_removed),
+			NULL, NULL, g_cclosure_marshal_VOID__STRING, 
+			G_TYPE_NONE, 1, G_TYPE_STRING);
+}
+
+GckFileTracker* 
+gck_file_tracker_new (const gchar *directory, const gchar *include, const gchar *exclude)
+{
+	GckFileTracker *self;
+	const gchar *homedir;
+	
+	g_return_val_if_fail (directory, NULL);
+	
+	self = g_object_new (GCK_TYPE_FILE_TRACKER, NULL);
+	
+	/* TODO: Use properties */	
+	
+	if (directory[0] == '~' && directory[1] == '/') {
+		homedir = g_getenv ("HOME");
+		if (!homedir)
+			homedir = g_get_home_dir ();
+		self->directory_path = g_build_filename (homedir, directory + 2, NULL);
+		
+	/* A relative or absolute path */
+	} else {
+		self->directory_path = g_strdup (directory);
+	}
+	
+	self->include = include ? g_pattern_spec_new (include) : NULL;
+	self->exclude = exclude ? g_pattern_spec_new (exclude) : NULL;
+	
+	return self;
+}
+
+void
+gck_file_tracker_refresh (GckFileTracker *self, gboolean force_all)
+{
+	GHashTable *checks;
+	
+	g_return_if_fail (GCK_IS_FILE_TRACKER (self));
+	
+	/* Copy into our check set */
+	checks = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+	g_hash_table_foreach (self->files, copy_key_string, checks);
+	
+	/* If only one volume, then just try and access it directly */
+	update_directory (self, force_all, checks);
+		
+	/* Find any keyrings whose paths we didn't see */
+	g_hash_table_foreach (checks, remove_files, self); 
+	g_hash_table_destroy (checks);
+}

Added: trunk/pkcs11/gck/gck-file-tracker.h
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/gck-file-tracker.h	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,63 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* gck-file-tracker.h - Watch for changes in a directory
+
+   Copyright (C) 2008, Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#ifndef __GCK_FILE_TRACKER_H__
+#define __GCK_FILE_TRACKER_H__
+
+#include <glib-object.h>
+
+#include "gck-file-tracker.h"
+
+G_BEGIN_DECLS
+
+#define GCK_TYPE_FILE_TRACKER             (gck_file_tracker_get_type ())
+#define GCK_FILE_TRACKER(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GCK_TYPE_FILE_TRACKER, GckFileTracker))
+#define GCK_FILE_TRACKER_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GCK_TYPE_FILE_TRACKER, GObject))
+#define GCK_IS_FILE_TRACKER(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GCK_TYPE_FILE_TRACKER))
+#define GCK_IS_FILE_TRACKER_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GCK_TYPE_FILE_TRACKER))
+#define GCK_FILE_TRACKER_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GCK_TYPE_FILE_TRACKER, GckFileTrackerClass))
+
+typedef struct _GckFileTracker GckFileTracker;
+typedef struct _GckFileTrackerClass GckFileTrackerClass;
+
+struct _GckFileTrackerClass {
+	GObjectClass parent_class;
+
+	void (*file_added) (GckFileTracker *locmgr, const gchar *path);
+	void (*file_changed) (GckFileTracker *locmgr, const gchar *path);
+	void (*file_removed) (GckFileTracker *locmgr, const gchar *path);
+};
+
+GType                    gck_file_tracker_get_type             (void) G_GNUC_CONST;
+
+GckFileTracker*          gck_file_tracker_new                  (const gchar *directory,
+                                                                const gchar *include_pattern,
+                                                                const gchar *exclude_pattern);
+
+void                     gck_file_tracker_refresh              (GckFileTracker *self, 
+                                                                gboolean force_all);
+
+G_END_DECLS
+
+#endif /* __GCK_FILE_TRACKER_H__ */
+

Modified: trunk/pkcs11/gck/gck-module-ep.h
==============================================================================
--- trunk/pkcs11/gck/gck-module-ep.h	(original)
+++ trunk/pkcs11/gck/gck-module-ep.h	Mon Dec 22 20:21:06 2008
@@ -36,6 +36,8 @@
 	CK_RV rv = CKR_OK;
 	pid_t pid = getpid ();
 	
+	gck_crypto_initialize (void);
+	
 	g_static_mutex_lock (&pkcs11_module_mutex);
 	
 		if (pkcs11_module != NULL) {

Modified: trunk/pkcs11/gck/gck-module.c
==============================================================================
--- trunk/pkcs11/gck/gck-module.c	(original)
+++ trunk/pkcs11/gck/gck-module.c	Mon Dec 22 20:21:06 2008
@@ -216,6 +216,13 @@
  */
 
 static CK_RV
+gck_module_real_refresh_token (GckModule *self)
+{
+	/* Derived classes should do something interesting */
+	return CKR_OK;
+}
+
+static CK_RV
 gck_module_real_login_user (GckModule *self, CK_SLOT_ID slot_id, CK_UTF8CHAR_PTR pin, CK_ULONG n_pin)
 {
 	VirtualSlot *slot;
@@ -360,6 +367,7 @@
 	klass->slot_info = &default_slot_info;
 	klass->token_info = &default_token_info;
 	
+	klass->refresh_token = gck_module_real_refresh_token;
 	klass->login_user = gck_module_real_login_user;
 	klass->logout_user = gck_module_real_logout_user;
 	

Modified: trunk/pkcs11/gck/gck-module.h
==============================================================================
--- trunk/pkcs11/gck/gck-module.h	(original)
+++ trunk/pkcs11/gck/gck-module.h	Mon Dec 22 20:21:06 2008
@@ -57,6 +57,8 @@
 	
 	/* virtual methods */
 	
+	CK_RV (*refresh_token) (GckModule *self);
+	
 	CK_RV (*login_user) (GckModule *self, CK_SLOT_ID slot_id, 
 	                     CK_UTF8CHAR_PTR pin, CK_ULONG n_pin);
 	

Added: trunk/pkcs11/gck/pk.asn
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/pk.asn	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,103 @@
+PK { }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+-- This file contains parts of PKCS-1 structures and some stuff
+-- required for DSA keys.
+
+RSAPublicKey ::= SEQUENCE {
+        modulus                 INTEGER, -- n
+        publicExponent          INTEGER  -- e 
+}
+
+-- 
+-- Representation of RSA private key with information for the 
+-- CRT algorithm.
+--
+RSAPrivateKey ::= SEQUENCE {
+        version          	Version,
+        modulus          	INTEGER, -- (Usually large) n
+        publicExponent   	INTEGER, -- (Usually small) e
+        privateExponent  	INTEGER, -- (Usually large) d
+        prime1           	INTEGER, -- (Usually large) p
+	prime2           	INTEGER, -- (Usually large) q
+	exponent1        	INTEGER, -- (Usually large) d mod (p-1)
+	exponent2        	INTEGER, -- (Usually large) d mod (q-1)
+	coefficient      	INTEGER, -- (Usually large) (inverse of q) mod p
+	otherPrimeInfos 	OtherPrimeInfos OPTIONAL
+}
+
+Version ::= INTEGER { two-prime(0), multi(1) }
+-- version must be multi if otherPrimeInfos present --
+
+OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
+
+OtherPrimeInfo ::= SEQUENCE {
+	prime INTEGER,  -- ri
+	exponent INTEGER, -- di
+	coefficient INTEGER -- ti 
+}
+
+-- for signature calculation
+-- added by nmav
+
+AlgorithmIdentifier ::= SEQUENCE  {
+     algorithm               OBJECT IDENTIFIER,
+     parameters              ANY DEFINED BY algorithm OPTIONAL  
+}
+                                -- contains a value of the type
+                                -- registered for use with the
+                                -- algorithm object identifier value
+
+DigestInfo ::= SEQUENCE {
+     digestAlgorithm DigestAlgorithmIdentifier,
+     digest Digest 
+}
+
+DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+
+Digest ::= OCTET STRING
+
+DSAPublicPart ::= INTEGER
+
+DSAPublicKey ::= SEQUENCE {
+        version          	INTEGER, -- should be zero
+        p          		INTEGER,
+        q   			INTEGER,
+        g  			INTEGER,
+        Y	     	      	INTEGER  -- public
+}
+
+DSAParameters ::= SEQUENCE {
+        p                   INTEGER,
+        q                   INTEGER,
+        g                   INTEGER
+}
+
+DSASignatureValue ::= SEQUENCE {
+        r                   INTEGER,
+        s                   INTEGER
+}
+
+DSAPrivatePart ::= INTEGER
+
+DSAPrivateKey ::= SEQUENCE {
+        version          	INTEGER, -- should be zero
+        p          		INTEGER,
+        q   			INTEGER,
+        g  			INTEGER,
+        Y	     	      	INTEGER, -- public
+	priv           		INTEGER
+}
+
+-- from PKCS#3
+DHParameter ::= SEQUENCE {
+	prime INTEGER, -- p
+	base INTEGER, -- g
+	privateValueLength INTEGER OPTIONAL 
+}
+
+
+END

Added: trunk/pkcs11/gck/pkix.asn
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/pkix.asn	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,1230 @@
+
+PKIX1 { }
+
+DEFINITIONS IMPLICIT TAGS ::=
+
+BEGIN
+
+-- This contains both PKIX1Implicit88 and RFC2630 ASN.1 modules.
+
+-- ISO arc for standard certificate and CRL extensions
+
+id-ce OBJECT IDENTIFIER  ::=  {joint-iso-ccitt(2) ds(5) 29}
+
+
+-- authority key identifier OID and syntax
+
+id-ce-authorityKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 35 }
+
+AuthorityKeyIdentifier ::= SEQUENCE {
+      keyIdentifier             [0] KeyIdentifier            OPTIONAL,
+      authorityCertIssuer       [1] GeneralNames             OPTIONAL,
+      authorityCertSerialNumber [2] CertificateSerialNumber  OPTIONAL }
+    -- authorityCertIssuer and authorityCertSerialNumber shall both
+    -- be present or both be absgent
+
+KeyIdentifier ::= OCTET STRING
+
+-- subject key identifier OID and syntax
+
+id-ce-subjectKeyIdentifier OBJECT IDENTIFIER ::=  { id-ce 14 }
+
+SubjectKeyIdentifier ::= KeyIdentifier
+
+-- key usage extension OID and syntax
+
+id-ce-keyUsage OBJECT IDENTIFIER ::=  { id-ce 15 }
+
+KeyUsage ::= BIT STRING {
+     digitalSignature        (0),
+     nonRepudiation          (1),
+     keyEncipherment         (2),
+     dataEncipherment        (3),
+     keyAgreement            (4),
+     keyCertSign             (5),
+     cRLSign                 (6),
+     encipherOnly            (7),
+     decipherOnly            (8) }
+
+-- private key usage period extension OID and syntax
+
+id-ce-privateKeyUsagePeriod OBJECT IDENTIFIER ::=  { id-ce 16 }
+
+PrivateKeyUsagePeriod ::= SEQUENCE {
+     notBefore       [0]     GeneralizedTime OPTIONAL,
+     notAfter        [1]     GeneralizedTime OPTIONAL }
+     -- either notBefore or notAfter shall be present
+
+-- certificate policies extension OID and syntax
+
+id-ce-certificatePolicies OBJECT IDENTIFIER ::=  { id-ce 32 }
+
+CertificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
+
+PolicyInformation ::= SEQUENCE {
+     policyIdentifier   CertPolicyId,
+     policyQualifiers   SEQUENCE SIZE (1..MAX) OF
+             PolicyQualifierInfo OPTIONAL }
+
+CertPolicyId ::= OBJECT IDENTIFIER
+
+PolicyQualifierInfo ::= SEQUENCE {
+       policyQualifierId  PolicyQualifierId,
+       qualifier        ANY DEFINED BY policyQualifierId }
+
+-- Implementations that recognize additional policy qualifiers shall
+-- augment the following definition for PolicyQualifierId
+
+PolicyQualifierId ::=
+    OBJECT IDENTIFIER  -- ( id-qt-cps | id-qt-unotice )
+
+-- CPS pointer qualifier
+
+CPSuri ::= IA5String
+
+-- user notice qualifier
+
+UserNotice ::= SEQUENCE {
+     noticeRef        NoticeReference OPTIONAL,
+     explicitText     DisplayText OPTIONAL}
+
+NoticeReference ::= SEQUENCE {
+     organization     DisplayText,
+     noticeNumbers    SEQUENCE OF INTEGER }
+
+DisplayText ::= CHOICE {
+     visibleString    VisibleString  (SIZE (1..200)),
+     bmpString        BMPString      (SIZE (1..200)),
+     utf8String       UTF8String     (SIZE (1..200)) }
+
+-- policy mapping extension OID and syntax
+
+id-ce-policyMappings OBJECT IDENTIFIER ::=  { id-ce 33 }
+
+PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
+     issuerDomainPolicy      CertPolicyId,
+     subjectDomainPolicy     CertPolicyId }
+
+-- subject alternative name extension OID and syntax
+
+-- Directory string type --
+
+DirectoryString ::= CHOICE {
+      teletexString             TeletexString (SIZE (1..MAX)),
+      printableString           PrintableString (SIZE (1..MAX)),
+      universalString           UniversalString (SIZE (1..MAX)),
+      utf8String              UTF8String (SIZE (1..MAX)),
+      bmpString               BMPString (SIZE(1..MAX)),
+      -- IA5String is added here to handle old UID encoded as ia5String --
+      -- See tests/userid/ for more information.  It shouldn't be here, --
+      -- so if it causes problems, considering dropping it. --
+      ia5String               IA5String (SIZE(1..MAX)) }
+
+id-ce-subjectAltName OBJECT IDENTIFIER ::=  { id-ce 17 }
+
+SubjectAltName ::= GeneralNames
+
+GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
+
+GeneralName ::= CHOICE {
+     otherName                       [0]     AnotherName,
+     rfc822Name                      [1]     IA5String,
+     dNSName                         [2]     IA5String,
+     x400Address                     [3]     ORAddress,
+-- Changed to work with the libtasn1 parser.
+     directoryName                   [4]     EXPLICIT RDNSequence, --Name,
+     ediPartyName                    [5]     EDIPartyName,
+     uniformResourceIdentifier       [6]     IA5String,
+     iPAddress                       [7]     OCTET STRING,
+     registeredID                    [8]     OBJECT IDENTIFIER }
+
+-- AnotherName replaces OTHER-NAME ::= TYPE-IDENTIFIER, as
+-- TYPE-IDENTIFIER is not supported in the '88 ASN.1 syntax
+
+AnotherName ::= SEQUENCE {
+     type-id    OBJECT IDENTIFIER,
+     value      [0] EXPLICIT ANY DEFINED BY type-id }
+
+EDIPartyName ::= SEQUENCE {
+     nameAssigner            [0]     DirectoryString OPTIONAL,
+     partyName               [1]     DirectoryString }
+
+-- issuer alternative name extension OID and syntax
+
+id-ce-issuerAltName OBJECT IDENTIFIER ::=  { id-ce 18 }
+
+IssuerAltName ::= GeneralNames
+
+id-ce-subjectDirectoryAttributes OBJECT IDENTIFIER ::=  { id-ce 9 }
+
+SubjectDirectoryAttributes ::= SEQUENCE SIZE (1..MAX) OF Attribute
+
+-- basic constraints extension OID and syntax
+
+id-ce-basicConstraints OBJECT IDENTIFIER ::=  { id-ce 19 }
+
+BasicConstraints ::= SEQUENCE {
+     cA                      BOOLEAN DEFAULT FALSE,
+     pathLenConstraint       INTEGER (0..MAX) OPTIONAL }
+
+-- name constraints extension OID and syntax
+
+id-ce-nameConstraints OBJECT IDENTIFIER ::=  { id-ce 30 }
+
+NameConstraints ::= SEQUENCE {
+     permittedSubtrees       [0]     GeneralSubtrees OPTIONAL,
+     excludedSubtrees        [1]     GeneralSubtrees OPTIONAL }
+
+GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+
+GeneralSubtree ::= SEQUENCE {
+     base                    GeneralName,
+     minimum         [0]     BaseDistance DEFAULT 0,
+     maximum         [1]     BaseDistance OPTIONAL }
+
+BaseDistance ::= INTEGER (0..MAX)
+
+-- policy constraints extension OID and syntax
+
+id-ce-policyConstraints OBJECT IDENTIFIER ::=  { id-ce 36 }
+
+PolicyConstraints ::= SEQUENCE {
+     requireExplicitPolicy           [0] SkipCerts OPTIONAL,
+     inhibitPolicyMapping            [1] SkipCerts OPTIONAL }
+
+SkipCerts ::= INTEGER (0..MAX)
+
+-- CRL distribution points extension OID and syntax
+
+id-ce-cRLDistributionPoints     OBJECT IDENTIFIER  ::=  {id-ce 31}
+
+CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+
+DistributionPoint ::= SEQUENCE {
+     distributionPoint       [0]     EXPLICIT DistributionPointName OPTIONAL,
+     reasons                 [1]     ReasonFlags OPTIONAL,
+     cRLIssuer               [2]     GeneralNames OPTIONAL
+}
+
+DistributionPointName ::= CHOICE {
+    fullName                [0]     GeneralNames,
+    nameRelativeToCRLIssuer [1]     RelativeDistinguishedName 
+}
+
+ReasonFlags ::= BIT STRING {
+     unused                  (0),
+     keyCompromise           (1),
+     cACompromise            (2),
+     affiliationChanged      (3),
+     superseded              (4),
+     cessationOfOperation    (5),
+     certificateHold         (6),
+     privilegeWithdrawn      (7),
+     aACompromise            (8) }
+
+-- extended key usage extension OID and syntax
+
+id-ce-extKeyUsage OBJECT IDENTIFIER ::= {id-ce 37}
+
+ExtKeyUsageSyntax ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
+
+KeyPurposeId ::= OBJECT IDENTIFIER
+
+-- extended key purpose OIDs
+id-kp-serverAuth      OBJECT IDENTIFIER ::= { id-kp 1 }
+id-kp-clientAuth      OBJECT IDENTIFIER ::= { id-kp 2 }
+id-kp-codeSigning     OBJECT IDENTIFIER ::= { id-kp 3 }
+id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
+id-kp-ipsecEndSystem  OBJECT IDENTIFIER ::= { id-kp 5 }
+id-kp-ipsecTunnel     OBJECT IDENTIFIER ::= { id-kp 6 }
+id-kp-ipsecUser       OBJECT IDENTIFIER ::= { id-kp 7 }
+id-kp-timeStamping    OBJECT IDENTIFIER ::= { id-kp 8 }
+
+-- authority info access
+
+id-pe-authorityInfoAccess OBJECT IDENTIFIER ::= { id-pe 1 }
+
+AuthorityInfoAccessSyntax  ::=
+        SEQUENCE SIZE (1..MAX) OF AccessDescription
+
+AccessDescription  ::=  SEQUENCE {
+        accessMethod          OBJECT IDENTIFIER,
+        accessLocation        GeneralName  }
+
+-- CRL number extension OID and syntax
+
+id-ce-cRLNumber OBJECT IDENTIFIER ::= { id-ce 20 }
+
+CRLNumber ::= INTEGER (0..MAX)
+
+-- issuing distribution point extension OID and syntax
+
+id-ce-issuingDistributionPoint OBJECT IDENTIFIER ::= { id-ce 28 }
+
+IssuingDistributionPoint ::= SEQUENCE {
+     distributionPoint       [0] DistributionPointName OPTIONAL,
+     onlyContainsUserCerts   [1] BOOLEAN DEFAULT FALSE,
+     onlyContainsCACerts     [2] BOOLEAN DEFAULT FALSE,
+     onlySomeReasons         [3] ReasonFlags OPTIONAL,
+     indirectCRL             [4] BOOLEAN DEFAULT FALSE }
+
+
+id-ce-deltaCRLIndicator OBJECT IDENTIFIER ::= { id-ce 27 }
+
+-- deltaCRLIndicator ::= BaseCRLNumber
+
+BaseCRLNumber ::= CRLNumber
+
+-- CRL reasons extension OID and syntax
+
+id-ce-cRLReasons OBJECT IDENTIFIER ::= { id-ce 21 }
+
+CRLReason ::= ENUMERATED {
+     unspecified             (0),
+     keyCompromise           (1),
+     cACompromise            (2),
+     affiliationChanged      (3),
+     superseded              (4),
+     cessationOfOperation    (5),
+     certificateHold         (6),
+     removeFromCRL           (8) }
+
+-- certificate issuer CRL entry extension OID and syntax
+
+id-ce-certificateIssuer OBJECT IDENTIFIER ::= { id-ce 29 }
+
+CertificateIssuer ::= GeneralNames
+
+-- hold instruction extension OID and syntax
+
+id-ce-holdInstructionCode OBJECT IDENTIFIER ::= { id-ce 23 }
+
+HoldInstructionCode ::= OBJECT IDENTIFIER
+
+-- ANSI x9 holdinstructions
+
+-- ANSI x9 arc holdinstruction arc
+holdInstruction OBJECT IDENTIFIER ::=
+          {joint-iso-itu-t(2) member-body(2) us(840) x9cm(10040) 2}
+
+-- ANSI X9 holdinstructions referenced by this standard
+id-holdinstruction-none OBJECT IDENTIFIER  ::=
+                {holdInstruction 1} -- deprecated
+id-holdinstruction-callissuer OBJECT IDENTIFIER ::=
+                {holdInstruction 2}
+id-holdinstruction-reject OBJECT IDENTIFIER ::=
+                {holdInstruction 3}
+
+-- invalidity date CRL entry extension OID and syntax
+
+id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 }
+
+InvalidityDate ::=  GeneralizedTime
+
+
+-- --------------------------------------
+--  EXPLICIT
+-- --------------------------------------
+
+-- UNIVERSAL Types defined in '93 and '98 ASN.1
+-- but required by this specification
+
+VisibleString ::= [UNIVERSAL 26] IMPLICIT OCTET STRING
+
+NumericString ::= [UNIVERSAL 18] IMPLICIT OCTET STRING
+
+IA5String ::= [UNIVERSAL 22] IMPLICIT OCTET STRING
+
+TeletexString ::= [UNIVERSAL 20] IMPLICIT OCTET STRING
+
+PrintableString ::= [UNIVERSAL 19] IMPLICIT OCTET STRING
+
+UniversalString ::= [UNIVERSAL 28] IMPLICIT OCTET STRING
+        -- UniversalString is defined in ASN.1:1993
+
+BMPString ::= [UNIVERSAL 30] IMPLICIT OCTET STRING
+      -- BMPString is the subtype of UniversalString and models
+       -- the Basic Multilingual Plane of ISO/IEC/ITU 10646-1
+
+UTF8String ::= [UNIVERSAL 12] IMPLICIT OCTET STRING
+        -- The content of this type conforms to RFC 2279.
+
+
+-- PKIX specific OIDs
+
+id-pkix  OBJECT IDENTIFIER  ::=
+         { iso(1) identified-organization(3) dod(6) internet(1)
+                    security(5) mechanisms(5) pkix(7) }
+
+-- PKIX arcs
+
+id-pe OBJECT IDENTIFIER  ::=  { id-pkix 1 }
+        -- arc for private certificate extensions
+id-qt OBJECT IDENTIFIER ::= { id-pkix 2 }
+        -- arc for policy qualifier types
+id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+        -- arc for extended key purpose OIDS
+id-ad OBJECT IDENTIFIER ::= { id-pkix 48 }
+        -- arc for access descriptors
+
+-- policyQualifierIds for Internet policy qualifiers
+
+id-qt-cps      OBJECT IDENTIFIER ::=  { id-qt 1 }
+        -- OID for CPS qualifier
+id-qt-unotice  OBJECT IDENTIFIER ::=  { id-qt 2 }
+        -- OID for user notice qualifier
+
+-- access descriptor definitions
+
+id-ad-ocsp      OBJECT IDENTIFIER ::= { id-ad 1 }
+id-ad-caIssuers OBJECT IDENTIFIER ::= { id-ad 2 }
+
+-- attribute data types --
+
+Attribute       ::=     SEQUENCE {
+        type            AttributeType,
+        values  SET OF AttributeValue
+                -- at least one value is required -- 
+}
+
+AttributeType           ::=   OBJECT IDENTIFIER
+
+AttributeValue          ::=   ANY DEFINED BY type
+
+AttributeTypeAndValue           ::=     SEQUENCE {
+        type    AttributeType,
+        value   AttributeValue }
+
+-- suggested naming attributes: Definition of the following
+--  information object set may be augmented to meet local
+--  requirements.  Note that deleting members of the set may
+--  prevent interoperability with conforming implementations.
+--  presented in pairs: the AttributeType followed by the
+--  type definition for the corresponding AttributeValue
+
+-- Arc for standard naming attributes
+id-at           OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) ds(5) 4}
+
+-- Attributes of type NameDirectoryString
+id-at-initials          AttributeType ::= { id-at 43 }
+X520initials ::= DirectoryString
+
+id-at-generationQualifier AttributeType ::= { id-at 44 }
+X520generationQualifier ::= DirectoryString
+
+id-at-surname           AttributeType ::= { id-at 4 }
+X520surName ::= DirectoryString
+
+id-at-givenName         AttributeType ::= { id-at 42 }
+X520givenName ::= DirectoryString
+
+id-at-name              AttributeType ::= { id-at 41 }
+X520name        ::= DirectoryString
+
+id-at-commonName        AttributeType   ::=     {id-at 3}
+X520CommonName  ::=      DirectoryString
+
+id-at-localityName      AttributeType   ::=     {id-at 7}
+X520LocalityName ::= DirectoryString
+
+id-at-stateOrProvinceName       AttributeType   ::=     {id-at 8}
+X520StateOrProvinceName         ::= DirectoryString
+
+id-at-organizationName          AttributeType   ::=     {id-at 10}
+X520OrganizationName ::= DirectoryString
+
+id-at-organizationalUnitName    AttributeType   ::=     {id-at 11}
+X520OrganizationalUnitName ::= DirectoryString
+
+id-at-title     AttributeType   ::=     {id-at 12}
+X520Title ::=   DirectoryString
+
+id-at-description     AttributeType   ::=     {id-at 13}
+X520Description ::=   DirectoryString
+
+id-at-dnQualifier       AttributeType   ::=     {id-at 46}
+X520dnQualifier ::=     PrintableString
+
+id-at-countryName       AttributeType   ::=     {id-at 6}
+X520countryName ::=     PrintableString (SIZE (2)) -- IS 3166 codes
+
+id-at-serialNumber       AttributeType   ::=     {id-at 5}
+X520serialNumber ::=     PrintableString
+
+id-at-telephoneNumber       AttributeType   ::=     {id-at 20}
+X520telephoneNumber ::=     PrintableString
+
+id-at-facsimileTelephoneNumber       AttributeType   ::=     {id-at 23}
+X520facsimileTelephoneNumber ::=     PrintableString
+
+id-at-pseudonym 	AttributeType   ::=     {id-at 65}
+X520pseudonym ::=	DirectoryString
+
+id-at-name 	AttributeType   ::=     {id-at 41}
+X520name ::=	DirectoryString
+
+id-at-streetAddress 	AttributeType   ::=     {id-at 9}
+X520streetAddress ::=	DirectoryString
+
+id-at-postalAddress	AttributeType	::=	{id-at 16}
+X520postalAddress ::= PostalAddress
+
+PostalAddress ::= SEQUENCE OF DirectoryString
+
+
+ -- Legacy attributes
+
+pkcs OBJECT IDENTIFIER ::=
+       { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) }
+
+pkcs-9 OBJECT IDENTIFIER ::=
+       { pkcs 9 }
+
+
+emailAddress AttributeType      ::= { pkcs-9 1 }
+
+Pkcs9email ::= IA5String (SIZE (1..ub-emailaddress-length))
+
+-- naming data types --
+
+Name            ::=   CHOICE { -- only one possibility for now --
+                                 rdnSequence  RDNSequence }
+
+RDNSequence     ::=   SEQUENCE OF RelativeDistinguishedName
+
+DistinguishedName       ::=   RDNSequence
+
+RelativeDistinguishedName  ::=
+                    SET SIZE (1 .. MAX) OF AttributeTypeAndValue
+
+
+
+-- --------------------------------------------------------
+-- certificate and CRL specific structures begin here
+-- --------------------------------------------------------
+
+Certificate  ::=  SEQUENCE  {
+     tbsCertificate       TBSCertificate,
+     signatureAlgorithm   AlgorithmIdentifier,
+     signature            BIT STRING  }
+
+TBSCertificate  ::=  SEQUENCE  {
+     version         [0]  EXPLICIT Version DEFAULT v1,
+     serialNumber         CertificateSerialNumber,
+     signature            AlgorithmIdentifier,
+     issuer               Name,
+     validity             Validity,
+     subject              Name,
+     subjectPublicKeyInfo SubjectPublicKeyInfo,
+     issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
+                          -- If present, version shall be v2 or v3
+     subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
+                          -- If present, version shall be v2 or v3
+     extensions      [3]  EXPLICIT Extensions OPTIONAL
+                          -- If present, version shall be v3 --  
+}
+
+Version  ::=  INTEGER  {  v1(0), v2(1), v3(2)  }
+
+CertificateSerialNumber  ::=  INTEGER
+
+Validity ::= SEQUENCE {
+     notBefore      Time,
+     notAfter       Time }
+
+Time ::= CHOICE {
+     utcTime        UTCTime,
+     generalTime    GeneralizedTime }
+
+UniqueIdentifier  ::=  BIT STRING
+
+SubjectPublicKeyInfo  ::=  SEQUENCE  {
+     algorithm            AlgorithmIdentifier,
+     subjectPublicKey     BIT STRING  }
+
+Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
+
+Extension  ::=  SEQUENCE  {
+     extnID      OBJECT IDENTIFIER,
+     critical    BOOLEAN DEFAULT FALSE,
+     extnValue   OCTET STRING  }
+
+
+-- ------------------------------------------
+-- CRL structures
+-- ------------------------------------------
+
+CertificateList  ::=  SEQUENCE  {
+     tbsCertList          TBSCertList,
+     signatureAlgorithm   AlgorithmIdentifier,
+     signature            BIT STRING  }
+
+TBSCertList  ::=  SEQUENCE  {
+     version                 Version OPTIONAL,
+                                  -- if present, shall be v2
+     signature               AlgorithmIdentifier,
+     issuer                  Name,
+     thisUpdate              Time,
+     nextUpdate              Time OPTIONAL,
+     revokedCertificates     SEQUENCE OF SEQUENCE  {
+          userCertificate         CertificateSerialNumber,
+          revocationDate          Time,
+          crlEntryExtensions      Extensions OPTIONAL
+                                         -- if present, shall be v2
+                               }  OPTIONAL,
+     crlExtensions           [0] EXPLICIT Extensions OPTIONAL
+                                         -- if present, shall be v2 -- 
+}
+
+-- Version, Time, CertificateSerialNumber, and Extensions were
+-- defined earlier for use in the certificate structure
+
+AlgorithmIdentifier  ::=  SEQUENCE  {
+     algorithm               OBJECT IDENTIFIER,
+     parameters              ANY DEFINED BY algorithm OPTIONAL  }
+                                -- contains a value of the type
+                                -- registered for use with the
+                                -- algorithm object identifier value
+
+-- Algorithm OIDs and parameter structures
+
+pkcs-1 OBJECT IDENTIFIER ::= {
+     pkcs 1 }
+
+rsaEncryption OBJECT IDENTIFIER ::=  { pkcs-1 1 }
+
+md2WithRSAEncryption OBJECT IDENTIFIER  ::=  { pkcs-1 2 }
+
+md5WithRSAEncryption OBJECT IDENTIFIER  ::=  { pkcs-1 4 }
+
+sha1WithRSAEncryption OBJECT IDENTIFIER  ::=  { pkcs-1 5 }
+
+id-dsa-with-sha1 OBJECT IDENTIFIER ::=  {
+     iso(1) member-body(2) us(840) x9-57 (10040) x9algorithm(4) 3 }
+
+Dss-Sig-Value ::= SEQUENCE {
+     r       INTEGER,
+     s       INTEGER  
+}
+
+dhpublicnumber OBJECT IDENTIFIER ::= {
+     iso(1) member-body(2) us(840) ansi-x942(10046) number-type(2) 1 }
+
+DomainParameters ::= SEQUENCE {
+     p       INTEGER, -- odd prime, p=jq +1
+     g       INTEGER, -- generator, g
+     q       INTEGER, -- factor of p-1
+     j       INTEGER OPTIONAL, -- subgroup factor, j>= 2
+     validationParms  ValidationParms OPTIONAL }
+
+ValidationParms ::= SEQUENCE {
+     seed             BIT STRING,
+     pgenCounter      INTEGER }
+
+id-dsa OBJECT IDENTIFIER ::= {
+     iso(1) member-body(2) us(840) x9-57(10040) x9algorithm(4) 1 }
+
+Dss-Parms  ::=  SEQUENCE  {
+     p             INTEGER,
+     q             INTEGER,
+     g             INTEGER  }
+
+-- x400 address syntax starts here
+--      OR Names
+
+ORAddress ::= SEQUENCE {
+   built-in-standard-attributes BuiltInStandardAttributes,
+   built-in-domain-defined-attributes
+                        BuiltInDomainDefinedAttributes OPTIONAL,
+   -- see also teletex-domain-defined-attributes
+   extension-attributes ExtensionAttributes OPTIONAL }
+--      The OR-address is semantically absent from the OR-name if the
+--      built-in-standard-attribute sequence is empty and the
+--      built-in-domain-defined-attributes and extension-attributes are
+--      both omitted.
+
+--      Built-in Standard Attributes
+
+BuiltInStandardAttributes ::= SEQUENCE {
+   country-name CountryName OPTIONAL,
+   administration-domain-name AdministrationDomainName OPTIONAL,
+   network-address      [0] EXPLICIT NetworkAddress OPTIONAL,
+   -- see also extended-network-address
+   terminal-identifier  [1] EXPLICIT TerminalIdentifier OPTIONAL,
+   private-domain-name  [2] EXPLICIT PrivateDomainName OPTIONAL,
+   organization-name    [3] EXPLICIT OrganizationName OPTIONAL,
+   -- see also teletex-organization-name
+   numeric-user-identifier      [4] EXPLICIT NumericUserIdentifier OPTIONAL,
+   personal-name        [5] EXPLICIT PersonalName OPTIONAL,
+   -- see also teletex-personal-name
+   organizational-unit-names    [6] EXPLICIT OrganizationalUnitNames OPTIONAL
+   -- see also teletex-organizational-unit-names -- 
+}
+
+CountryName ::= [APPLICATION 1] CHOICE {
+   x121-dcc-code NumericString
+                (SIZE (ub-country-name-numeric-length)),
+   iso-3166-alpha2-code PrintableString
+                (SIZE (ub-country-name-alpha-length)) }
+
+AdministrationDomainName ::= [APPLICATION 2] EXPLICIT CHOICE {
+   numeric NumericString (SIZE (0..ub-domain-name-length)),
+   printable PrintableString (SIZE (0..ub-domain-name-length)) }
+
+NetworkAddress ::= X121Address  -- see also extended-network-address
+
+X121Address ::= NumericString (SIZE (1..ub-x121-address-length))
+
+TerminalIdentifier ::= PrintableString (SIZE (1..ub-terminal-id-length))
+
+PrivateDomainName ::= CHOICE {
+   numeric NumericString (SIZE (1..ub-domain-name-length)),
+   printable PrintableString (SIZE (1..ub-domain-name-length)) }
+
+OrganizationName ::= PrintableString
+                            (SIZE (1..ub-organization-name-length))
+-- see also teletex-organization-name
+
+NumericUserIdentifier ::= NumericString
+                            (SIZE (1..ub-numeric-user-id-length))
+
+PersonalName ::= SET {
+   surname [0] PrintableString (SIZE (1..ub-surname-length)),
+   given-name [1] PrintableString
+                        (SIZE (1..ub-given-name-length)) OPTIONAL,
+   initials [2] PrintableString (SIZE (1..ub-initials-length)) OPTIONAL,
+   generation-qualifier [3] PrintableString
+                (SIZE (1..ub-generation-qualifier-length)) OPTIONAL }
+-- see also teletex-personal-name
+
+OrganizationalUnitNames ::= SEQUENCE SIZE (1..ub-organizational-units)
+                                        OF OrganizationalUnitName
+-- see also teletex-organizational-unit-names
+
+OrganizationalUnitName ::= PrintableString (SIZE
+                        (1..ub-organizational-unit-name-length))
+
+--      Built-in Domain-defined Attributes
+
+BuiltInDomainDefinedAttributes ::= SEQUENCE SIZE
+                                (1..ub-domain-defined-attributes) OF
+                                BuiltInDomainDefinedAttribute
+
+BuiltInDomainDefinedAttribute ::= SEQUENCE {
+   type PrintableString (SIZE
+                        (1..ub-domain-defined-attribute-type-length)),
+   value PrintableString (SIZE
+                        (1..ub-domain-defined-attribute-value-length))}
+
+--      Extension Attributes
+
+ExtensionAttributes ::= SET SIZE (1..ub-extension-attributes) OF
+                        ExtensionAttribute
+
+ExtensionAttribute ::=  SEQUENCE {
+   extension-attribute-type [0] EXPLICIT INTEGER (0..ub-extension-attributes),
+   extension-attribute-value [1] EXPLICIT
+                        ANY DEFINED BY extension-attribute-type }
+
+-- Extension types and attribute values
+--
+
+common-name INTEGER ::= 1
+
+CommonName ::= PrintableString (SIZE (1..ub-common-name-length))
+
+teletex-common-name INTEGER ::= 2
+
+TeletexCommonName ::= TeletexString (SIZE (1..ub-common-name-length))
+
+teletex-organization-name INTEGER ::= 3
+
+TeletexOrganizationName ::=
+                TeletexString (SIZE (1..ub-organization-name-length))
+
+teletex-personal-name INTEGER ::= 4
+
+TeletexPersonalName ::= SET {
+   surname [0] EXPLICIT TeletexString (SIZE (1..ub-surname-length)),
+   given-name [1] EXPLICIT TeletexString
+                (SIZE (1..ub-given-name-length)) OPTIONAL,
+   initials [2] EXPLICIT TeletexString (SIZE (1..ub-initials-length)) OPTIONAL,
+   generation-qualifier [3] EXPLICIT TeletexString (SIZE
+                (1..ub-generation-qualifier-length)) OPTIONAL }
+
+teletex-organizational-unit-names INTEGER ::= 5
+
+TeletexOrganizationalUnitNames ::= SEQUENCE SIZE
+        (1..ub-organizational-units) OF TeletexOrganizationalUnitName
+
+TeletexOrganizationalUnitName ::= TeletexString
+                        (SIZE (1..ub-organizational-unit-name-length))
+
+pds-name INTEGER ::= 7
+
+PDSName ::= PrintableString (SIZE (1..ub-pds-name-length))
+
+physical-delivery-country-name INTEGER ::= 8
+
+PhysicalDeliveryCountryName ::= CHOICE {
+   x121-dcc-code NumericString (SIZE (ub-country-name-numeric-length)),
+   iso-3166-alpha2-code PrintableString
+                        (SIZE (ub-country-name-alpha-length)) }
+
+postal-code INTEGER ::= 9
+
+PostalCode ::= CHOICE {
+   numeric-code NumericString (SIZE (1..ub-postal-code-length)),
+   printable-code PrintableString (SIZE (1..ub-postal-code-length)) }
+
+physical-delivery-office-name INTEGER ::= 10
+
+PhysicalDeliveryOfficeName ::= PDSParameter
+
+physical-delivery-office-number INTEGER ::= 11
+
+PhysicalDeliveryOfficeNumber ::= PDSParameter
+
+extension-OR-address-components INTEGER ::= 12
+
+ExtensionORAddressComponents ::= PDSParameter
+
+physical-delivery-personal-name INTEGER ::= 13
+
+PhysicalDeliveryPersonalName ::= PDSParameter
+
+physical-delivery-organization-name INTEGER ::= 14
+
+PhysicalDeliveryOrganizationName ::= PDSParameter
+
+extension-physical-delivery-address-components INTEGER ::= 15
+
+ExtensionPhysicalDeliveryAddressComponents ::= PDSParameter
+
+unformatted-postal-address INTEGER ::= 16
+
+UnformattedPostalAddress ::= SET {
+   printable-address SEQUENCE SIZE (1..ub-pds-physical-address-lines) OF
+           PrintableString (SIZE (1..ub-pds-parameter-length)) OPTIONAL,
+   teletex-string TeletexString
+         (SIZE (1..ub-unformatted-address-length)) OPTIONAL }
+
+street-address INTEGER ::= 17
+
+StreetAddress ::= PDSParameter
+
+post-office-box-address INTEGER ::= 18
+
+PostOfficeBoxAddress ::= PDSParameter
+
+poste-restante-address INTEGER ::= 19
+
+PosteRestanteAddress ::= PDSParameter
+
+unique-postal-name INTEGER ::= 20
+
+UniquePostalName ::= PDSParameter
+
+local-postal-attributes INTEGER ::= 21
+
+LocalPostalAttributes ::= PDSParameter
+
+PDSParameter ::= SET {
+   printable-string PrintableString
+                (SIZE(1..ub-pds-parameter-length)) OPTIONAL,
+   teletex-string TeletexString
+                (SIZE(1..ub-pds-parameter-length)) OPTIONAL }
+
+extended-network-address INTEGER ::= 22
+
+ExtendedNetworkAddress ::= CHOICE {
+   e163-4-address SEQUENCE {
+        number [0] EXPLICIT NumericString (SIZE (1..ub-e163-4-number-length)),
+        sub-address [1] EXPLICIT NumericString
+                (SIZE (1..ub-e163-4-sub-address-length)) OPTIONAL },
+   psap-address [0] EXPLICIT PresentationAddress }
+
+PresentationAddress ::= SEQUENCE {
+        pSelector       [0] EXPLICIT OCTET STRING OPTIONAL,
+        sSelector       [1] EXPLICIT OCTET STRING OPTIONAL,
+        tSelector       [2] EXPLICIT OCTET STRING OPTIONAL,
+        nAddresses      [3] EXPLICIT SET SIZE (1..MAX) OF OCTET STRING }
+
+terminal-type  INTEGER ::= 23
+
+TerminalType ::= INTEGER {
+   telex (3),
+   teletex (4),
+   g3-facsimile (5),
+   g4-facsimile (6),
+   ia5-terminal (7),
+   videotex (8) } -- (0..ub-integer-options)
+
+--      Extension Domain-defined Attributes
+
+teletex-domain-defined-attributes INTEGER ::= 6
+
+TeletexDomainDefinedAttributes ::= SEQUENCE SIZE
+   (1..ub-domain-defined-attributes) OF TeletexDomainDefinedAttribute
+
+TeletexDomainDefinedAttribute ::= SEQUENCE {
+        type TeletexString
+               (SIZE (1..ub-domain-defined-attribute-type-length)),
+        value TeletexString
+               (SIZE (1..ub-domain-defined-attribute-value-length)) }
+
+--  specifications of Upper Bounds shall be regarded as mandatory
+--  from Annex B of ITU-T X.411 Reference Definition of MTS Parameter
+--  Upper Bounds
+
+--      Upper Bounds
+ub-name INTEGER ::=     32768
+ub-common-name  INTEGER ::=     64
+ub-locality-name        INTEGER ::=     128
+ub-state-name   INTEGER ::=     128
+ub-organization-name    INTEGER ::=     64
+ub-organizational-unit-name     INTEGER ::=     64
+ub-title        INTEGER ::=     64
+ub-match        INTEGER ::=     128
+
+ub-emailaddress-length INTEGER ::= 128
+
+ub-common-name-length INTEGER ::= 64
+ub-country-name-alpha-length INTEGER ::= 2
+ub-country-name-numeric-length INTEGER ::= 3
+ub-domain-defined-attributes INTEGER ::= 4
+ub-domain-defined-attribute-type-length INTEGER ::= 8
+ub-domain-defined-attribute-value-length INTEGER ::= 128
+ub-domain-name-length INTEGER ::= 16
+ub-extension-attributes INTEGER ::= 256
+ub-e163-4-number-length INTEGER ::= 15
+ub-e163-4-sub-address-length INTEGER ::= 40
+ub-generation-qualifier-length INTEGER ::= 3
+ub-given-name-length INTEGER ::= 16
+ub-initials-length INTEGER ::= 5
+ub-integer-options INTEGER ::= 256
+ub-numeric-user-id-length INTEGER ::= 32
+ub-organization-name-length INTEGER ::= 64
+ub-organizational-unit-name-length INTEGER ::= 32
+ub-organizational-units INTEGER ::= 4
+ub-pds-name-length INTEGER ::= 16
+ub-pds-parameter-length INTEGER ::= 30
+ub-pds-physical-address-lines INTEGER ::= 6
+ub-postal-code-length INTEGER ::= 16
+ub-surname-length INTEGER ::= 40
+ub-terminal-id-length INTEGER ::= 24
+ub-unformatted-address-length INTEGER ::= 180
+ub-x121-address-length INTEGER ::= 16
+
+-- Note - upper bounds on string types, such as TeletexString, are
+-- measured in characters.  Excepting PrintableString or IA5String, a
+-- significantly greater number of octets will be required to hold
+-- such a value.  As a minimum, 16 octets, or twice the specified upper
+-- bound, whichever is the larger, should be allowed for TeletexString.
+-- For UTF8String or UniversalString at least four times the upper
+-- bound should be allowed.
+
+
+
+-- END of PKIX1Implicit88
+
+
+-- BEGIN of RFC2630
+
+-- Cryptographic Message Syntax
+
+pkcs-7-ContentInfo ::= SEQUENCE {
+  contentType pkcs-7-ContentType,
+  content [0] EXPLICIT ANY DEFINED BY contentType }
+
+pkcs-7-DigestInfo ::= SEQUENCE {
+  digestAlgorithm pkcs-7-DigestAlgorithmIdentifier,
+  digest pkcs-7-Digest 
+}
+
+pkcs-7-Digest ::= OCTET STRING
+
+pkcs-7-ContentType ::= OBJECT IDENTIFIER
+
+pkcs-7-SignedData ::= SEQUENCE {
+  version pkcs-7-CMSVersion,
+  digestAlgorithms pkcs-7-DigestAlgorithmIdentifiers,
+  encapContentInfo pkcs-7-EncapsulatedContentInfo,
+  certificates [0] IMPLICIT pkcs-7-CertificateSet OPTIONAL,
+  crls [1] IMPLICIT pkcs-7-CertificateRevocationLists OPTIONAL,
+  signerInfos pkcs-7-SignerInfos 
+}
+
+pkcs-7-CMSVersion ::= INTEGER  { v0(0), v1(1), v2(2), v3(3), v4(4) }
+
+pkcs-7-DigestAlgorithmIdentifiers ::= SET OF pkcs-7-DigestAlgorithmIdentifier
+
+pkcs-7-DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+
+pkcs-7-EncapsulatedContentInfo ::= SEQUENCE {
+  eContentType pkcs-7-ContentType,
+  eContent [0] EXPLICIT OCTET STRING OPTIONAL }
+
+-- We don't use CertificateList here since we only want
+-- to read the raw data.
+pkcs-7-CertificateRevocationLists ::= SET OF ANY
+
+pkcs-7-CertificateChoices ::= CHOICE {
+-- Although the paper uses Certificate type, we
+-- don't use it since, we don't need to parse it.
+-- We only need to read and store it.
+  certificate ANY
+}
+
+pkcs-7-CertificateSet ::= SET OF pkcs-7-CertificateChoices
+
+pkcs-7-SignerInfos ::= SET OF ANY -- this is not correct but we don't use it
+ -- anyway
+
+
+-- BEGIN of RFC2986
+
+-- Certificate requests
+pkcs-10-CertificationRequestInfo ::= SEQUENCE {
+     version       INTEGER { v1(0) },
+     subject       Name,
+     subjectPKInfo SubjectPublicKeyInfo,
+     attributes    [0] Attributes
+}
+
+Attributes ::= SET OF Attribute
+
+pkcs-10-CertificationRequest ::= SEQUENCE {
+     certificationRequestInfo pkcs-10-CertificationRequestInfo,
+     signatureAlgorithm AlgorithmIdentifier,
+     signature          BIT STRING
+}
+
+-- stuff from PKCS#9
+
+pkcs-9-ub-challengePassword   INTEGER ::= 255
+
+pkcs-9-certTypes OBJECT IDENTIFIER ::= {pkcs-9 22}
+pkcs-9-crlTypes OBJECT IDENTIFIER ::= {pkcs-9 23}
+
+pkcs-9-at-challengePassword OBJECT IDENTIFIER   ::= {pkcs-9 7}
+
+pkcs-9-challengePassword        ::= CHOICE {
+      printableString       PrintableString (SIZE (1..pkcs-9-ub-challengePassword)),
+      utf8String            UTF8String (SIZE (1..pkcs-9-ub-challengePassword)) }
+
+pkcs-9-at-localKeyId               OBJECT IDENTIFIER ::= {pkcs-9 21}
+
+pkcs-9-localKeyId ::= OCTET STRING
+
+pkcs-9-at-friendlyName             OBJECT IDENTIFIER ::= {pkcs-9 20}
+
+pkcs-9-friendlyName ::= BMPString      (SIZE (1..255))
+
+-- PKCS #8 stuff
+
+-- Private-key information syntax
+
+pkcs-8-PrivateKeyInfo ::= SEQUENCE {
+  version pkcs-8-Version,
+  privateKeyAlgorithm AlgorithmIdentifier,
+  privateKey pkcs-8-PrivateKey,
+  attributes [0] Attributes OPTIONAL }
+
+pkcs-8-Version ::= INTEGER {v1(0)}
+
+pkcs-8-PrivateKey ::= OCTET STRING
+
+pkcs-8-Attributes ::= SET OF Attribute
+
+-- Encrypted private-key information syntax
+
+pkcs-8-EncryptedPrivateKeyInfo ::= SEQUENCE {
+    encryptionAlgorithm AlgorithmIdentifier,
+    encryptedData pkcs-8-EncryptedData 
+}
+
+pkcs-8-EncryptedData ::= OCTET STRING
+
+-- PKCS #5 stuff
+
+pkcs-5 OBJECT IDENTIFIER ::=
+       { pkcs 5 }
+
+pkcs-5-encryptionAlgorithm OBJECT IDENTIFIER ::=
+       { iso(1) member-body(2) us(840) rsadsi(113549) 3 }
+
+pkcs-5-des-EDE3-CBC OBJECT IDENTIFIER ::= {pkcs-5-encryptionAlgorithm 7}
+
+pkcs-5-des-EDE3-CBC-params ::= OCTET STRING (SIZE(8))
+
+pkcs-5-des-CBC-params ::= OCTET STRING (SIZE(8))
+
+pkcs-5-rc2-CBC-params ::= SEQUENCE {
+  rc2ParameterVersion INTEGER OPTIONAL,
+  iv OCTET STRING (SIZE(8)) 
+}
+  
+pkcs-5-PBE-params ::= SEQUENCE {
+  salt OCTET STRING (SIZE(8)),
+  iterationCount INTEGER
+}
+
+pkcs-5-id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13}
+
+pkcs-5-PBES2-params ::= SEQUENCE {
+  keyDerivationFunc AlgorithmIdentifier,
+  encryptionScheme AlgorithmIdentifier }
+
+-- PBKDF2
+
+pkcs-5-id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
+
+-- pkcs-5-id-hmacWithSHA1 OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) rsadsi(113549) 2 7}
+
+-- pkcs-5-algid-hmacWithSHA1 AlgorithmIdentifier ::=
+--   {algorithm pkcs-5-id-hmacWithSHA1, parameters NULL : NULL}
+
+pkcs-5-PBKDF2-params ::= SEQUENCE {
+  salt CHOICE {
+    specified OCTET STRING,
+    otherSource AlgorithmIdentifier
+  },
+  iterationCount INTEGER (1..MAX),
+  keyLength INTEGER (1..MAX) OPTIONAL,
+  prf AlgorithmIdentifier OPTIONAL -- DEFAULT pkcs-5-id-hmacWithSHA1 
+}
+
+-- PKCS #12 stuff
+
+pkcs-12	OBJECT IDENTIFIER ::= {pkcs 12}
+
+pkcs-12-PFX ::= SEQUENCE {
+    	version		INTEGER {v3(3)},
+    	authSafe	pkcs-7-ContentInfo,
+    	macData    	pkcs-12-MacData OPTIONAL
+}
+
+pkcs-12-PbeParams ::= SEQUENCE {
+	salt	OCTET STRING,
+	iterations INTEGER
+}
+
+pkcs-12-MacData ::= SEQUENCE {
+    	mac 		pkcs-7-DigestInfo,
+	macSalt	        OCTET STRING,
+	iterations	INTEGER DEFAULT 1
+-- Note: The default is for historical reasons and its use is
+-- deprecated. A higher value, like 1024 is recommended.
+}
+
+pkcs-12-AuthenticatedSafe ::= SEQUENCE OF pkcs-7-ContentInfo
+	-- Data if unencrypted
+	-- EncryptedData if password-encrypted
+	-- EnvelopedData if public key-encrypted
+
+pkcs-12-SafeContents ::= SEQUENCE OF pkcs-12-SafeBag
+
+pkcs-12-SafeBag ::= SEQUENCE {
+  	bagId	      	OBJECT IDENTIFIER,
+  	bagValue      	[0] EXPLICIT ANY DEFINED BY badId,
+  	bagAttributes 	SET OF pkcs-12-PKCS12Attribute OPTIONAL
+}
+
+-- Bag types
+
+
+pkcs-12-bagtypes OBJECT IDENTIFIER ::= {pkcs-12 10 1}
+
+pkcs-12-keyBag OBJECT IDENTIFIER ::= {pkcs-12-bagtypes 1}
+pkcs-12-pkcs8ShroudedKeyBag OBJECT IDENTIFIER ::= {pkcs-12-bagtypes 2}
+pkcs-12-certBag OBJECT IDENTIFIER ::= {pkcs-12-bagtypes 3}
+pkcs-12-crlBag OBJECT IDENTIFIER ::= {pkcs-12-bagtypes 4}
+
+pkcs-12-KeyBag ::= pkcs-8-PrivateKeyInfo
+
+-- Shrouded KeyBag
+
+pkcs-12-PKCS8ShroudedKeyBag ::= pkcs-8-EncryptedPrivateKeyInfo
+
+-- CertBag
+
+pkcs-12-CertBag ::= SEQUENCE {
+	certId    OBJECT IDENTIFIER,
+	certValue [0] EXPLICIT ANY DEFINED BY certId
+}
+
+-- x509Certificate BAG-TYPE ::= {OCTET STRING IDENTIFIED BY {pkcs-9-certTypes 1}}
+-- DER-encoded X.509 certificate stored in OCTET STRING
+
+pkcs-12-CRLBag ::= SEQUENCE {
+	crlId     	OBJECT IDENTIFIER,
+	crlValue 	[0] EXPLICIT ANY DEFINED BY crlId
+}
+
+-- x509CRL BAG-TYPE ::=
+--	{OCTET STRING IDENTIFIED BY {pkcs-9-crlTypes 1}}
+-- DER-encoded X.509 CRL stored in OCTET STRING
+
+pkcs-12-PKCS12Attribute ::= Attribute
+
+-- PKCS #7 stuff (needed in PKCS 12)
+
+pkcs-7-data OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 1 }
+
+pkcs-7-encryptedData OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+    us(840) rsadsi(113549) pkcs(1) pkcs7(7) 6 }
+
+pkcs-7-Data ::= OCTET STRING
+
+pkcs-7-EncryptedData ::= SEQUENCE {
+    version pkcs-7-CMSVersion,
+    encryptedContentInfo pkcs-7-EncryptedContentInfo,
+    unprotectedAttrs [1] IMPLICIT pkcs-7-UnprotectedAttributes OPTIONAL }
+
+pkcs-7-EncryptedContentInfo ::= SEQUENCE {
+    contentType pkcs-7-ContentType,
+    contentEncryptionAlgorithm pkcs-7-ContentEncryptionAlgorithmIdentifier,
+    encryptedContent [0] IMPLICIT pkcs-7-EncryptedContent OPTIONAL }
+
+pkcs-7-ContentEncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+
+pkcs-7-EncryptedContent ::= OCTET STRING
+
+pkcs-7-UnprotectedAttributes ::= SET SIZE (1..MAX) OF Attribute
+
+-- LDAP stuff
+-- may not be correct
+
+id-at-ldap-DC AttributeType ::= { 0 9 2342 19200300 100 1 25 }
+
+ldap-DC ::= IA5String
+
+id-at-ldap-UID AttributeType ::= { 0 9 2342 19200300 100 1 1 }
+
+ldap-UID ::= DirectoryString
+
+-- rfc3039
+
+id-pda  OBJECT IDENTIFIER ::= { id-pkix 9 }
+
+id-pda-dateOfBirth          AttributeType ::= { id-pda 1 }
+DateOfBirth ::=             GeneralizedTime
+
+id-pda-placeOfBirth         AttributeType ::= { id-pda 2 }
+PlaceOfBirth ::=            DirectoryString
+
+id-pda-gender               AttributeType ::= { id-pda 3 }
+Gender ::=                  PrintableString (SIZE(1))
+                            -- "M", "F", "m" or "f"
+
+id-pda-countryOfCitizenship AttributeType ::= { id-pda 4 }
+CountryOfCitizenship ::=    PrintableString (SIZE (2))
+                            -- ISO 3166 Country Code
+
+id-pda-countryOfResidence   AttributeType ::= { id-pda 5 }
+CountryOfResidence ::=      PrintableString (SIZE (2))
+                            -- ISO 3166 Country Code
+
+END

Modified: trunk/pkcs11/gck/temporary-test.c
==============================================================================
--- trunk/pkcs11/gck/temporary-test.c	(original)
+++ trunk/pkcs11/gck/temporary-test.c	Mon Dec 22 20:21:06 2008
@@ -1,6 +1,30 @@
 
 #include "gck-crypto.h"
+
 #include <stdlib.h>
+#include <pthread.h>
+
+#include "common/gkr-secure-memory.h"
+
+static pthread_mutex_t memory_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+void
+gkr_memory_lock (void)
+{
+	pthread_mutex_lock (&memory_mutex);
+}
+
+void
+gkr_memory_unlock (void)
+{
+	pthread_mutex_unlock (&memory_mutex);
+}
+
+void*
+gkr_memory_fallback (void *p, unsigned long sz)
+{
+	return realloc (p, sz);
+}
 
 int 
 main(int argc, char* argv[])

Added: trunk/pkcs11/gck/tests/Makefile.am
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/Makefile.am	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,26 @@
+
+BUILT_SOURCES = \
+	asn1-def-test.h
+
+asn1-def-test.h: test.asn
+	asn1Parser -o asn1-def-test.h test.asn 
+	
+UNIT_AUTO = \
+	unit-test-crypto.c \
+	unit-test-data-asn1.c \
+	unit-test-data-der.c \
+	unit-test-data-openssl.c \
+	unit-test-file-tracker.c \
+	$(BUILT_SOURCES)
+
+UNIT_PROMPT = 
+
+UNIT_LIBS =  \
+	$(top_builddir)/pkcs11/gck/libgck.la \
+	$(top_builddir)/common/libgkr-module-common.la
+
+EXTRA_DIST = \
+	test.asn \
+	test-data
+
+include $(top_srcdir)/tests/gtest.make

Added: trunk/pkcs11/gck/tests/test-data/pem-rsa-enc.key
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/test-data/pem-rsa-enc.key	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,18 @@
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,24522D4CE5F5CD7B
+
+2H/8j0HYUya7LWEUxpgjp/LVcCX7yZB7SoREdoJdcqJEBUMWVxU/2OfVB8EZupmy
+7YHcnn5v1JwwtmAXAtqM9JGlvNWaRr1m4zDrhJn1fY3tu8YGtMR49IOZmOUBK+X+
+IxWAwaFDqLntuGZZnAmRJtgFVYVABEs5yM9zgoCGDaU4WMK3caD7Jnw8jH5m0nqQ
+XiQ1y1dHxFJmAgG0b5h2z7zjQTmmXd3IhXqSqsE/9ryruCCYa0Z7aAN5oAmO89I9
+gOyy3J4h76mTNFfF5btV4Jllwd4LkgGOmm69UxAyUTGzwYJ5gxgB3xFzGBwpVlcu
+72PrQCrjZqZ6rj6cTPGUYzcyMtEw3Xd6mFhApqJpVRZwNWUAMMJwHl2oWwKcIxfV
+y+OftRX6kc+cunrxCkl9aKuHDoJPEq+/Uh+AEXqir+942Vull0WPyuWUjaPKR1xJ
+poYsNfHRWq+klKCggQQL6jwuVbDLhbaXfgaNBQO1XMracgfmnO1PQPw8JSQ5iOkm
+Ybt2oHAEnrEWxZGn1PfRq6Z8HAbBlQpfmG7SMJZdQjlndKA6GR+tN5krKfpj6uak
+0eklm0Nb0YcDzJ3qqHXxIimK3Kh/WRZ1hVTnX4mS9u3HNQMo5Ov6z8OQN+Q45ffi
+ZDFkVwUTEJ+iwmCG7XnxX0v8Bv5LZmAnPu95KQTp4Ds0AZ6Sp+RqxvhnCO25cgWj
++N5jHGzsDk9/Jw7rAHz8pnl3sziNBWdAk5ASPA28HCQQo5peWnWajM3Pk98+/wHY
+blTh7gw77gTake6hpiegnhNUXwGm6BXEqmyu7mPW0z5XFRb9W7bpog==
+-----END RSA PRIVATE KEY-----

Added: trunk/pkcs11/gck/tests/test.asn
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/test.asn	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,18 @@
+TEST { }
+
+DEFINITIONS EXPLICIT TAGS ::=
+
+BEGIN
+
+TestIntegers ::= SEQUENCE {
+	uint1                   INTEGER,
+	uint2			INTEGER,
+	uint3			INTEGER,
+	mpi                     INTEGER
+}
+
+TestData ::= SEQUENCE {
+	data			OCTET STRING
+}
+
+END

Added: trunk/pkcs11/gck/tests/unit-test-crypto.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-crypto.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,297 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-crypto.c: Test crypto stuff
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "run-auto-test.h"
+
+#include "gck/gck-crypto.h"
+
+#include <gcrypt.h>
+
+DEFINE_SETUP(crypto_setup)
+{
+	gck_crypto_initialize ();
+}
+
+const static struct {
+	const gchar *password;
+	int cipher_algo;
+	int hash_algo;
+	int iterations;
+	const gchar *salt;
+	
+	const gchar *result_simple;
+	const gchar *result_pkcs12;
+	const gchar *result_pbkdf2;
+	const gchar *result_pbe;
+} all_generation_tests[] = {
+	
+	{ /* 24 byte output */
+		"booo", GCRY_CIPHER_3DES, GCRY_MD_MD5, 1, 
+		"\x70\x4C\xFF\xD6\x2F\xBA\x03\xE9", 
+		"\x84\x12\xBB\x34\x94\x8C\x40\xAD\x97\x57\x96\x74\x5B\x6A\xFB\xF8\xD6\x61\x33\x51\xEA\x8C\xCF\xD8", 
+		NULL,
+		NULL,
+		NULL
+        },
+
+	{ /* 5 byte output */
+		"booo", GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 2048, 
+		"\x8A\x58\xC2\xE8\x7C\x1D\x80\x11",
+		NULL,
+		"\xD6\xA6\xF0\x76\x66",
+		NULL,
+		NULL
+	},
+	
+	{ /* Null Password, 5 byte output */
+		NULL, GCRY_CIPHER_RFC2268_40, GCRY_MD_SHA1, 2000,
+		"\x04\xE0\x1C\x3E\xF8\xF2\xE9\xFD",
+		NULL,
+		"\x98\x7F\x20\x97\x1E",
+		NULL,
+		NULL
+	},
+        
+	{ /* 24 byte output */
+		"booo", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048,
+		"\xBD\xEE\x0B\xC6\xCF\x43\xAC\x25",
+		NULL,
+		"\x3F\x38\x1B\x0E\x87\xEB\x19\xBE\xD1\x39\xDC\x5B\xC2\xD2\xB3\x3C\x35\xA8\xB8\xF9\xEE\x66\x48\x94",
+		"\x20\x25\x90\xD8\xD6\x98\x3E\x71\x10\x17\x1F\x51\x49\x87\x27\xCA\x97\x27\xD1\xC9\x72\xF8\x11\xBB",
+		NULL
+	},
+
+	{ /* Empty password, 24 byte output */
+		"", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048,
+		"\xF7\xCF\xD9\xCF\x1F\xF3\xAD\xF6",
+		NULL,
+		NULL,
+		"\x53\xE3\x35\x9E\x5D\xC1\x85\x1A\x71\x3A\x67\x4E\x80\x56\x13\xD6\x4E\x3E\x89\x43\xB7\x1D\x5F\x7F",
+		NULL
+	},
+
+	{ /* Empty password, 24 byte output */
+		"", GCRY_CIPHER_3DES, GCRY_MD_SHA1, 2048,
+		"\xD9\xB3\x2E\xC7\xBA\x1A\x8E\x15",
+		NULL,
+		"\x39\x70\x75\x7C\xF5\xE2\x13\x0B\x5D\xC2\x9D\x96\x8B\x71\xC7\xFC\x5B\x97\x1F\x79\x9F\x06\xFC\xA2",
+		NULL,
+		NULL
+	},
+	
+	{ /* 8 byte output */
+		"booo", GCRY_CIPHER_DES, GCRY_MD_MD5, 2048,
+		"\x93\x4C\x3D\x29\xA2\x42\xB0\xF5",
+		NULL, 
+		NULL,
+		NULL,
+		"\x8C\x67\x19\x7F\xB9\x23\xE2\x8D"
+	}
+};
+
+#define N_GENERATION_TESTS (sizeof (all_generation_tests) / sizeof (all_generation_tests[0]))
+
+DEFINE_TEST(generate_key_simple)
+{
+	int i;
+	gboolean ret;
+	guchar *key;
+	
+	for (i = 0; i < N_GENERATION_TESTS; ++i) {
+		
+		if (!all_generation_tests[i].result_simple)
+			continue;
+		
+		ret = gck_crypto_symkey_generate_simple (all_generation_tests[i].cipher_algo, 
+                                                         all_generation_tests[i].hash_algo,
+                                                         all_generation_tests[i].password,
+                                                         (guchar*)all_generation_tests[i].salt, 8,
+                                                         all_generation_tests[i].iterations,
+                                                         &key, NULL);
+		g_assert (ret && "key generation failed");
+
+		ret = (memcmp (key, all_generation_tests[i].result_simple, 
+		               gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0);
+
+		g_assert (ret && "invalid simple key generated"); 
+	}
+}
+
+DEFINE_TEST(generate_key_pkcs12)
+{
+	int i;
+	gboolean ret;
+	guchar *key;
+	
+	for (i = 0; i < N_GENERATION_TESTS; ++i) {
+		
+		if (!all_generation_tests[i].result_pkcs12)
+			continue;
+		
+		ret = gck_crypto_symkey_generate_pkcs12 (all_generation_tests[i].cipher_algo, 
+                                                         all_generation_tests[i].hash_algo,
+                                                         all_generation_tests[i].password,
+                                                         (guchar*)all_generation_tests[i].salt, 8,
+                                                         all_generation_tests[i].iterations,
+                                                         &key, NULL);
+		g_assert ("failed to generate pkcs12 key" && ret);
+		
+		ret = (memcmp (key, all_generation_tests[i].result_pkcs12, 
+			        gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0);
+			
+		g_assert ("invalid pkcs12 key generated" && ret); 
+	}
+}
+
+DEFINE_TEST(generate_key_pbkdf2)
+{
+	int i;
+	gboolean ret;
+	guchar *key;
+	
+	for (i = 0; i < N_GENERATION_TESTS; ++i) {
+		
+		if (!all_generation_tests[i].result_pbkdf2)
+			continue;
+		
+		ret = gck_crypto_symkey_generate_pbkdf2 (all_generation_tests[i].cipher_algo, 
+                                                         all_generation_tests[i].hash_algo,
+                                                         all_generation_tests[i].password,
+                                                         (guchar*)all_generation_tests[i].salt, 8,
+                                                         all_generation_tests[i].iterations,
+                                                         &key, NULL);
+		g_assert ("failed to generate pbkdf2 key" && ret);
+			
+		ret = (memcmp (key, all_generation_tests[i].result_pbkdf2, 
+			        gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0);
+		
+		g_assert ("invalid pbkdf2 key generated" && ret); 
+	}
+}
+
+DEFINE_TEST(generate_key_pbe)
+{
+	int i;
+	gboolean ret;
+	guchar *key;
+	
+	for (i = 0; i < N_GENERATION_TESTS; ++i) {
+		
+		if (!all_generation_tests[i].result_pbe)
+			continue;
+		
+		ret = gck_crypto_symkey_generate_pbe (all_generation_tests[i].cipher_algo, 
+                                                      all_generation_tests[i].hash_algo,
+                                                      all_generation_tests[i].password,
+                                                      (guchar*)all_generation_tests[i].salt, 8,
+                                                      all_generation_tests[i].iterations,
+                                                      &key, NULL);
+		g_assert ("failed to generate pbe key" && ret);
+		
+		ret = (memcmp (key, all_generation_tests[i].result_pbe, 
+			        gcry_cipher_get_algo_keylen (all_generation_tests[i].cipher_algo)) == 0);
+			
+		g_assert ("invalid pbe key generated" && ret); 
+			
+	}
+}
+
+#if 0
+#define TEST_KEY \
+"(private-key (rsa " \
+"(n  #00B78758D55EBFFAB61D07D0DC49B5309A6F1DA2AE51C275DFC2370959BB81AC0C39093B1C618E396161A0DECEB8768D0FFB14F197B96C3DA14190EE0F20D51315#)" \
+"(e #010001#)" \
+"(d #108BCAC5FDD35812981E6EC5957D98E2AB76E4064C47B861D27C2CC322C50792313C852B4164A035B42D261F1A09F9FFE8F477F9F78FF2EABBDA6BA875C671D7#)" \
+"(p #00C357F11B19A18C66573D25D1E466D9AB8BCDDCDFE0B2E80BD46712C4BEC18EB7#)" \
+"(q #00F0843B90A60EF7034CA4BE80414ED9497CABCC685143B388013FF989CBB0E093#)" \
+"(u #12F2555F52EB56329A991CF0404B51C68AC921AD370A797860F550415FF987BD#)" \
+"))"
+
+gcry_sexp_t thekey = NULL;
+
+void unit_test_parse_key (CuTest *cu)
+{
+	gcry_sexp_t sexp = NULL;
+	gcry_error_t gcry;
+	gcry_mpi_t mpi = NULL;
+	gboolean ret;
+	gboolean is_priv = FALSE;
+	int algorithm = 0;
+	
+	gcry = gcry_sexp_new (&sexp, TEST_KEY, strlen (TEST_KEY), 1);
+	g_return_if_fail (gcry == 0);
+	
+	/* Get the private key out */
+	thekey = gkr_crypto_sexp_get_child (sexp, "private-key", NULL);
+	CuAssert (cu, "couldn't extract private key", sexp != NULL);
+	
+	ret = gkr_crypto_skey_parse (thekey, &algorithm, &is_priv, &sexp);
+	CuAssert (cu, "couldn't parse rsa key", ret);
+	CuAssert (cu, "parsed bad algorithm", algorithm == GCRY_PK_RSA);
+	CuAssert (cu, "not a private-key", is_priv == TRUE);
+	CuAssert (cu, "didn't get numbers", sexp != NULL);
+	
+	ret = gkr_crypto_sexp_extract_mpi (sexp, &mpi, "p", NULL);
+	CuAssert (cu, "couldn't extract mpi from key", ret);
+	CuAssert (cu, "no mpi returned from extract", mpi != NULL);
+}
+
+void unit_test_make_keyid (CuTest *cu)
+{
+	guchar hash[20];
+	gkrid id;
+	const guchar *p;
+	gsize n;
+	
+	p = gcry_pk_get_keygrip (thekey, hash);
+	g_return_if_fail (p == hash);
+	
+	id = gkr_crypto_skey_make_id (thekey);
+	CuAssert (cu, "null returned as key id", id != NULL);
+	
+	p = gkr_id_get_raw (id, &n);
+	CuAssert (cu, "key id is of wrong length", n == sizeof (hash));
+	CuAssert (cu, "key grip doesn't match key id", memcmp (hash, p, n) == 0);	
+}
+
+void unit_test_key_to_public (CuTest *cu)
+{
+	gcry_sexp_t pubkey = NULL;
+	gboolean ret;
+	gkrid u1, u2;
+	
+	ret = gkr_crypto_skey_private_to_public (thekey, &pubkey);
+	CuAssert (cu, "couldn't make public key", ret);
+	CuAssert (cu, "returned null public key", pubkey != NULL);
+	
+	u1 = gkr_crypto_skey_make_id (thekey);
+	u2 = gkr_crypto_skey_make_id (pubkey);
+	CuAssert (cu, "public and private keys are not equivalent", 
+	          gkr_id_equals (u1, u2)); 
+}	
+
+#endif

Added: trunk/pkcs11/gck/tests/unit-test-data-asn1.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-data-asn1.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,251 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-pkix-parser.c: Test PKIX parser
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "run-auto-test.h"
+
+#include "gck/gck-data-asn1.h"
+
+#include <glib.h>
+#include <gcrypt.h>
+#include <libtasn1.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define extern 
+#include "asn1-def-test.h"
+#undef extern
+
+ASN1_TYPE asn1_test = NULL;
+
+DEFINE_SETUP(asn1_tree)
+{
+	int res = asn1_array2tree (test_asn1_tab, &asn1_test, NULL);
+	g_assert (res == ASN1_SUCCESS);
+}
+
+DEFINE_TEARDOWN(asn1_tree)
+{
+	asn1_delete_structure (&asn1_test);
+}
+
+DEFINE_TEST(asn1_types)
+{
+	ASN1_TYPE asn;
+	
+	asn = gck_data_asn1_get_pk_asn1type ();
+	g_assert ("pk asn type is null" && asn != NULL);
+
+	asn = gck_data_asn1_get_pkix_asn1type ();
+	g_assert ("pkix asn type is null" && asn != NULL);
+}
+
+DEFINE_TEST(asn1_integers)
+{
+	ASN1_TYPE asn;
+	gcry_mpi_t mpi, mpt;
+	guchar *data;
+	gsize n_data;
+	gboolean ret;
+	guint val;
+	int res;
+	
+	res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn);
+	g_assert ("asn test structure is null" && asn != NULL);
+
+	ret = gck_data_asn1_write_uint (asn, "uint1", 35);
+	g_assert ("couldn't write integer" && ret);
+	
+	ret = gck_data_asn1_write_uint (asn, "uint2", 23456);
+	g_assert ("couldn't write integer" && ret);
+	
+	ret = gck_data_asn1_write_uint (asn, "uint3", 209384022);
+	g_assert ("couldn't write integer" && ret);
+	
+	/* Make a random number */
+	mpi = gcry_mpi_new (512);
+	g_return_if_fail (mpi);
+	gcry_mpi_randomize (mpi, 512, GCRY_WEAK_RANDOM);
+	
+	/* Write the mpi out */
+	ret = gck_data_asn1_write_mpi (asn, "mpi", mpi);
+	
+	/* Now encode the whole caboodle */
+	data = gck_data_asn1_encode (asn, "", &n_data, NULL);
+	g_assert ("encoding asn1 didn't work" && data != NULL);
+	
+	asn1_delete_structure (&asn);
+	
+	/* Now decode it all nicely */
+	res = asn1_create_element (asn1_test, "TEST.TestIntegers", &asn); 
+	g_return_if_fail (res == ASN1_SUCCESS);
+	
+	res = asn1_der_decoding (&asn, data, n_data, NULL);
+	g_assert ("decoding asn didn't work" && res == ASN1_SUCCESS);
+	
+	/* And get out the values */
+	ret = gck_data_asn1_read_uint (asn, "uint1", &val);
+	g_assert ("couldn't read integer from asn1" && ret);
+	g_assert_cmpuint (val, ==, 35);
+	
+	ret = gck_data_asn1_read_uint (asn, "uint2", &val);
+	g_assert ("couldn't read integer from asn1" && ret);
+	g_assert_cmpuint (val, ==, 23456);
+
+	ret = gck_data_asn1_read_uint (asn, "uint3", &val);
+	g_assert ("couldn't read integer from asn1" && ret);
+	g_assert_cmpuint (val, ==, 209384022);
+	
+	ret = gck_data_asn1_read_mpi (asn, "mpi", &mpt);
+	g_assert ("couldn't read mpi from asn1" && ret);
+	g_assert ("mpi returned is null" && mpt != NULL);
+	g_assert ("mpi is wrong number" && gcry_mpi_cmp (mpi, mpt) == 0);
+}
+
+DEFINE_TEST(write_value)
+{
+	ASN1_TYPE asn = NULL;
+	guchar *data;
+	gsize n_data;
+	int res;
+		
+	res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+	g_assert ("asn test structure is null" && asn != NULL);
+		
+	if (!gck_data_asn1_write_value (asn, "data", (const guchar*)"SOME DATA", 9))
+		g_assert_not_reached ();
+
+	data = gck_data_asn1_read_value (asn, "data", &n_data, NULL);
+	g_assert (data != NULL);
+	g_assert_cmpuint (n_data, ==, 9);
+	g_assert (memcmp (data, "SOME DATA", 9) == 0);
+	g_free (data);
+	
+	asn1_delete_structure (&asn); 
+}
+
+DEFINE_TEST(element_length_content)
+{
+	ASN1_TYPE asn = NULL;
+	guchar buffer[1024];
+	const guchar *content;
+	gsize n_content;
+	gint length;
+	int res;
+	
+	res = asn1_create_element (asn1_test, "TEST.TestData", &asn);
+	g_assert ("asn test structure is null" && asn != NULL);
+	
+	res = asn1_write_value (asn, "data", "SOME DATA", 9);
+	g_assert (res == ASN1_SUCCESS);
+	
+	length = 1024;
+	res = asn1_der_coding (asn, "", buffer, &length, NULL);
+	g_assert (res == ASN1_SUCCESS);
+	
+	/* Now the real test */
+	length = gck_data_asn1_element_length (buffer, 1024);
+	g_assert_cmpint (length, ==, 13);
+	
+	content = gck_data_asn1_element_content (buffer, length, &n_content);
+	g_assert (content);
+	g_assert_cmpuint (n_content, ==, 11);
+	
+	content = gck_data_asn1_element_content (content, n_content, &n_content);
+	g_assert (content);
+	g_assert_cmpuint (n_content, ==, 9);	
+	g_assert (memcmp (content, "SOME DATA", 9) == 0);
+}
+
+typedef struct _TimeTestData {
+	gchar *value;
+	time_t ref;
+} TimeTestData;
+
+static const TimeTestData generalized_time_test_data[] = {
+	{ "20070725130528Z", 1185368728 },
+	{ "20070725130528.2134Z", 1185368728 },
+	{ "20070725140528-0100", 1185368728 },
+	{ "20070725040528+0900", 1185368728 },
+	{ "20070725013528+1130", 1185368728 },
+	{ "20070725Z", 1185321600 },
+	{ "20070725+0000", 1185321600 },
+	{ NULL, 0 }
+};
+
+static const TimeTestData utc_time_test_data[] = {
+	/* Test the Y2K style wrap arounds */
+	{ "070725130528Z", 1185368728 },  /* The year 2007 */
+	{ "020725130528Z", 1027602328 },  /* The year 2002 */
+	{ "970725130528Z", 869835928 },	  /* The year 1997 */
+	{ "370725130528Z", 2132139928 },  /* The year 2037 */
+	
+	/* Test the time zones and other formats */
+	{ "070725130528.2134Z", 1185368728 },
+	{ "070725140528-0100", 1185368728 },
+	{ "070725040528+0900", 1185368728 },
+	{ "070725013528+1130", 1185368728 },
+	{ "070725Z", 1185321600 },
+	{ "070725+0000", 1185321600 },
+	
+	{ NULL, 0 }
+};
+
+DEFINE_TEST(general_time)
+{
+	time_t when;
+	const TimeTestData *data;
+	
+	for (data = generalized_time_test_data; data->value; ++data) {
+		when = gck_data_asn1_parse_general_time (data->value);
+		if (data->ref != when) {
+			printf ("%s", data->value);
+			printf ("%s != ", ctime (&when));
+			printf ("%s\n", ctime (&data->ref));
+			fflush (stdout);
+		}
+			
+		g_assert ("decoded time doesn't match reference" && data->ref == when);
+	}
+}
+
+DEFINE_TEST(utc_time)
+{
+	time_t when;
+	const TimeTestData *data;
+	
+	for (data = utc_time_test_data; data->value; ++data) {
+		when = gck_data_asn1_parse_utc_time (data->value);
+		if (data->ref != when) {
+			printf ("%s", data->value);
+			printf ("%s != ", ctime (&when));
+			printf ("%s\n", ctime (&data->ref));
+			fflush (stdout);
+		}
+			
+		g_assert ("decoded time doesn't match reference" && data->ref == when);
+	}
+}

Added: trunk/pkcs11/gck/tests/unit-test-data-der.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-data-der.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,190 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-pkix-parser.c: Test PKIX parser
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "run-auto-test.h"
+
+#include "gck/gck-crypto.h"
+#include "gck/gck-data-der.h"
+
+#include <glib.h>
+#include <gcrypt.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+const gchar *rsapub = "(public-key (rsa" \
+" (n #00AE4B381CF43F7DC24CF90827325E2FB2EB57EDDE29562DF391C8942AA8E6423410E2D3FE26381F9DE0395E74BF2D17621AE46992C72CF895F6FA5FBE98054FBF#)" \
+" (e #010001#)))";
+
+const gchar *rsaprv = "(private-key (rsa" \
+" (n #00B78758D55EBFFAB61D07D0DC49B5309A6F1DA2AE51C275DFC2370959BB81AC0C39093B1C618E396161A0DECEB8768D0FFB14F197B96C3DA14190EE0F20D51315#)" \
+" (e #010001#)" \
+" (d #108BCAC5FDD35812981E6EC5957D98E2AB76E4064C47B861D27C2CC322C50792313C852B4164A035B42D261F1A09F9FFE8F477F9F78FF2EABBDA6BA875C671D7#)" \
+" (p #00C357F11B19A18C66573D25D1E466D9AB8BCDDCDFE0B2E80BD46712C4BEC18EB7#)" \
+" (q #00F0843B90A60EF7034CA4BE80414ED9497CABCC685143B388013FF989CBB0E093#)" \
+" (u #12F2555F52EB56329A991CF0404B51C68AC921AD370A797860F550415FF987BD#)))";
+
+const gchar *dsapub = "(public-key (dsa" \
+" (p #0090EC0B60735839C754EAF8F64BB03FC35398D69772BFAE540079DEA2D3A61FAFFB27630A038A01A3D0CD62A10745A574A27ECB462F4F0885B79C61BBE954A60A29668AD54BBA5C07A72FD8B1105249670B339DF2C59E64A47064EFCF0B7236C5C72CD55CEB32917430BEC9A003D4E484FBAA84D79571B38D6B5AC95BB73E3F7B#)" \
+" (q #00FA214A1385C21BFEBAADAB240A2430C607D56271#)" \
+" (g #2DE05751F5DAEE97F3D43C54595A3E94A080728F0C66C98AEBED5762F6AB155802D8359EAD1DE1EC36A459FBEEEA48E59B9E6A8CB4F5295936B3CC881A5D957C7339175E2CFFE0F30D3711E430DB6648C2EB474AA10A4A3297450531FF2C7C6951220C9D446B6B6B0F00262E1EBEB3CC861476AA518CC555C9ABF9E5F39023FC#)" \
+" (y #54734451DB79D4EEDF0BBCEBD43BB6CBB7B8584603B957080075DD318EB5B0266D4B20DC5EFF376BDFC4EA2983B1F7F02A39ED4C619ED68712729FFF3B7C696ADD1B6D748F56A4B4BEC5C4385E528423A3B88AE65E6D5500F97839E7A486255982189C3B4FA8D94338C76F0E5CAFC9A30A1ED728BB9F2091D594E3250A09EA00#)))";
+
+const gchar *dsaprv = "(private-key (dsa" \
+"  (p #0090EC0B60735839C754EAF8F64BB03FC35398D69772BFAE540079DEA2D3A61FAFFB27630A038A01A3D0CD62A10745A574A27ECB462F4F0885B79C61BBE954A60A29668AD54BBA5C07A72FD8B1105249670B339DF2C59E64A47064EFCF0B7236C5C72CD55CEB32917430BEC9A003D4E484FBAA84D79571B38D6B5AC95BB73E3F7B#)" \
+"  (q #00FA214A1385C21BFEBAADAB240A2430C607D56271#)" \
+"  (g #2DE05751F5DAEE97F3D43C54595A3E94A080728F0C66C98AEBED5762F6AB155802D8359EAD1DE1EC36A459FBEEEA48E59B9E6A8CB4F5295936B3CC881A5D957C7339175E2CFFE0F30D3711E430DB6648C2EB474AA10A4A3297450531FF2C7C6951220C9D446B6B6B0F00262E1EBEB3CC861476AA518CC555C9ABF9E5F39023FC#)" \
+"  (y #54734451DB79D4EEDF0BBCEBD43BB6CBB7B8584603B957080075DD318EB5B0266D4B20DC5EFF376BDFC4EA2983B1F7F02A39ED4C619ED68712729FFF3B7C696ADD1B6D748F56A4B4BEC5C4385E528423A3B88AE65E6D5500F97839E7A486255982189C3B4FA8D94338C76F0E5CAFC9A30A1ED728BB9F2091D594E3250A09EA00#)" \
+"  (x #00876F84F709D51108DFB0CBFA1F1C569C09C413EC#)))";
+
+static gboolean
+compare_keys (gcry_sexp_t key, gcry_sexp_t sexp)
+{
+	guchar hash1[20], hash2[20];
+	guchar *p;
+	
+	/* Now compare them */
+	p = gcry_pk_get_keygrip (key, hash1);
+	g_assert ("couldn't get key id for private key" && p == hash1);
+	p = gcry_pk_get_keygrip (key, hash2);
+	g_assert ("couldn't get key id for parsed private key" && p == hash2);
+
+	return memcmp (hash1, hash2, 20) == 0;
+}
+
+static void
+test_der_public (gcry_sexp_t key)
+{
+	guchar *data;
+	gsize n_data;
+	GckDataResult ret;
+	gcry_sexp_t sexp;
+		
+	/* Encode it */
+	data = gck_data_der_write_public_key (key, &n_data);
+	g_assert ("couldn't encode public key" && data != NULL);
+	g_assert ("encoding is empty" && n_data > 0);
+	
+	/* Now parse it */
+	ret = gck_data_der_read_public_key (data, n_data, &sexp);
+	g_assert ("couldn't decode public key" && ret == GCK_DATA_SUCCESS);
+	g_assert ("parsed key is empty" && sexp != NULL);
+	
+	/* Now compare them */
+	g_assert ("key parsed differently" && compare_keys (key, sexp)); 	
+}
+
+DEFINE_TEST(der_rsa_public)
+{
+	gcry_sexp_t key;
+	gcry_error_t gcry;
+	
+	gcry = gcry_sexp_sscan (&key, NULL, rsapub, strlen (rsapub));
+	g_return_if_fail (gcry == 0);
+
+	test_der_public (key);	
+}
+
+DEFINE_TEST(der_dsa_public)
+{
+	gcry_sexp_t key;
+	gcry_error_t gcry;
+	
+	gcry = gcry_sexp_sscan (&key, NULL, dsapub, strlen (dsapub));
+	g_return_if_fail (gcry == 0);
+
+	test_der_public (key);	
+}
+
+static void
+test_der_private (gcry_sexp_t key)
+{
+	guchar *data;
+	gsize n_data;
+	GckDataResult ret;
+	gcry_sexp_t sexp;
+
+	/* Encode it */
+	data = gck_data_der_write_private_key (key, &n_data);
+	g_assert ("couldn't encode private key" && data != NULL);
+	g_assert ("encoding is empty" && n_data > 0);
+	
+	/* Now parse it */
+	ret = gck_data_der_read_private_key (data, n_data, &sexp);
+	g_assert ("couldn't decode private key" && ret == GCK_DATA_SUCCESS);
+	g_assert ("parsed key is empty" && sexp != NULL);
+	
+	/* Now compare them */
+	g_assert ("key parsed differently" && compare_keys (key, sexp)); 	
+}
+
+DEFINE_TEST(der_rsa_private)
+{
+	gcry_sexp_t key;
+	gcry_error_t gcry;
+	
+	gcry = gcry_sexp_sscan (&key, NULL, rsaprv, strlen (rsaprv));
+	g_return_if_fail (gcry == 0);
+	
+	test_der_private (key);
+}
+
+DEFINE_TEST(der_dsa_private)
+{
+	gcry_sexp_t key;
+	gcry_error_t gcry;
+	
+	gcry = gcry_sexp_sscan (&key, NULL, dsaprv, strlen (dsaprv));
+	g_return_if_fail (gcry == 0);
+	
+	test_der_private (key);
+}
+
+DEFINE_TEST(der_dsa_private_parts)
+{
+	guchar *params, *key;
+	gsize n_params, n_key;
+	gcry_sexp_t skey, pkey;
+	gcry_error_t gcry;
+	GckDataResult result;
+	
+	gcry = gcry_sexp_sscan (&skey, NULL, dsaprv, strlen (dsaprv));
+	g_return_if_fail (gcry == 0);
+	
+	/* Encode the the dsa key by parts */
+	params = gck_data_der_write_private_key_dsa_params (skey, &n_params);
+	g_assert ("didn't encode dsa params" && params != NULL);
+	key = gck_data_der_write_private_key_dsa_part (skey, &n_key);
+	g_assert ("didn't encode dsa key" && key != NULL);
+	
+	/* Parse the dsa key by parts */
+	result = gck_data_der_read_private_key_dsa_parts (key, n_key, params, n_params, &pkey);
+	g_assert ("couldn't parse dsa parts" && result == GCK_DATA_SUCCESS);
+	g_assert ("parsing dsa parts resulted in null key" && pkey != NULL);
+	
+	/* Now compare them */
+	g_assert ("key parsed differently" && compare_keys (skey, pkey)); 	
+}

Added: trunk/pkcs11/gck/tests/unit-test-data-openssl.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-data-openssl.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,153 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-pkix-openssl.c: Test PKIX openssl
+
+   Copyright (C) 2008 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include "config.h"
+
+#include "run-auto-test.h"
+
+#include "common/gkr-secure-memory.h"
+
+#include "gck/gck-crypto.h"
+#include "gck/gck-data-pem.h"
+#include "gck/gck-data-openssl.h"
+
+#include <glib.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+static void
+read_file (const gchar *filename, guchar **contents, gsize *len)
+{
+	gchar *path;
+	gboolean ret;
+	
+	path = g_build_filename (g_get_current_dir (), "test-data", filename, NULL);
+	ret = g_file_get_contents (path, (gchar**)contents, len, NULL);
+	g_assert ("couldn't read in file" && ret);
+	
+	g_free (path);
+}
+
+guchar *refenc = NULL;
+guchar *refdata = NULL;
+gsize n_refenc = 0;
+gsize n_refdata = 0;
+GHashTable *refheaders = NULL;
+
+static void
+copy_each_key_value (gpointer key, gpointer value, gpointer user_data)
+{
+	g_hash_table_insert ((GHashTable*)user_data, g_strdup ((gchar*)key), g_strdup ((gchar*)value));
+}
+
+static void
+parse_reference (GQuark type, const guchar *data, gsize n_data,
+                 GHashTable *headers, gpointer user_data)
+{
+	GckDataResult res;
+	const gchar *dekinfo;
+	
+	g_assert ("no data in PEM callback" && data != NULL);
+	g_assert ("no data in PEM callback" && n_data > 0);
+	refenc = g_memdup (data, n_data);
+	n_refenc = n_data;
+	
+	g_assert ("no headers present in file" && headers != NULL);
+	refheaders = gck_data_pem_headers_new ();
+	g_hash_table_foreach (headers, copy_each_key_value, refheaders);
+	dekinfo = gck_data_openssl_get_dekinfo (headers);
+	g_assert ("no dekinfo in headers" && dekinfo != NULL);
+	
+	res = gck_data_openssl_decrypt_block (dekinfo, "booo", data, n_data, &refdata, &n_refdata);
+	g_assert ("couldn't openssl decrypt block" && res == GCK_DATA_SUCCESS);
+	g_assert ("no data returned from openssl decrypt" && refdata != NULL);
+	g_assert ("invalid amount of data returned from openssl decrypt" && n_refdata == n_data);
+}
+
+DEFINE_TEST(parse_reference)
+{
+	guchar *input;
+	gsize n_input;
+	guint num;
+	
+	read_file ("pem-rsa-enc.key", &input, &n_input);
+
+	num = gck_data_pem_parse (input, n_input, parse_reference, NULL);
+	g_assert ("couldn't PEM block in reference data" && num == 1);
+	
+	g_assert ("parse_reference() wasn't called" && refdata != NULL);
+}
+
+DEFINE_TEST(write_reference)
+{
+	const gchar *dekinfo;
+	guchar *encrypted;
+	gsize n_encrypted;
+	gboolean ret;
+	
+	dekinfo = gck_data_openssl_get_dekinfo (refheaders); 
+	g_assert ("no dekinfo in headers" && dekinfo != NULL);
+
+	ret = gck_data_openssl_encrypt_block (dekinfo, "booo", refdata, n_refdata, &encrypted, &n_encrypted);
+	g_assert ("couldn't openssl encrypt block" && ret == TRUE);
+	g_assert ("no data returned from openssl encrypt" && encrypted != NULL);
+	g_assert ("invalid amount of data returned from openssl encrypt" && n_refdata <= n_encrypted);
+	
+	g_assert ("data length doesn't match input length" && n_encrypted == n_refenc);
+	g_assert ("data doesn't match input" && memcmp (encrypted, refenc, n_encrypted) == 0);
+}
+
+/* 29 bytes (prime number, so block length has bad chance of matching */
+const static guchar *TEST_DATA = (guchar*)"ABCDEFGHIJKLMNOPQRSTUVWXYZ123";
+const gsize TEST_DATA_L = 29;
+	
+DEFINE_TEST(openssl_roundtrip)
+{
+	const gchar *dekinfo;
+	GckDataResult res;
+	gboolean ret;
+	guchar *encrypted, *decrypted;
+	gsize n_encrypted, n_decrypted;
+	int i;
+	
+	dekinfo = gck_data_openssl_prep_dekinfo (refheaders);
+	
+	ret = gck_data_openssl_encrypt_block (dekinfo, "password", TEST_DATA, TEST_DATA_L, &encrypted, &n_encrypted);
+	g_assert ("couldn't openssl encrypt block" && ret == TRUE);
+	g_assert ("no data returned from openssl encrypt" && encrypted != NULL);
+	g_assert ("invalid amount of data returned from openssl encrypt" && TEST_DATA_L <= n_encrypted);
+
+	res = gck_data_openssl_decrypt_block (dekinfo, "password", encrypted, n_encrypted, &decrypted, &n_decrypted);
+	g_assert ("couldn't openssl decrypt block" && res == GCK_DATA_SUCCESS);
+	g_assert ("no data returned from openssl decrypt" && decrypted != NULL);
+
+	/* Check that the data was decrypted properly */
+	g_assert ("decrypted data doesn't match length" && n_decrypted >= TEST_DATA_L);
+	g_assert ("decrypted data doesn't match" && memcmp (TEST_DATA, decrypted, TEST_DATA_L) == 0);
+	
+	/* Check that the remainder is all zeros */
+	for (i = TEST_DATA_L; i < n_decrypted; ++i)
+		g_assert ("non null byte in padding" && decrypted[i] == 0);
+}

Added: trunk/pkcs11/gck/tests/unit-test-file-tracker.c
==============================================================================
--- (empty file)
+++ trunk/pkcs11/gck/tests/unit-test-file-tracker.c	Mon Dec 22 20:21:06 2008
@@ -0,0 +1,221 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/* unit-test-location.c: Test location functionality
+
+   Copyright (C) 2007 Stefan Walter
+
+   The Gnome Keyring Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   The Gnome Keyring Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Library General Public License for more details.
+
+   You should have received a copy of the GNU Library General Public
+   License along with the Gnome Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.
+
+   Author: Stef Walter <stef memberwebs com>
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "run-auto-test.h"
+
+#include "gck/gck-file-tracker.h"
+
+#include <glib/gstdio.h>
+
+#define DATA "test-data"
+#define SUBDIR "test-subdir"
+#define WILDCARD "*.woo?"
+
+static GckFileTracker *the_tracker = NULL;
+static gchar *test_dir = NULL;
+static gchar *test_file = NULL;
+
+static guint n_files_added = 0;
+static gchar* last_file_added = 0;
+
+static guint n_files_changed = 0;
+static gchar* last_file_changed = 0;
+
+static guint n_files_removed = 0;
+static gchar* last_file_removed = 0;
+
+static void
+file_added (GckFileTracker *tracker, const gchar *path, gpointer unused)
+{
+	g_assert ("should be a non-null path" && path != NULL);
+	
+	++n_files_added;
+	g_free (last_file_added);
+	last_file_added = g_strdup (path);
+}
+
+static void
+file_changed (GckFileTracker *tracker, const gchar *path, gpointer unused)
+{
+	g_assert ("should be a non-null path" && path != NULL);
+	
+	++n_files_changed;
+	g_free (last_file_changed);
+	last_file_changed = g_strdup (path);
+}
+
+static void
+file_removed (GckFileTracker *tracker, const gchar *path, gpointer unused)
+{
+	g_assert ("should be a non-null path" && path != NULL);
+	
+	++n_files_removed;
+	g_free (last_file_removed);
+	last_file_removed = g_strdup (path);
+}
+
+static void
+file_reset_stats (void)
+{
+	g_free (last_file_removed);
+	g_free (last_file_added);
+	g_free (last_file_changed);
+	last_file_removed = last_file_added = last_file_changed = NULL;
+	n_files_added = n_files_changed = n_files_removed = 0;
+}
+
+DEFINE_SETUP(tracker)
+{
+	/* Make a test directory */
+	test_dir = g_build_filename ("/tmp", SUBDIR, NULL);
+	
+	the_tracker = gck_file_tracker_new (test_dir, WILDCARD, NULL);
+	g_signal_connect (the_tracker, "file-added", G_CALLBACK (file_added), NULL); 
+	g_signal_connect (the_tracker, "file-removed", G_CALLBACK (file_removed), NULL); 
+	g_signal_connect (the_tracker, "file-changed", G_CALLBACK (file_changed), NULL);
+	
+	/* Mtime must change so wait between tests */
+	sleep (1);
+	
+	test_file = g_build_filename (test_dir, "my-file.woof", NULL);
+	g_unlink (test_file);
+}
+
+DEFINE_TEARDOWN(tracker)
+{
+	file_reset_stats ();
+	g_object_unref (the_tracker);
+	g_free (test_dir);
+	g_free (test_file);
+}
+
+DEFINE_TEST(file_watch)
+{
+	/* A watch for an non-existant directory, should have no responses */
+	gck_file_tracker_refresh (the_tracker, FALSE);
+	
+	g_assert_cmpint (0, ==, n_files_added);
+	g_assert_cmpint (0, ==, n_files_changed);
+	g_assert_cmpint (0, ==, n_files_removed);
+	
+	g_mkdir_with_parents (test_dir, 0700);
+	
+	/* Should still have no responses even though it exists */
+	gck_file_tracker_refresh (the_tracker, FALSE);
+	
+	g_assert_cmpint (0, ==, n_files_added);
+	g_assert_cmpint (0, ==, n_files_changed);
+	g_assert_cmpint (0, ==, n_files_removed);	
+}
+
+DEFINE_TEST(watch_file)
+{
+	gboolean ret;
+
+	/* Make sure things are clean */
+	gck_file_tracker_refresh (the_tracker, FALSE);
+	
+	n_files_added = n_files_changed = n_files_removed = 0;
+	last_file_added = last_file_changed = last_file_removed = 0;
+
+	ret = g_file_set_contents (test_file, DATA, strlen (DATA), NULL);
+	g_assert (ret);
+	
+	/* Now make sure that file is located */
+	gck_file_tracker_refresh (the_tracker, FALSE);
+	
+	g_assert_cmpint (1, ==, n_files_added);
+	g_assert_cmpint (0, ==, n_files_changed);
+	g_assert_cmpint (0, ==, n_files_removed);	
+	
+	/* The added one should match our file */
+	g_assert_cmpstr (last_file_added, ==, test_file);
+	
+	file_reset_stats ();
+	sleep (1);
+	
+	/* Shouldn't find the file again */
+	gck_file_tracker_refresh (the_tracker, FALSE);
+	g_assert_cmpint (0, ==, n_files_added);
+	g_assert_cmpint (0, ==, n_files_changed);
+	g_assert_cmpint (0, ==, n_files_removed);	
+	
+	/* But we should find the file if forced to */	
+	gck_file_tracker_refresh (the_tracker, TRUE);
+	g_assert_cmpint (0, ==, n_files_added);
+	g_assert_cmpint (1, ==, n_files_changed);
+	g_assert_cmpint (0, ==, n_files_removed);
+	g_assert_cmpstr (last_file_changed, ==, test_file);	
+
+	file_reset_stats ();
+
+	ret = g_file_set_contents (test_file, DATA, strlen (DATA), NULL);
+	g_assert (ret);
+
+	/* File was updated */
+	gck_file_tracker_refresh (the_tracker, FALSE);
+	g_assert_cmpint (0, ==, n_files_added);
+	g_assert_cmpint (1, ==, n_files_changed);
+	g_assert_cmpint (0, ==, n_files_removed);	
+	g_assert_cmpstr (last_file_changed, ==, test_file);	
+
+	file_reset_stats ();
+	g_unlink (test_file);
+	
+	/* Now file should be removed */
+	gck_file_tracker_refresh (the_tracker, FALSE);
+
+	g_assert_cmpint (0, ==, n_files_added);
+	g_assert_cmpint (0, ==, n_files_changed);
+	g_assert_cmpint (1, ==, n_files_removed);	
+	g_assert_cmpstr (last_file_removed, ==, test_file);	
+}
+
+DEFINE_TEST(nomatch)
+{
+	gchar *file = g_build_filename (test_dir, "my-file.toot", NULL);
+	gboolean ret;
+
+	/* Mtime must change so wait between tests */
+	sleep (1);
+	
+	ret = g_file_set_contents (file, DATA, strlen (DATA), NULL);
+	g_assert (ret);
+
+	file_reset_stats ();
+	
+	/* Now make sure that file is not located */
+	gck_file_tracker_refresh (the_tracker, FALSE);
+	
+	g_assert_cmpint (0, ==, n_files_added);
+	g_assert_cmpint (0, ==, n_files_changed);
+	g_assert_cmpint (0, ==, n_files_removed);	
+	
+	g_unlink (file);
+	g_free (file);
+}

Modified: trunk/tests/gtest-helpers.c
==============================================================================
--- trunk/tests/gtest-helpers.c	(original)
+++ trunk/tests/gtest-helpers.c	Mon Dec 22 20:21:06 2008
@@ -52,10 +52,6 @@
 	return g_realloc (p, sz); 
 }
 
-#ifndef EXTERNAL_TEST
-#include "common/gkr-async.h"
-#endif
-
 static GMainLoop *mainloop = NULL;
 
 static gboolean
@@ -133,12 +129,6 @@
 	gtk_init (&argc, &argv);
 	mainloop = g_main_loop_new (NULL, FALSE);
 
-#ifndef EXTERNAL_TEST
-
-	gkr_async_workers_init (mainloop);
-	
-#endif
-
 	fatal_mask = g_log_set_always_fatal (G_LOG_FATAL_MASK);
 	fatal_mask |= G_LOG_LEVEL_WARNING | G_LOG_LEVEL_CRITICAL;
 	g_log_set_always_fatal (fatal_mask);

Modified: trunk/tests/gtest.make
==============================================================================
--- trunk/tests/gtest.make	(original)
+++ trunk/tests/gtest.make	Mon Dec 22 20:21:06 2008
@@ -8,8 +8,9 @@
 
 INCLUDES=				\
 	-I$(top_srcdir) 		\
-	-I$(top_srcdir)/daemon 		\
 	-I$(top_builddir) 		\
+	-I$(srcdir)/..			\
+	-I$(srcdir)/../..		\
 	$(GTK_CFLAGS)			\
 	$(GLIB_CFLAGS)  
 	



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