Probable bug in openpgp
gmail
arbogast.cedric at gmail.com
Sat Mar 26 15:57:18 CET 2011
Hi all,
This is my first contact and mail with gnutls mailing list, to summarize
i'm a coder maintening a personnal home server using several GNU tools
since the late 90's.
I build GNUTLS-2.12.0 in a chroot jail (gcc 4.5.2/libc 2.13/binutils
2.21/make 3.82) with an athlon architecture on ext3 FS and, as root,
and notice tests/openpgp-auth freeze after few error messages :
[root at pompomgalli] mkdir gnutls-2.12.0_build && cd gnutls-2.12.0_build
[root at pompomgalli] ../gnutls-2.12.0/configure && make
...
[root at pompomgalli] make check
...
PASS: mini-x509
PASS: mini-x509-rehandshake
Self test `./rng-fork' finished with 0 errors
successSelf test `./rng-fork' finished with 0 errors
PASS: rng-fork
Self test `./openssl' finished with 0 errors
PASS: openssl
server openpgp keys The request is invalid.
client openpgp keys The request is invalid.
server handshake Could not negotiate a supported cipher suite. (-21)
<[CTRL][C]>
[root at pompomgalli]
I investigate by put on debugging in tests/openpgp-auth and add strace
support relating to openpgp-auth in tests Makefile :
--- gnutls-2.12.0_build/tests/Makefile.orig 2011-03-26
13:23:14.000000000 +0100
+++ gnutls-2.12.0_build/tests/Makefile 2011-03-26 09:52:44.000000000 +0100
@@ -1670,6 +1670,7 @@
if test -f ./$$tst; then dir=./; \
elif test -f $$tst; then dir=; \
else dir="$(srcdir)/"; fi; \
+ if [ "$$tst" = "openpgp-auth" ] ; then tst="strace -o
pgp.txt -ff $$tst" ; fi; \
if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
all=`expr $$all + 1`; \
case " $(XFAIL_TESTS) " in \
--- gnutls-2.12.0/tests/openpgp-auth.c.orig 2011-03-16
22:40:25.000000000 +0100
+++ gnutls-2.12.0/tests/openpgp-auth.c 2011-03-26 12:05:10.000000000 +0100
@@ -60,6 +60,7 @@
const char *srcdir;
char *pub_key_path, *priv_key_path;
pid_t child;
+ debug=1;
gnutls_global_init ();
And relaunch tests suite :
[root at pompomgalli] make check
...
[ 5569| 7] RB: Have 5 bytes into buffer. Adding 112 bytes.
[ 5569| 7] RB: Requested 117 bytes
[ 5569| 4] REC[0x8055e80]: Decrypted Packet[1] Alert(21) with length: 2
[ 5569| 4] REC[0x8055e80]: Alert[1|0] - Close notify - was received
Process 5777 attached
[ 5569| 4] REC[0x8064250]: Allocating epoch #0
[ 5569| 7] new stream `[temp]'
[ 5569| 7] new stream fd=10
[ 5569| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/armor.c:327
[ 5569| 6] armor filter: decode
[ 5569| 7] filter [temp] [read]: type=1 rc=0
[ 5569| 7] replace stream fd=10 with fd=11
[ 5569| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/misc.c:325
[ 5569| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/misc.c:325
[ 5569| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:1002
[ 5569| 7] close stream ref=0 `[temp]'
[ 5569| 7] close stream fd=11
[ 5777| 4] REC[0x8064250]: Allocating epoch #0
[ 5569| 6] free armor filter
[ 5569| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:515
[ 5569| 7] new stream `[temp]'
[ 5569| 7] new stream fd=10
[ 5569| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/armor.c:327
[ 5777| 7] new stream `[temp]'
[ 5777| 7] new stream fd=10
[ 5777| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/armor.c:327
[ 5777| 6] armor filter: decode
[ 5777| 7] filter [temp] [read]: type=1 rc=0
[ 5777| 7] replace stream fd=10 with fd=11
[ 5777| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/misc.c:325
[ 5777| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/misc.c:325
[ 5777| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:1002
[ 5777| 7] close stream ref=0 `[temp]'
[ 5777| 7] close stream fd=11
[ 5777| 6] free armor filter
[ 5777| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:515
[ 5777| 7] new stream `[temp]'
[ 5777| 7] new stream fd=10
[ 5777| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/armor.c:327
[ 5777| 6] armor filter: decode
[ 5777| 7] filter [temp] [read]: type=1 rc=0
[ 5777| 7] replace stream fd=10 with fd=11
[ 5777| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:1002
[ 5777| 7] close stream ref=0 `[temp]'
[ 5777| 7] close stream fd=11
[ 5777| 6] free armor filter
[ 5777| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:515
[ 5777| 2] ASSERT: ../../gnutls-2.12.0/lib/gnutls_str.c:496
[ 5777| 2] Error converting hex string: f30fd423c143e7ba.
[ 5777| 2] ASSERT:
../../../gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c:414
[ 5777| 2] ASSERT:
../../../gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c:425
[ 5777| 2] ASSERT:
../../../gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c:509
client openpgp keys The request is invalid.
[ 5777| 2] ASSERT: ../../gnutls-2.12.0/lib/gnutls_constate.c:695
...
<[CTRL][C]>
[root at pompomgalli]
I notice then something is probably wrong with the key id : "[ 5777|
2] Error converting hex string: f30fd423c143e7ba." triggered by the
gnutls_str.c assert at line 496 which then trigger the three following
asserts.
I have then checked the gnutls_openpgp.c method at the origin of the
line 414 assert :
@321 "gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c"
static int
get_keyid (gnutls_openpgp_keyid_t keyid, const char *str)
{
size_t keyid_size = sizeof (keyid);
if (strlen (str) != 16)
{
_gnutls_debug_log
("The OpenPGP subkey ID has to be 16 hexadecimal
characters.\n");
return GNUTLS_E_INVALID_REQUEST;
}
if (_gnutls_hex2bin (str, strlen (str), keyid, &keyid_size) < 0)
{
_gnutls_debug_log ("Error converting hex string: %s.\n",
str);
return GNUTLS_E_INVALID_REQUEST;
}
return 0;
}
And the _gnutls_hex2bin method that triggers the converting error message :
@476 "gnutls-2.12.0/lib/gnutls_str.c"
int
_gnutls_hex2bin (const opaque * hex_data, int hex_size,
opaque * bin_data,
size_t * bin_size)
{
int i, j;
opaque hex2_data[3];
unsigned long val;
hex2_data[2] = 0;
for (i = j = 0; i < hex_size;)
{
if (!isxdigit (hex_data[i])) /* skip non-hex such
as the ':' in 00:FF */
{
i++;
continue;
}
if (j > *bin_size)
{
gnutls_assert ();
return GNUTLS_E_SHORT_MEMORY_BUFFER;
}
hex2_data[0] = hex_data[i];
hex2_data[1] = hex_data[i + 1];
i += 2;
val = strtoul ((char *) hex2_data, NULL, 16);
if (val == ULONG_MAX)
{
gnutls_assert ();
return GNUTLS_E_PARSING_ERROR;
}
bin_data[j] = val;
j++;
}
*bin_size = j;
return 0;
}
The line 496 assert (if (j > *bin_size) { gnutls_assert (); return
GNUTLS_E_SHORT_MEMORY_BUFFER; }) is normaly triggered by an unexpected
numbers of digits in keyid requiring too many bytes in the target binary
buffer.
I guess then there is something wrrong with the keyid str string or the
keyid_size. The keyid str in the log above seems correct, with 16 digits
forming a correct hexadecimal string.
I decide to check the keyid_size :
--- gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c.orig 2011-03-16
20:53:46.000000000 +0100
+++ gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c 2011-03-26
13:18:35.000000000 +0100
@@ -332,7 +332,7 @@
if (_gnutls_hex2bin (str, strlen (str), keyid, &keyid_size) < 0)
{
- _gnutls_debug_log ("Error converting hex string: %s.\n", str);
+ _gnutls_debug_log ("Error converting hex string: %s.[%d]\n",
str,keyid_size);
return GNUTLS_E_INVALID_REQUEST;
}
And relaunch tests suite :
[root at pompomgalli] make check
...
[13182| 7] RB: Requested 181 bytes
[13182| 4] REC[0x8055e80]: Decrypted Packet[2] Alert(21) with length: 2
[13182| 4] REC[0x8055e80]: Alert[1|0] - Close notify - was received
Process 13182 suspended
[13184| 6] armor filter: decode
[13184| 7] filter [temp] [read]: type=1 rc=0
[13184| 7] replace stream fd=10 with fd=11
[13184| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/misc.c:325
[13184| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/misc.c:325
[13184| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:1002
[13184| 7] close stream ref=0 `[temp]'
[13184| 7] close stream fd=11
[13184| 6] free armor filter
[13184| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:515
[13184| 7] new stream `[temp]'
[13184| 7] new stream fd=10
[13184| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/armor.c:327
[13184| 6] armor filter: decode
[13184| 7] filter [temp] [read]: type=1 rc=0
[13184| 7] replace stream fd=10 with fd=11
[13184| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:1002
[13184| 7] close stream ref=0 `[temp]'
[13184| 7] close stream fd=11
[13184| 6] free armor filter
[13184| 2] ASSERT: ../../../gnutls-2.12.0/lib/opencdk/stream.c:515
[13184| 2] ASSERT: ../../gnutls-2.12.0/lib/gnutls_str.c:496
[13184| 2] Error converting hex string: f30fd423c143e7ba.[4]
[13184| 2] ASSERT:
../../../gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c:414
[13184| 2] ASSERT:
../../../gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c:425
[13184| 2] ASSERT:
../../../gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c:509
client openpgp keys The request is invalid.
[13184| 2] ASSERT: ../../gnutls-2.12.0/lib/gnutls_constate.c:695
[13184| 4] REC[0x8064250]: Allocating epoch #1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_DSS_AES_128_CBC_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_DSS_CAMELLIA_128_CBC_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_DSS_AES_256_CBC_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_DSS_CAMELLIA_256_CBC_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_DSS_3DES_EDE_CBC_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite: DHE_DSS_ARCFOUR_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_RSA_AES_128_CBC_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_RSA_CAMELLIA_128_CBC_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_RSA_AES_256_CBC_SHA1
[13184| 3] HSK[0x8064250]: Keeping ciphersuite:
DHE_RSA_CAMELLIA_256_CBC_SHA1
<[CTRL][C]>
[root at pompomgalli]
The ligne "[13184| 2] Error converting hex string:
f30fd423c143e7ba.[4]" is self explaining, hard to store 16 digits
hexadecimal string in 4 bytes.
The gnutls_openpgp_keyid_t type is now my main suspect and i then check
his definition and stuff relating to it :
@56 "gnutls-2.12.0/lib/includes/gnutls/openpgp.h"
typedef unsigned char gnutls_openpgp_keyid_t[8];
@2874 "gnutls-2.12.0/NEWS"
gnutls_openpgp_keyid_t: ADDED, instead of hard-coded 'unsigned
char[8]'.
(in Version 2.3.1, released 2008-02-21 )
Bingo !
sizeof(unsigned char[8]) return 8
but
sizeof(*) return ...
4 on a 32 bits architecture
8 on a 64 bits architecture
The issue appears at the third pass of the openpgp-auth which provides
directly a keyid, which drives openpgp to parse the keyid.
On a 64 bits architecture, the pointer size matchs the keyid buffer size
and then get_keyid works without any troubles.
On a 32 bits architecture, it fails as show the openpgp-auth test.
The problem is that keyid_size in the get_keyid method has to get the
keyid BUFFER size and not the keyid POINTER size.
A way to correct that could be to alter openpgp.h to have sizeof(keyid)
returning BUFFER size without broke ABI compatibility :
typedef struct { unsigned char __gnutls_openpgp_keyid_t[8]; }
gnutls_openpgp_keyid_t;
But everything in gnutls deal with gnutls_openpgp_keyid_t as a pointer,
so it's seems better to directly alter "size_t keyid_size = sizeof
(keyid); " in
gnutls_openpgp.c to "size_t keyid_size = sizeof (unsigned char[8]);" and
doing it properly with a constant.
Here is three suggested patchs for this bug :
Patch 1 :
--- gnutls-2.12.0/lib/includes/gnutls/gnutls.h.in.orig 2011-03-23
19:53:44.000000000 +0100
+++ gnutls-2.12.0/lib/includes/gnutls/gnutls.h.in 2011-03-26
14:11:46.000000000 +0100
@@ -1571,6 +1571,11 @@
#define GNUTLS_KEY_CRL_SIGN 2
#define GNUTLS_KEY_ENCIPHER_ONLY 1
#define GNUTLS_KEY_DECIPHER_ONLY 32768
+
+ /* specifics contants relating to keys and subkeys :
+ */
+#define GNUTLS_KEY_ID_SIZE_IN_BYTES 8
+
void
gnutls_certificate_set_params_function
(gnutls_certificate_credentials_t
Patch 2 :
--- gnutls-2.12.0/lib/includes/gnutls/openpgp.h.orig 2011-02-28
17:12:24.000000000 +0100
+++ gnutls-2.12.0/lib/includes/gnutls/openpgp.h 2011-03-26
14:13:53.000000000 +0100
@@ -53,7 +53,7 @@
GNUTLS_OPENPGP_FMT_BASE64
} gnutls_openpgp_crt_fmt_t;
- typedef unsigned char gnutls_openpgp_keyid_t[8];
+ typedef unsigned char
gnutls_openpgp_keyid_t[GNUTLS_KEY_ID_SIZE_IN_BYTES];
/* gnutls_openpgp_cert_t should be defined in gnutls.h
*/
Patch 3 :
--- gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c.orig 2011-03-16
20:53:46.000000000 +0100
+++ gnutls-2.12.0/lib/openpgp/gnutls_openpgp.c 2011-03-26
14:16:04.000000000 +0100
@@ -321,7 +321,11 @@
static int
get_keyid (gnutls_openpgp_keyid_t keyid, const char *str)
{
- size_t keyid_size = sizeof (keyid);
+ /* keyid_size should get keyid buffer size,
+ * since 2008-02-21 keyid has become a pointer so
+ * sizeof(keyid) become wrong and
+ * keyid_size must be explicity given */
+ size_t keyid_size = sizeof (unsigned char[GNUTLS_KEY_ID_SIZE_IN_BYTES]);
if (strlen (str) != 16)
{
@@ -329,7 +333,6 @@
("The OpenPGP subkey ID has to be 16 hexadecimal characters.\n");
return GNUTLS_E_INVALID_REQUEST;
}
-
if (_gnutls_hex2bin (str, strlen (str), keyid, &keyid_size) < 0)
{
_gnutls_debug_log ("Error converting hex string: %s.\n", str);
I have applied this three patchs on my build and the openpgp-auth is
now succesfull :
[root at pompomgalli] make check
...
PASS: mini-x509
PASS: mini-x509-rehandshake
Self test `./rng-fork' finished with 0 errors
successSelf test `./rng-fork' finished with 0 errors
PASS: rng-fork
Self test `./openssl' finished with 0 errors
PASS: openssl
Self test `./openpgp-auth' finished with 0 errors
Self test `./openpgp-auth' finished with 0 errors
Self test `./openpgp-auth' finished with 0 errors
Self test `./openpgp-auth' finished with 0 errors
Self test `./openpgp-auth' finished with 0 errors
Self test `./openpgp-auth' finished with 0 errors
Self test `./openpgp-auth' finished with 0 errors
Self test `./openpgp-auth' finished with 0 errors
PASS: openpgp-auth
Self test `./openpgp-keyring' finished with 0 errors
PASS: openpgp-keyring
PASS: pgps2kgnu
Self test `./x509self' finished with 0 errors
Self test `./x509self' finished with 0 errors
...
Hope this will help, i'm available for tests/infos if needed.
Regards, Cedric.
More information about the Gnutls-devel
mailing list