Re: [exim-dev] [exim] 4.80 RC2 TLS interop between GnuTLS an…

Top Page
Delete this message
Reply to this message
Author: Janne Snabb
Date:  
To: exim-dev
Subject: Re: [exim-dev] [exim] 4.80 RC2 TLS interop between GnuTLS and NSS
On 2012-05-20 17:35, Phil Pennock wrote:
> I don't see a better error code for peer EOF, but calling EOF a record
> overflow is still a little confusing to dumbasses like me.


I agree, EOF handling in GnuTLS does not look very convincing.

> Okay, is clearly NSS disliking the server_hello_done.


I think the failing code in NSS is in
mozilla/security/nss/lib/ssl/derive.c, the following bit:

            /* perform client side ops */
            /* generate a pair of ephemeral keys using server's parms */
            cpriv = SECKEY_CreateECPrivateKey(pecParams, &cpub, NULL);
            if (!cpriv || !cpub) {
                if (testecdhe) {
                    SECKEY_DestroyPrivateKey(keapriv);
                    SECKEY_DestroyPublicKey(keapub);
                }
                PORT_SetError(SEC_ERROR_KEYGEN_FAIL);
                rv = SECFailure;
                break;
            }



Furthermore, if I alter Exim's tls-gnu.c as follows I do not have a
problem any more:

-static const char * const exim_default_gnutls_priority = "NORMAL";
+static const char * const exim_default_gnutls_priority = "NORMAL:-DHE-RSA";

(Setting "tls_require_ciphers = NORMAL:-DHE-RSA" in the runtime
configuration does not seem to help. Another bug?)

Another magic workaround is to force the DH key size in tls-gnu.c:

@@ -392,10 +392,11 @@
 dh_bits = EXIM_SERVER_DH_BITS_PRE2_12;
 DEBUG(D_tls)
   debug_printf("GnuTLS lacks gnutls_sec_param_to_pk_bits(), using %d
bits.\n",
       dh_bits);
 #endif
+dh_bits = 2048; /* DEBUG: force DH key size */


 if (!string_format(filename, sizeof(filename),
       "%s/gnutls-params-%d", spool_directory, dh_bits))
   return tls_error(US"overlong filename", NULL, NULL);



So it looks like this is something related to DH ephemeral key
generation on the client/NSS side. They key is generated based on the
parameters supplied by the GnuTLS server. When the TLS handshake is
failing, I see the following key size:

17757 GnuTLS tells us that for D-H PK, NORMAL is 2432 bits.

Maybe NSS is unable to create/use bigger keys than 2048 bits? Running
the following command in NSS source tree finds suspiciously many ugly
matches:
find . -type f | xargs fgrep 2048

Some of them have comments like "XXX different size?"... looks like
someone should run "s/2048/8192/g" over the NSS source code and the
problem would be sorted for a few years :).

When using older GnuTLS versions the DH key size is less than 2432, thus
the failure does not occur.

When using newer GnuTLS (3.0.19-2 on Debian "sid") the negotiated cipher
is different:

17757 cipher: TLS1.0:ECDHE_RSA_AES_256_CBC_SHA1:256

... whereas the problematic GnuTLS versions negotiate the following
cipher by default:

29636 cipher: TLS1.0:DHE_RSA_CAMELLIA_256_CBC_SHA1:256

Do we need to clamp the DH key size at 2048 to workaround NSS bugs? Or
can we detect somehow that the client is buggy NSS library and clamp
only in that case?


PS. I also did a quick interop using PolarSSL based client. No problems
there.

--
Janne Snabb / EPIPE Communications
snabb@??? - http://epipe.com/