diff -ruN gnutls26-2.4.1.orig/lib/opencdk/opencdk.h gnutls26-2.4.1/lib/opencdk/opencdk.h
--- gnutls26-2.4.1.orig/lib/opencdk/opencdk.h	2008-06-30 16:45:51.000000000 -0400
+++ gnutls26-2.4.1/lib/opencdk/opencdk.h	2008-08-21 19:23:44.000000000 -0400
@@ -214,7 +214,11 @@
 enum cdk_s2k_type_t {
     CDK_S2K_SIMPLE     = 0,
     CDK_S2K_SALTED     = 1,
-    CDK_S2K_ITERSALTED = 3
+    CDK_S2K_ITERSALTED = 3,
+    CDK_S2K_GNU_EXT = 101 
+ /* GNU S2K extensions: refer to DETAILS from GnuPG: 
+  http://cvs.gnupg.org/cgi-bin/viewcvs.cgi/trunk/doc/DETAILS?root=GnuPG
+ */
 };
 
 
diff -ruN gnutls26-2.4.1.orig/lib/opencdk/read-packet.c gnutls26-2.4.1/lib/opencdk/read-packet.c
--- gnutls26-2.4.1.orig/lib/opencdk/read-packet.c	2008-06-30 16:45:51.000000000 -0400
+++ gnutls26-2.4.1/lib/opencdk/read-packet.c	2008-08-21 19:30:09.000000000 -0400
@@ -78,10 +78,35 @@
 }
 
 
-static int
+/* read about S2K at http://tools.ietf.org/html/rfc4880#section-3.7.1 */
+static cdk_error_t
 read_s2k (cdk_stream_t inp, cdk_s2k_t s2k)
 {
-  return CDK_Not_Implemented;
+  size_t nread;
+
+  s2k->mode = cdk_stream_getc (inp);
+  s2k->hash_algo = cdk_stream_getc (inp);
+  if (s2k->mode == CDK_S2K_SIMPLE) 
+      return 0;
+  else if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
+    {
+      if (stream_read (inp, s2k->salt, DIM (s2k->salt), &nread))
+	return CDK_Inv_Packet;
+      if (nread != DIM (s2k->salt))
+	return CDK_Inv_Packet;
+      
+      if (s2k->mode == CDK_S2K_ITERSALTED)
+	s2k->count = cdk_stream_getc (inp);
+    }
+  else if (s2k->mode == CDK_S2K_GNU_EXT)
+    {
+      /* GNU extensions to the S2K : read DETAILS from gnupg */
+      return 0;
+    }
+  else
+    return CDK_Not_Implemented;
+
+  return 0;
 }
 
 
@@ -194,6 +219,7 @@
 static cdk_error_t
 read_symkey_enc (cdk_stream_t inp, size_t pktlen, cdk_pkt_symkey_enc_t ske)
 {
+  cdk_error_t ret;
   cdk_s2k_t s2k;
   size_t minlen;
   size_t nread, nleft;
@@ -213,7 +239,9 @@
     return CDK_Out_Of_Core;
   
   ske->cipher_algo = cdk_stream_getc (inp);
-  s2k->mode = cdk_stream_getc (inp);
+  ret = read_s2k(inp, s2k);
+  if (ret != 0)
+    return ret;
   switch (s2k->mode)
     {
     case CDK_S2K_SIMPLE    : minlen = 0; break;
@@ -225,18 +253,6 @@
       return CDK_Inv_Packet;
     }
   
-  s2k->hash_algo = cdk_stream_getc (inp);
-  if (s2k->mode == CDK_S2K_SALTED || s2k->mode == CDK_S2K_ITERSALTED)
-    {
-      if (stream_read (inp, s2k->salt, DIM (s2k->salt), &nread))
-	return CDK_Inv_Packet;
-      if (nread != DIM (s2k->salt))
-	return CDK_Inv_Packet;
-      
-      if (s2k->mode == CDK_S2K_ITERSALTED)
-	s2k->count = cdk_stream_getc (inp);
-    }
-  
   ske->seskeylen = pktlen - 4 - minlen;
   /* We check if there is an encrypted session key and if it fits into
      the buffer. The maximal key length is 256-bit. */
@@ -421,14 +437,19 @@
       rc = read_s2k (inp, sk->protect.s2k);
       if (rc) 
 	return rc;
-      sk->protect.ivlen = gcry_cipher_get_algo_blklen (sk->protect.algo);
-      if (!sk->protect.ivlen)
-	return CDK_Inv_Packet;
-      rc = stream_read (inp, sk->protect.iv, sk->protect.ivlen, &nread);
-      if (rc)
-	return rc;
-      if (nread != sk->protect.ivlen)
-	return CDK_Inv_Packet;
+      /* refer to --export-secret-subkeys in gpg(1) */
+      if (sk->protect.s2k->mode == CDK_S2K_GNU_EXT) 
+	sk->protect.ivlen = 0;
+      else {
+	sk->protect.ivlen = gcry_cipher_get_algo_blklen (sk->protect.algo);
+	if (!sk->protect.ivlen)
+	  return CDK_Inv_Packet;
+	rc = stream_read (inp, sk->protect.iv, sk->protect.ivlen, &nread);
+	if (rc)
+	  return rc;
+	if (nread != sk->protect.ivlen)
+	  return CDK_Inv_Packet;
+      }
     }
   else
     sk->protect.algo = sk->s2k_usage;
@@ -476,6 +497,22 @@
 	return CDK_Out_Of_Core;
       if (stream_read (inp, sk->encdata, sk->enclen, &nread))
 	return CDK_Inv_Packet;
+      /* Handle the GNU S2K extensions we know (just gnu-dummy right now): */
+      if (sk->protect.s2k->mode == CDK_S2K_GNU_EXT) {
+	unsigned char gnumode;
+	if ((sk->enclen < strlen("GNU") + 1) ||
+	    (0 != memcmp("GNU", sk->encdata, strlen("GNU"))))
+	  return CDK_Inv_Packet;
+	gnumode = sk->encdata[strlen("GNU")];
+	/* we only handle gnu-dummy (mode 1).
+	   mode 2 should refer to external smart cards.
+	*/
+	if (gnumode != 1)
+	  return CDK_Inv_Packet;
+	/* gnu-dummy should have no more data */
+	if (sk->enclen != strlen("GNU") + 1)
+	  return CDK_Inv_Packet;
+      }
       nskey = cdk_pk_get_nskey (sk->pk->pubkey_algo);
       if (!nskey)
 	return CDK_Inv_Algo;