--- /dev/null
+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;