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;